ml-regression-polynomial
Advanced tools
Comparing version 1.0.3 to 2.0.0
@@ -0,1 +1,15 @@ | ||
# [2.0.0](https://github.com/mljs/regression-polynomial/compare/v1.0.3...v2.0.0) (2019-06-29) | ||
### chore | ||
* update dependencies and remove support for Node.js 6 ([7b44099](https://github.com/mljs/regression-polynomial/commit/7b44099)) | ||
### BREAKING CHANGES | ||
* Node.js 6 is no longer supported. | ||
<a name="1.0.3"></a> | ||
@@ -2,0 +16,0 @@ ## [1.0.3](https://github.com/mljs/regression-polynomial/compare/v1.0.2...v1.0.3) (2017-07-21) |
202
lib/index.js
@@ -7,125 +7,131 @@ 'use strict'; | ||
var BaseRegression__default = _interopDefault(BaseRegression); | ||
var Matrix = require('ml-matrix'); | ||
var Matrix__default = _interopDefault(Matrix); | ||
var mlMatrix = require('ml-matrix'); | ||
class PolynomialRegression extends BaseRegression__default { | ||
constructor(x, y, degree) { | ||
super(); | ||
if (x === true) { | ||
this.degree = y.degree; | ||
this.powers = y.powers; | ||
this.coefficients = y.coefficients; | ||
} else { | ||
BaseRegression.checkArrayLength(x, y); | ||
regress(this, x, y, degree); | ||
} | ||
constructor(x, y, degree) { | ||
super(); | ||
if (x === true) { | ||
this.degree = y.degree; | ||
this.powers = y.powers; | ||
this.coefficients = y.coefficients; | ||
} else { | ||
BaseRegression.checkArrayLength(x, y); | ||
regress(this, x, y, degree); | ||
} | ||
} | ||
_predict(x) { | ||
let y = 0; | ||
for (let k = 0; k < this.powers.length; k++) { | ||
y += this.coefficients[k] * Math.pow(x, this.powers[k]); | ||
} | ||
return y; | ||
_predict(x) { | ||
let y = 0; | ||
for (let k = 0; k < this.powers.length; k++) { | ||
y += this.coefficients[k] * Math.pow(x, this.powers[k]); | ||
} | ||
return y; | ||
} | ||
toJSON() { | ||
return { | ||
name: 'polynomialRegression', | ||
degree: this.degree, | ||
powers: this.powers, | ||
coefficients: this.coefficients | ||
}; | ||
} | ||
toJSON() { | ||
return { | ||
name: 'polynomialRegression', | ||
degree: this.degree, | ||
powers: this.powers, | ||
coefficients: this.coefficients | ||
}; | ||
} | ||
toString(precision) { | ||
return this._toFormula(precision, false); | ||
} | ||
toString(precision) { | ||
return this._toFormula(precision, false); | ||
} | ||
toLaTeX(precision) { | ||
return this._toFormula(precision, true); | ||
toLaTeX(precision) { | ||
return this._toFormula(precision, true); | ||
} | ||
_toFormula(precision, isLaTeX) { | ||
let sup = '^'; | ||
let closeSup = ''; | ||
let times = ' * '; | ||
if (isLaTeX) { | ||
sup = '^{'; | ||
closeSup = '}'; | ||
times = ''; | ||
} | ||
_toFormula(precision, isLaTeX) { | ||
let sup = '^'; | ||
let closeSup = ''; | ||
let times = ' * '; | ||
if (isLaTeX) { | ||
sup = '^{'; | ||
closeSup = '}'; | ||
times = ''; | ||
let fn = ''; | ||
let str = ''; | ||
for (let k = 0; k < this.coefficients.length; k++) { | ||
str = ''; | ||
if (this.coefficients[k] !== 0) { | ||
if (this.powers[k] === 0) { | ||
str = BaseRegression.maybeToPrecision(this.coefficients[k], precision); | ||
} else { | ||
if (this.powers[k] === 1) { | ||
str = | ||
`${BaseRegression.maybeToPrecision(this.coefficients[k], precision) + times}x`; | ||
} else { | ||
str = | ||
`${BaseRegression.maybeToPrecision(this.coefficients[k], precision) + | ||
times | ||
}x${ | ||
sup | ||
}${this.powers[k] | ||
}${closeSup}`; | ||
} | ||
} | ||
let fn = ''; | ||
let str = ''; | ||
for (let k = 0; k < this.coefficients.length; k++) { | ||
str = ''; | ||
if (this.coefficients[k] !== 0) { | ||
if (this.powers[k] === 0) { | ||
str = BaseRegression.maybeToPrecision(this.coefficients[k], precision); | ||
} else { | ||
if (this.powers[k] === 1) { | ||
str = BaseRegression.maybeToPrecision(this.coefficients[k], precision) + times + 'x'; | ||
} else { | ||
str = BaseRegression.maybeToPrecision(this.coefficients[k], precision) + times + 'x' + sup + this.powers[k] + closeSup; | ||
} | ||
} | ||
if (this.coefficients[k] > 0 && k !== (this.coefficients.length - 1)) { | ||
str = ' + ' + str; | ||
} else if (k !== (this.coefficients.length - 1)) { | ||
str = ' ' + str; | ||
} | ||
} | ||
fn = str + fn; | ||
if (this.coefficients[k] > 0 && k !== this.coefficients.length - 1) { | ||
str = ` + ${str}`; | ||
} else if (k !== this.coefficients.length - 1) { | ||
str = ` ${str}`; | ||
} | ||
if (fn.charAt(0) === '+') { | ||
fn = fn.slice(1); | ||
} | ||
return 'f(x) = ' + fn; | ||
} | ||
fn = str + fn; | ||
} | ||
if (fn.charAt(0) === '+') { | ||
fn = fn.slice(1); | ||
} | ||
static load(json) { | ||
if (json.name !== 'polynomialRegression') { | ||
throw new TypeError('not a polynomial regression model'); | ||
} | ||
return new PolynomialRegression(true, json); | ||
return `f(x) = ${fn}`; | ||
} | ||
static load(json) { | ||
if (json.name !== 'polynomialRegression') { | ||
throw new TypeError('not a polynomial regression model'); | ||
} | ||
return new PolynomialRegression(true, json); | ||
} | ||
} | ||
function regress(pr, x, y, degree) { | ||
const n = x.length; | ||
let powers; | ||
if (Array.isArray(degree)) { | ||
powers = degree; | ||
degree = powers.length; | ||
} else { | ||
degree++; | ||
powers = new Array(degree); | ||
for (let k = 0; k < degree; k++) { | ||
powers[k] = k; | ||
} | ||
} | ||
const F = new Matrix__default(n, degree); | ||
const Y = new Matrix__default([y]); | ||
const n = x.length; | ||
let powers; | ||
if (Array.isArray(degree)) { | ||
powers = degree; | ||
degree = powers.length; | ||
} else { | ||
degree++; | ||
powers = new Array(degree); | ||
for (let k = 0; k < degree; k++) { | ||
for (let i = 0; i < n; i++) { | ||
if (powers[k] === 0) { | ||
F[i][k] = 1; | ||
} else { | ||
F[i][k] = Math.pow(x[i], powers[k]); | ||
} | ||
} | ||
powers[k] = k; | ||
} | ||
} | ||
const F = new mlMatrix.Matrix(n, degree); | ||
const Y = new mlMatrix.Matrix([y]); | ||
for (let k = 0; k < degree; k++) { | ||
for (let i = 0; i < n; i++) { | ||
if (powers[k] === 0) { | ||
F.set(i, k, 1); | ||
} else { | ||
F.set(i, k, Math.pow(x[i], powers[k])); | ||
} | ||
} | ||
} | ||
const FT = F.transposeView(); | ||
const A = FT.mmul(F); | ||
const B = FT.mmul(Y.transposeView()); | ||
const FT = new mlMatrix.MatrixTransposeView(F); | ||
const A = FT.mmul(F); | ||
const B = FT.mmul(new mlMatrix.MatrixTransposeView(Y)); | ||
pr.degree = degree - 1; | ||
pr.powers = powers; | ||
pr.coefficients = Matrix.solve(A, B).to1DArray(); | ||
pr.degree = degree - 1; | ||
pr.powers = powers; | ||
pr.coefficients = mlMatrix.solve(A, B).to1DArray(); | ||
} | ||
module.exports = PolynomialRegression; |
{ | ||
"name": "ml-regression-polynomial", | ||
"version": "1.0.3", | ||
"version": "2.0.0", | ||
"description": "Polynomial Regression", | ||
@@ -12,7 +12,9 @@ "main": "lib/index.js", | ||
"scripts": { | ||
"compile": "rollup -c", | ||
"eslint": "eslint src", | ||
"eslint-fix": "npm run eslint -- --fix", | ||
"prepublish": "rollup -c", | ||
"test": "run-s testonly eslint", | ||
"testonly": "jest" | ||
"prepublishOnly": "npm run compile", | ||
"test": "npm run test-coverage && npm run eslint", | ||
"test-only": "jest", | ||
"test-coverage": "jest --coverage" | ||
}, | ||
@@ -34,14 +36,14 @@ "repository": { | ||
"devDependencies": { | ||
"babel-plugin-transform-es2015-modules-commonjs": "^6.24.1", | ||
"eslint": "^4.2.0", | ||
"eslint-config-cheminfo": "^1.7.0", | ||
"eslint-plugin-no-only-tests": "^2.0.0", | ||
"jest": "^20.0.4", | ||
"npm-run-all": "^4.0.2", | ||
"rollup": "^0.45.2" | ||
"@babel/plugin-transform-modules-commonjs": "^7.4.4", | ||
"eslint": "^5.16.0", | ||
"eslint-config-cheminfo": "^1.20.1", | ||
"eslint-plugin-import": "^2.17.2", | ||
"eslint-plugin-jest": "^22.5.1", | ||
"jest": "^24.7.1", | ||
"rollup": "^1.10.1" | ||
}, | ||
"dependencies": { | ||
"ml-matrix": "^5.0.0", | ||
"ml-regression-base": "^1.1.1" | ||
"ml-matrix": "^6.1.2", | ||
"ml-regression-base": "^2.0.1" | ||
} | ||
} |
# regression-polynomial | ||
[![NPM version][npm-image]][npm-url] | ||
[![build status][travis-image]][travis-url] | ||
[![npm download][download-image]][download-url] | ||
[![NPM version][npm-image]][npm-url] | ||
[![build status][travis-image]][travis-url] | ||
[![npm download][download-image]][download-url] | ||
@@ -11,3 +11,3 @@ Polynomial Regression. | ||
`$ npm install --save ml-regression-polynomial` | ||
`$ npm i ml-regression-polynomial` | ||
@@ -34,3 +34,3 @@ ## Usage | ||
[MIT](./LICENSE) | ||
[MIT](./LICENSE) | ||
@@ -37,0 +37,0 @@ [npm-image]: https://img.shields.io/npm/v/ml-regression-polynomial.svg?style=flat-square |
import PolynomialRegression from '..'; | ||
describe('Polynomial regression', () => { | ||
it('degree 2', () => { | ||
const x = [-3, 0, 2, 4]; | ||
const y = [3, 1, 1, 3]; | ||
const result = new PolynomialRegression(x, y, 2); | ||
it('degree 2', () => { | ||
const x = [-3, 0, 2, 4]; | ||
const y = [3, 1, 1, 3]; | ||
const result = new PolynomialRegression(x, y, 2); | ||
const expected = [0.850519, -0.192495, 0.178462]; | ||
const expected = [0.850519, -0.192495, 0.178462]; | ||
for (let i = 0; i < expected.length; ++i) { | ||
expect(result.coefficients[i]).toBeCloseTo(expected[i], 10e-6); | ||
expect(result.powers[i]).toEqual(i); | ||
} | ||
for (let i = 0; i < expected.length; ++i) { | ||
expect(result.coefficients[i]).toBeCloseTo(expected[i], 10e-6); | ||
expect(result.powers[i]).toBe(i); | ||
} | ||
const score = result.score(x, y); | ||
expect(score.r2).toBeGreaterThan(0.8); | ||
expect(score.chi2).toBeLessThan(0.1); | ||
expect(score.rmsd).toBeLessThan(0.01); | ||
expect(result.toString(4)).toEqual('f(x) = 0.1785 * x^2 - 0.1925 * x + 0.8505'); | ||
expect(result.toLaTeX(2)).toEqual('f(x) = 0.18x^{2} - 0.19x + 0.85'); | ||
}); | ||
const score = result.score(x, y); | ||
expect(score.r2).toBeGreaterThan(0.8); | ||
expect(score.chi2).toBeLessThan(0.1); | ||
expect(score.rmsd).toBeCloseTo(0.12); | ||
expect(result.toString(4)).toBe( | ||
'f(x) = 0.1785 * x^2 - 0.1925 * x + 0.8505' | ||
); | ||
expect(result.toLaTeX(2)).toBe('f(x) = 0.18x^{2} - 0.19x + 0.85'); | ||
}); | ||
it('degree 5', () => { | ||
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; | ||
const regression = new PolynomialRegression(x, y, degree); | ||
expect(regression.predict(80)).toBeCloseTo(2.6, 1e-6); | ||
expect(regression.coefficients).toEqual([17.39552328011271, -0.3916378430736305, -0.0019874818431079486, 0.0001367602062643227, -0.000001302280135149651, 3.837755337564968e-9]); | ||
expect(regression.toString(3)).toEqual('f(x) = 3.84e-9 * x^5 - 0.00000130 * x^4 + 0.000137 * x^3 - 0.00199 * x^2 - 0.392 * x + 17.4'); | ||
it('degree 5', () => { | ||
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; | ||
const regression = new PolynomialRegression(x, y, degree); | ||
expect(regression.predict(80)).toBeCloseTo(2.6, 1e-6); | ||
expect(regression.coefficients).toStrictEqual([ | ||
17.39552328011271, | ||
-0.3916378430736305, | ||
-0.0019874818431079486, | ||
0.0001367602062643227, | ||
-0.000001302280135149651, | ||
3.837755337564968e-9 | ||
]); | ||
expect(regression.toString(3)).toBe( | ||
'f(x) = 3.84e-9 * x^5 - 0.00000130 * x^4 + 0.000137 * x^3 - 0.00199 * x^2 - 0.392 * x + 17.4' | ||
); | ||
}); | ||
it('toJSON and load', () => { | ||
const regression = PolynomialRegression.load({ | ||
name: 'polynomialRegression', | ||
degree: 1, | ||
powers: [1], | ||
coefficients: [-1] | ||
}); | ||
it('toJSON and load', () => { | ||
const regression = PolynomialRegression.load({ | ||
name: 'polynomialRegression', | ||
degree: 1, | ||
powers: [1], | ||
coefficients: [-1] | ||
}); | ||
expect(regression.predict(1)).toBe(-1); | ||
expect(regression.predict(1)).toEqual(-1); | ||
const model = regression.toJSON(); | ||
expect(model).toEqual({ | ||
name: 'polynomialRegression', | ||
degree: 1, | ||
powers: [1], | ||
coefficients: [-1] | ||
}); | ||
const model = regression.toJSON(); | ||
expect(model).toStrictEqual({ | ||
name: 'polynomialRegression', | ||
degree: 1, | ||
powers: [1], | ||
coefficients: [-1] | ||
}); | ||
}); | ||
}); |
206
src/index.js
@@ -1,122 +0,132 @@ | ||
import BaseRegression, {checkArrayLength, maybeToPrecision} from 'ml-regression-base'; | ||
import Matrix, {solve} from 'ml-matrix'; | ||
import BaseRegression, { | ||
checkArrayLength, | ||
maybeToPrecision | ||
} from 'ml-regression-base'; | ||
import { Matrix, MatrixTransposeView, solve } from 'ml-matrix'; | ||
export default class PolynomialRegression extends BaseRegression { | ||
constructor(x, y, degree) { | ||
super(); | ||
if (x === true) { | ||
this.degree = y.degree; | ||
this.powers = y.powers; | ||
this.coefficients = y.coefficients; | ||
} else { | ||
checkArrayLength(x, y); | ||
regress(this, x, y, degree); | ||
} | ||
constructor(x, y, degree) { | ||
super(); | ||
if (x === true) { | ||
this.degree = y.degree; | ||
this.powers = y.powers; | ||
this.coefficients = y.coefficients; | ||
} else { | ||
checkArrayLength(x, y); | ||
regress(this, x, y, degree); | ||
} | ||
} | ||
_predict(x) { | ||
let y = 0; | ||
for (let k = 0; k < this.powers.length; k++) { | ||
y += this.coefficients[k] * Math.pow(x, this.powers[k]); | ||
} | ||
return y; | ||
_predict(x) { | ||
let y = 0; | ||
for (let k = 0; k < this.powers.length; k++) { | ||
y += this.coefficients[k] * Math.pow(x, this.powers[k]); | ||
} | ||
return y; | ||
} | ||
toJSON() { | ||
return { | ||
name: 'polynomialRegression', | ||
degree: this.degree, | ||
powers: this.powers, | ||
coefficients: this.coefficients | ||
}; | ||
} | ||
toJSON() { | ||
return { | ||
name: 'polynomialRegression', | ||
degree: this.degree, | ||
powers: this.powers, | ||
coefficients: this.coefficients | ||
}; | ||
} | ||
toString(precision) { | ||
return this._toFormula(precision, false); | ||
} | ||
toString(precision) { | ||
return this._toFormula(precision, false); | ||
} | ||
toLaTeX(precision) { | ||
return this._toFormula(precision, true); | ||
toLaTeX(precision) { | ||
return this._toFormula(precision, true); | ||
} | ||
_toFormula(precision, isLaTeX) { | ||
let sup = '^'; | ||
let closeSup = ''; | ||
let times = ' * '; | ||
if (isLaTeX) { | ||
sup = '^{'; | ||
closeSup = '}'; | ||
times = ''; | ||
} | ||
_toFormula(precision, isLaTeX) { | ||
let sup = '^'; | ||
let closeSup = ''; | ||
let times = ' * '; | ||
if (isLaTeX) { | ||
sup = '^{'; | ||
closeSup = '}'; | ||
times = ''; | ||
let fn = ''; | ||
let str = ''; | ||
for (let k = 0; k < this.coefficients.length; k++) { | ||
str = ''; | ||
if (this.coefficients[k] !== 0) { | ||
if (this.powers[k] === 0) { | ||
str = maybeToPrecision(this.coefficients[k], precision); | ||
} else { | ||
if (this.powers[k] === 1) { | ||
str = | ||
`${maybeToPrecision(this.coefficients[k], precision) + times}x`; | ||
} else { | ||
str = | ||
`${maybeToPrecision(this.coefficients[k], precision) + | ||
times | ||
}x${ | ||
sup | ||
}${this.powers[k] | ||
}${closeSup}`; | ||
} | ||
} | ||
let fn = ''; | ||
let str = ''; | ||
for (let k = 0; k < this.coefficients.length; k++) { | ||
str = ''; | ||
if (this.coefficients[k] !== 0) { | ||
if (this.powers[k] === 0) { | ||
str = maybeToPrecision(this.coefficients[k], precision); | ||
} else { | ||
if (this.powers[k] === 1) { | ||
str = maybeToPrecision(this.coefficients[k], precision) + times + 'x'; | ||
} else { | ||
str = maybeToPrecision(this.coefficients[k], precision) + times + 'x' + sup + this.powers[k] + closeSup; | ||
} | ||
} | ||
if (this.coefficients[k] > 0 && k !== (this.coefficients.length - 1)) { | ||
str = ' + ' + str; | ||
} else if (k !== (this.coefficients.length - 1)) { | ||
str = ' ' + str; | ||
} | ||
} | ||
fn = str + fn; | ||
if (this.coefficients[k] > 0 && k !== this.coefficients.length - 1) { | ||
str = ` + ${str}`; | ||
} else if (k !== this.coefficients.length - 1) { | ||
str = ` ${str}`; | ||
} | ||
if (fn.charAt(0) === '+') { | ||
fn = fn.slice(1); | ||
} | ||
return 'f(x) = ' + fn; | ||
} | ||
fn = str + fn; | ||
} | ||
if (fn.charAt(0) === '+') { | ||
fn = fn.slice(1); | ||
} | ||
static load(json) { | ||
if (json.name !== 'polynomialRegression') { | ||
throw new TypeError('not a polynomial regression model'); | ||
} | ||
return new PolynomialRegression(true, json); | ||
return `f(x) = ${fn}`; | ||
} | ||
static load(json) { | ||
if (json.name !== 'polynomialRegression') { | ||
throw new TypeError('not a polynomial regression model'); | ||
} | ||
return new PolynomialRegression(true, json); | ||
} | ||
} | ||
function regress(pr, x, y, degree) { | ||
const n = x.length; | ||
let powers; | ||
if (Array.isArray(degree)) { | ||
powers = degree; | ||
degree = powers.length; | ||
} else { | ||
degree++; | ||
powers = new Array(degree); | ||
for (let k = 0; k < degree; k++) { | ||
powers[k] = k; | ||
} | ||
} | ||
const F = new Matrix(n, degree); | ||
const Y = new Matrix([y]); | ||
const n = x.length; | ||
let powers; | ||
if (Array.isArray(degree)) { | ||
powers = degree; | ||
degree = powers.length; | ||
} else { | ||
degree++; | ||
powers = new Array(degree); | ||
for (let k = 0; k < degree; k++) { | ||
for (let i = 0; i < n; i++) { | ||
if (powers[k] === 0) { | ||
F[i][k] = 1; | ||
} else { | ||
F[i][k] = Math.pow(x[i], powers[k]); | ||
} | ||
} | ||
powers[k] = k; | ||
} | ||
} | ||
const F = new Matrix(n, degree); | ||
const Y = new Matrix([y]); | ||
for (let k = 0; k < degree; k++) { | ||
for (let i = 0; i < n; i++) { | ||
if (powers[k] === 0) { | ||
F.set(i, k, 1); | ||
} else { | ||
F.set(i, k, Math.pow(x[i], powers[k])); | ||
} | ||
} | ||
} | ||
const FT = F.transposeView(); | ||
const A = FT.mmul(F); | ||
const B = FT.mmul(Y.transposeView()); | ||
const FT = new MatrixTransposeView(F); | ||
const A = FT.mmul(F); | ||
const B = FT.mmul(new MatrixTransposeView(Y)); | ||
pr.degree = degree - 1; | ||
pr.powers = powers; | ||
pr.coefficients = solve(A, B).to1DArray(); | ||
pr.degree = degree - 1; | ||
pr.powers = powers; | ||
pr.coefficients = solve(A, B).to1DArray(); | ||
} |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
310
13033
+ Addedml-matrix@6.12.0(transitive)
+ Addedml-regression-base@2.1.6(transitive)
- Removedml-matrix@5.3.0(transitive)
- Removedml-regression-base@1.2.1(transitive)
Updatedml-matrix@^6.1.2
Updatedml-regression-base@^2.0.1