6

Desperately need a Javascript equivalent to polyval and polyfit functions that exist in Matlab. Essentially those functions in matlab do a curve fit based on two equally sized arrays depending on a specified polynomial. I need to do some calculations that involve curve fitting in javascript and can't for the life of me find an equivalent function.

This is MatLab's explanation of the function polyfit

"P = POLYFIT(X,Y,N) finds the coefficients of a polynomial P(X) of degree N that fits the data Y best in a least-squares sense. P is a row vector of length N+1 containing the polynomial coefficients in descending powers, P(1)*X^N + P(2)*X^(N-1) +...+ P(N)*X + P(N+1)."

This is MatLab's explanation of polyval.

"POLYVAL Evaluate polynomial. Y = POLYVAL(P,X) returns the value of a polynomial P evaluated at X. P is a vector of length N+1 whose elements are the coefficients of the polynomial in descending powers.

    Y = P(1)*X^N + P(2)*X^(N-1) + ... + P(N)*X + P(N+1)"

Any help would be super.

Regards,

Wayne
  • 59,728
  • 15
  • 131
  • 126
Spets
  • 2,391
  • 4
  • 24
  • 26

4 Answers4

3

numericjs may help you get started.

Mariusz Jamro
  • 30,615
  • 24
  • 120
  • 162
biogeek
  • 561
  • 1
  • 4
  • 13
  • The numeric.js site is down but you can still get the code on GitHub: https://github.com/sloisel/numeric/blob/master/src/numeric.js – Jacob Philpott Apr 01 '21 at 19:38
2

POLYFIT performs a least-square polynomial fitting which comes down to solving a system of linear equations. I did a quick search, but I couldn't find a basic linear algebra Javascript library that solves such systems... The easiest method would be to implement the Gaussian elimination algorithm yourself.

POLYVAL is simply evaluating the polynomial at the points X by substituting the coefficients in the equation.

Community
  • 1
  • 1
Amro
  • 123,847
  • 25
  • 243
  • 454
  • Ya I was thinking of rewriting Polyfit on my own, but was hoping there was a library or something in Javascript. – Spets Jul 28 '11 at 04:39
  • It comes down to solving a system of linear equations, but if you have many points, you're much better off using a Singular Value Decomposition. There is some code there: view-source:http://users.telenet.be/paul.larmuseau/SVD.htm – Alexandre C. Feb 26 '12 at 14:45
  • 3
    I wrote something for this, since it didn't exist! https://github.com/prismofeverything/cyclops . It will also generate a function for you from the resulting coefficients that calculates the polynomial for a given index value. – prismofeverything Feb 13 '13 at 08:27
  • @prismoeverything: +1 thank you for sharing your code (you should post an answer preferably with some explanation). I see you are using the excellent numeric.js library to compute the SVD (by now it is THE best javascript library for any numerical computation) – Amro Feb 13 '13 at 10:28
1

perhaps this code might help someone

function _prepare(_mat) {
_mat=[[]].concat(_mat)
for(i=0;i<_mat.length;++i)
    _mat[i]=[0].concat(_mat[i])
return _mat
}

function linear(_mat){
_mat=_prepare(_mat)
return _solve(_mat)
}


function _solve(_mat){
var c=new Array(),d=new Array()
var n=_mat.length-1

for(i=0;i<=n+1;i++) {
    d[i]=new Array();
    c[i]=0
    for(j=0;j<=n+1;++j)
        d[i][j]=0
}

// mission impossible
// calculate all the determinants of the system
for(m=2; m<=n ; ++m) {
    for(i=m;i<=n;++i)
        for(j = m-1;j<=n+1;++j)
            d[i][j] = [_mat[i][j] * _mat[m-1][m-1] , _mat[i][m-1]]
        for(i=m;i<=n;++i)
            for(j=m-1;j<=n+1;++j) {
                _mat[i][j] = d[i][j][0]-d[i][j][1]*_mat[m-1][j] 
                if(Math.abs(_mat[i][j])<1e-25) _mat[i][j]=0  // i have to add this line
            }
}
// now the coefficients of equation (not exactly)

for(i=n;i>=1;--i) {
    c[i-1] = _mat[i][n+1]
    if (i!=n)
    for(j=n; j>=i+1;--j)
        c[i-1] = c[i-1] -_mat[i][j] * c[j-1]
    if(_mat[i][i]!=0)
        c[i-1]=c[i-1] / _mat[i][i]
    else
        c[i-1]=0
    if(Math.abs(c[i-1])<1e-25)
        c[i-1]=0
}
c.length=n
return c
}

function fitpoly(e,b){
var a=new Array()
var n = 1+b,e=[[0,0]].concat(e),ns=e.length-1
for(i=0;i<=n+1;i++) {
    a[i]=new Array();
    for(j=0;j<=n+1;++j)
        a[i][j]=0
}
for(m=1;m <= n;m++)
    for(i=1;i<= m;i++) {
        j = m - i + 1; 
        for(ii=1;ii <= ns;ii++)
            a[i][j] = a[i][j] + Math.pow(e[ii][0], m-1)
    }  
for(i=1;i<= n;++i)
    for(ii=1;ii<=ns;++ii)
        a[i][n+1] = a[i][n+1] +e[ii][1]*Math.pow(e[ii][0],i-1) 
for(m = n+2 ; m <= 2*n ; ++m)
    for(i = m-n; i<= n;++i) {
        j= m -i 
        for(ii=1; ii<=ns;++ii)
            a[i][j] = a[i][j] + Math.pow(e[ii][0],m-2) // coefficients of system
    }
a.length=a.length-1  
return _solve(a)
}


//and then
poly_degree = 6
points= [[2,2],[2,4],[4,6],[6,4],[8,2]]
// coefficients of polynome 
console.log(fitpoly(points, poly_degree))

// or solve a linear system. Here with six variables
solution = linear([[1,2,3,-2,-3,-26,52],[3,2,5,-2,4,30,-60],[6,1,-4,-1,5,94,-188],[-1,2,4,3,4,30,-60],[-1,4,2,-1,2,26,-52],[3,-3,11,-7,-2,-1,-95]])
console.log(solution)
P.Tsiros
  • 11
  • 2
  • 1
    THanks dude but I'm already done with the development of this and haven't touched it in ages. I ended up employing Sylvesters Library for matrix computation/manipulation and then hand rolled my own solution. I could post it here if anyone is interested. – Spets Jan 19 '16 at 17:52
  • @Spets - thanks!, I'm interested (if this is not too much trouble from your end..) – Li3ro Nov 22 '17 at 03:29
0

Give this gist a try, it uses numeric.js:

function polyfit(xArray, yArray, order) {

  if (xArray.length <= order) console.warn("Warning: Polyfit may be poorly conditioned.")

  let xMatrix = []
  let yMatrix = numeric.transpose([yArray])

  for (let i = 0; i < xArray.length; i++) {

    let temp = []

    for (let j = 0; j <= order; j++) {

      temp.push(Math.pow(xArray[i], j))

    }

    xMatrix.push(temp)

  }

  let xMatrixT = numeric.transpose(xMatrix)

  let dot1 = numeric.dot(xMatrixT, xMatrix)
  let dot2 = numeric.dot(xMatrixT, yMatrix)

  let dotInv = numeric.inv(dot1)

  let coefficients = numeric.dot(dotInv, dot2)

  return coefficients

}
Jacob Philpott
  • 538
  • 1
  • 8
  • 24