How do I create a best-fit polynomial curve in Javascript?
Asked Answered
S

3

7

I'm trying to calculate a best-fit curve for data using a 3-6 order polynomial. I found this tutorial: Cubic Regression (best fit line) in JavaScript

First, I can't seem to get my outputs to remotely match the curve. jsbin here: http://jsbin.com/qukuqigobu/1/edit?html,js,console,output

var data_x = [500,1000,1500,2000,2500,3000,3500,4000,4500,5000,5500,6000,6500,7000];
var data_y = [50,80,100,160,210,265,340,390,440,470,500,500,495,460];

var cubic = function(params,x) {
  return params[0] * x*x*x +
    params[1] * x*x +
    params[2] * x +
    params[3];
};

var objective = function(params) {
  var total = 0.0;
  for(var i=0; i < data_x.length; ++i) {
    var resultThisDatum = cubic(params, data_x[i]);
    var delta = resultThisDatum - data_y[i];
    total += (delta*delta);
  }
  return total;
};

var initial = [1,1,1,1];
var minimiser = numeric.uncmin(objective,initial);

console.log("initial:");
for(var j=0; j<initial.length; ++j) {
  console.log(initial[j]);  
}

console.log("minimiser:");
for(var j=0; j<minimiser.solution.length; ++j) {
  console.log(minimiser.solution[j]);
}

My output coefficients are:

1
-17358.001260500238
80977844.06724495
-96625621220.328

However, using LINEST in excel, they are:

-4.68257E-09
4.26789E-05
-0.01
45.39760539

I calculated Y values from the Xs in Excel using this to confirm a good correlation. The minimizer results do not work.

This is the first step, but ideally I'd want to be able to do the same thing for 4th, 5th and 6th order polynomials as well.

Any help would be much appreciated. Thanks.

Savoyard answered 1/2, 2015 at 23:6 Comment(0)
S
8

Figured it out using Matrix Algebra:

var x = [500,1000,1500,2000,2500,3000,3500,4000,4500,5000,5500,6000,6500,7000];
var y = [50,80,100,160,210,265,340,390,440,470,500,500,495,460];

order = 3;

var xMatrix = [];
var xTemp = [];
var yMatrix = numeric.transpose([y]);

for (j=0;j<x.length;j++)
{
    xTemp = [];
    for(i=0;i<=order;i++)
    {
        xTemp.push(1*Math.pow(x[j],i));
    }
    xMatrix.push(xTemp);
}

var xMatrixT = numeric.transpose(xMatrix);
var dot1 = numeric.dot(xMatrixT,xMatrix);
var dotInv = numeric.inv(dot1);
var dot2 = numeric.dot(xMatrixT,yMatrix);
var solution = numeric.dot(dotInv,dot2);
console.log("Coefficients a + bx^1 + cx^2...")
console.log(solution);

jsbin: http://jsbin.com/yoqiqanofo/1/

Savoyard answered 3/2, 2015 at 14:16 Comment(6)
Hey but what to do after getting those numbers? How can I plugged them into the formula to perform prediction?Ecphonesis
@hyperfkcb I know I am a few months late but it would probably give you a better understanding if you read: en.wikipedia.org/wiki/Polynomial_regression his code is an implementation of just one method of calculating a "best bit" for an nth order polynomial.Austerity
@hyperfkcb Which library did you use? "numeric is not defined"...Dogface
@theshadow Do you know which library it is?Dogface
@Dogface if you look at the jsbin they linked, they are importing numericjs.com/lib/numeric-1.2.6.min.js in the htmlAusterity
The numericjs.com website is down but you can still get the code on GitHub: github.com/sloisel/numericHaploid
O
1

You might be intersted in MLjs's Polynomial Regression library.

Sample usage copied from its documentation:

import PolynomialRegression from 'ml-regression-polynomial';

const x = [50, 50, 50, 70, 70, 70, 80, 80, 80, 90, 90, 90, 100, 100, 100];
const y = [3.3, 2.8, 2.9, 2.3, 2.6, 2.1, 2.5, 2.9, 2.4, 3.0, 3.1, 2.8, 3.3, 3.5, 3.0];
const degree = 5; // setup the maximum degree of the polynomial

const regression = new PolynomialRegression(x, y, degree);
console.log(regression.predict(80)); // Apply the model to some x value. Prints 2.6.
console.log(regression.coefficients); // Prints the coefficients in increasing order of power (from 0 to degree).
console.log(regression.toString(3)); // Prints a human-readable version of the function.
console.log(regression.toLaTeX());
console.log(regression.score(x, y));
Otolaryngology answered 28/7, 2022 at 12:52 Comment(0)
L
0

Alglib.js can be used for cubic spline fitting. You can use it on any other functional form for that matter.

https://jsfiddle.net/webalizer12/46tcf8w9/26/

var f = function(a_n, x){
    return a_n[3]*Math.pow(x, 3)+a_n[2]*Math.pow(x, 2)+a_n[1]*Math.pow(x, 1)+a_n[0];
}

var data = [[500,50],
[1000,80],
[1500,100],
[2000,160],
[2500,210],
[3000,265],
[3500,340],
[4000,390],
[4500,440],
[5000,470],
[5500,500],
[6000,500],
[6500,495],
[7000,460]];

var fn1 = function(a){
    let sum = 0
    for (let i = 0; i < data.length; ++i) {
        sum = sum + Math.pow(data[i][1] - f(a, data[i][0]), 2)
    }
    let sse = Math.sqrt(sum)
    return sse
}

let solver = new Alglib()
solver.add_function(fn1) //Add the first equation to the solver.

solver.promise.then(function(result) { 
    let x_guess = [0,0,0,0] //Guess the initial values of the solution.
let x_scale = [10,1e-1, 1e-4, 1e-8] //Set the scale of the values in the function only positive values here.
let max_iterations=50000
let penalty=50.0
let radius=0.1
let diffstep=0.000001
let stop_threshold=0.000001
solver.solve("min", x_guess, x_scale, max_iterations, penalty, radius, diffstep, stop_threshold) //Solve the equation

let a=solver.get_results()
console.log(solver.get_results())})
Laurenalaurence answered 4/10, 2022 at 3:29 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.