ml-regression-base
Advanced tools
Comparing version 1.2.0 to 1.2.1
@@ -0,1 +1,5 @@ | ||
## [1.2.1](https://github.com/mljs/regression-base/compare/v1.2.0...v1.2.1) (2019-04-15) | ||
<a name="1.2.0"></a> | ||
@@ -2,0 +6,0 @@ # [1.2.0](https://github.com/mljs/regression-base/compare/v1.1.1...v1.2.0) (2017-04-28) |
180
lib/index.js
@@ -6,113 +6,115 @@ 'use strict'; | ||
function maybeToPrecision(value, digits) { | ||
if (value < 0) { | ||
value = 0 - value; | ||
if (typeof digits === 'number') { | ||
return '- ' + value.toPrecision(digits); | ||
} else { | ||
return '- ' + value.toString(); | ||
} | ||
if (value < 0) { | ||
value = 0 - value; | ||
if (typeof digits === 'number') { | ||
return `- ${value.toPrecision(digits)}`; | ||
} else { | ||
if (typeof digits === 'number') { | ||
return value.toPrecision(digits); | ||
} else { | ||
return value.toString(); | ||
} | ||
return `- ${value.toString()}`; | ||
} | ||
} else { | ||
if (typeof digits === 'number') { | ||
return value.toPrecision(digits); | ||
} else { | ||
return value.toString(); | ||
} | ||
} | ||
} | ||
function checkArraySize(x, y) { | ||
if (!Array.isArray(x) || !Array.isArray(y)) { | ||
throw new TypeError('x and y must be arrays'); | ||
} | ||
if (x.length !== y.length) { | ||
throw new RangeError('x and y arrays must have the same length'); | ||
} | ||
if (!Array.isArray(x) || !Array.isArray(y)) { | ||
throw new TypeError('x and y must be arrays'); | ||
} | ||
if (x.length !== y.length) { | ||
throw new RangeError('x and y arrays must have the same length'); | ||
} | ||
} | ||
class BaseRegression { | ||
constructor() { | ||
if (new.target === BaseRegression) { | ||
throw new Error('BaseRegression must be subclassed'); | ||
} | ||
constructor() { | ||
if (new.target === BaseRegression) { | ||
throw new Error('BaseRegression must be subclassed'); | ||
} | ||
} | ||
predict(x) { | ||
if (typeof x === 'number') { | ||
return this._predict(x); | ||
} else if (Array.isArray(x)) { | ||
const y = new Array(x.length); | ||
for (let i = 0; i < x.length; i++) { | ||
y[i] = this._predict(x[i]); | ||
} | ||
return y; | ||
} else { | ||
throw new TypeError('x must be a number or array'); | ||
} | ||
predict(x) { | ||
if (typeof x === 'number') { | ||
return this._predict(x); | ||
} else if (Array.isArray(x)) { | ||
const y = new Array(x.length); | ||
for (let i = 0; i < x.length; i++) { | ||
y[i] = this._predict(x[i]); | ||
} | ||
return y; | ||
} else { | ||
throw new TypeError('x must be a number or array'); | ||
} | ||
} | ||
_predict() { | ||
throw new Error('_predict must be implemented'); | ||
} | ||
_predict() { | ||
throw new Error('_predict must be implemented'); | ||
} | ||
train() { | ||
//Do nothing for this package | ||
train() { | ||
// Do nothing for this package | ||
} | ||
toString() { | ||
return ''; | ||
} | ||
toLaTeX() { | ||
return ''; | ||
} | ||
/** | ||
* Return the correlation coefficient of determination (r) and chi-square. | ||
* @param {Array<number>} x | ||
* @param {Array<number>} y | ||
* @return {object} | ||
*/ | ||
score(x, y) { | ||
if (!Array.isArray(x) || !Array.isArray(y) || x.length !== y.length) { | ||
throw new Error('x and y must be arrays of the same length'); | ||
} | ||
toString() { | ||
return ''; | ||
const n = x.length; | ||
const y2 = new Array(n); | ||
for (let i = 0; i < n; i++) { | ||
y2[i] = this._predict(x[i]); | ||
} | ||
toLaTeX() { | ||
return ''; | ||
let xSum = 0; | ||
let ySum = 0; | ||
let chi2 = 0; | ||
let rmsd = 0; | ||
let xSquared = 0; | ||
let ySquared = 0; | ||
let xY = 0; | ||
for (let i = 0; i < n; i++) { | ||
xSum += y2[i]; | ||
ySum += y[i]; | ||
xSquared += y2[i] * y2[i]; | ||
ySquared += y[i] * y[i]; | ||
xY += y2[i] * y[i]; | ||
if (y[i] !== 0) { | ||
chi2 += ((y[i] - y2[i]) * (y[i] - y2[i])) / y[i]; | ||
} | ||
rmsd += (y[i] - y2[i]) * (y[i] - y2[i]); | ||
} | ||
/** | ||
* Return the correlation coefficient of determination (r) and chi-square. | ||
* @param {Array<number>} x | ||
* @param {Array<number>} y | ||
* @return {object} | ||
*/ | ||
score(x, y) { | ||
if (!Array.isArray(x) || !Array.isArray(y) || x.length !== y.length) { | ||
throw new Error('x and y must be arrays of the same length'); | ||
} | ||
const r = | ||
(n * xY - xSum * ySum) / | ||
Math.sqrt((n * xSquared - xSum * xSum) * (n * ySquared - ySum * ySum)); | ||
const n = x.length; | ||
const y2 = new Array(n); | ||
for (let i = 0; i < n; i++) { | ||
y2[i] = this._predict(x[i]); | ||
} | ||
let xSum = 0; | ||
let ySum = 0; | ||
let chi2 = 0; | ||
let rmsd = 0; | ||
let xSquared = 0; | ||
let ySquared = 0; | ||
let xY = 0; | ||
for (let i = 0; i < n; i++) { | ||
xSum += y2[i]; | ||
ySum += y[i]; | ||
xSquared += y2[i] * y2[i]; | ||
ySquared += y[i] * y[i]; | ||
xY += y2[i] * y[i]; | ||
if (y[i] !== 0) { | ||
chi2 += (y[i] - y2[i]) * (y[i] - y2[i]) / y[i]; | ||
} | ||
rmsd = (y[i] - y2[i]) * (y[i] - y2[i]); | ||
} | ||
const r = (n * xY - xSum * ySum) / Math.sqrt((n * xSquared - xSum * xSum) * (n * ySquared - ySum * ySum)); | ||
return { | ||
r: r, | ||
r2: r * r, | ||
chi2: chi2, | ||
rmsd: rmsd * rmsd / n | ||
}; | ||
} | ||
return { | ||
r: r, | ||
r2: r * r, | ||
chi2: chi2, | ||
rmsd: Math.sqrt(rmsd / n) | ||
}; | ||
} | ||
} | ||
exports['default'] = BaseRegression; | ||
exports.checkArrayLength = checkArraySize; | ||
exports.default = BaseRegression; | ||
exports.maybeToPrecision = maybeToPrecision; | ||
exports.checkArrayLength = checkArraySize; |
{ | ||
"name": "ml-regression-base", | ||
"version": "1.2.0", | ||
"version": "1.2.1", | ||
"description": "Base class for regression modules", | ||
@@ -15,4 +15,5 @@ "main": "lib/index.js", | ||
"prepublish": "rollup -c", | ||
"test": "run-s testonly eslint", | ||
"testonly": "jest" | ||
"test": "npm run test-coverage && npm run eslint", | ||
"test-coverage": "jest --coverage", | ||
"test-only": "jest" | ||
}, | ||
@@ -34,11 +35,12 @@ "repository": { | ||
"devDependencies": { | ||
"babel-jest": "^19.0.0", | ||
"babel-plugin-transform-es2015-modules-commonjs": "^6.24.1", | ||
"eslint": "^3.19.0", | ||
"eslint-config-cheminfo": "^1.7.0", | ||
"eslint-plugin-no-only-tests": "^1.1.0", | ||
"jest": "^19.0.2", | ||
"npm-run-all": "^4.0.2", | ||
"rollup": "^0.41.6" | ||
"babel-jest": "^24.7.1", | ||
"babel-plugin-transform-es2015-modules-commonjs": "^6.26.2", | ||
"eslint": "^5.16.0", | ||
"eslint-config-cheminfo": "^1.20.1", | ||
"eslint-plugin-import": "^2.17.1", | ||
"eslint-plugin-jest": "^22.4.1", | ||
"eslint-plugin-no-only-tests": "^2.3.0", | ||
"jest": "^24.7.1", | ||
"rollup": "^1.10.0" | ||
} | ||
} |
@@ -28,3 +28,3 @@ # regression-base | ||
toString() { | ||
return 'f(x) = x * 2'; | ||
return `f(x) = x * ${this.factor}`; | ||
} | ||
@@ -31,0 +31,0 @@ } |
import checkArrayLength from '../checkArrayLength'; | ||
describe('checkArrayLength', () => { | ||
it('throws on different Length', () => { | ||
const expected = /x and y arrays must have the same length/; | ||
expect(() => checkArrayLength([], [1])).toThrow(expected); | ||
expect(() => checkArrayLength([1], [])).toThrow(expected); | ||
expect(() => checkArrayLength([1], [1, 2])).toThrow(expected); | ||
}); | ||
it('throws on different Length', () => { | ||
const expected = /x and y arrays must have the same length/; | ||
expect(() => checkArrayLength([], [1])).toThrow(expected); | ||
expect(() => checkArrayLength([1], [])).toThrow(expected); | ||
expect(() => checkArrayLength([1], [1, 2])).toThrow(expected); | ||
}); | ||
it('throws if not arrays', () => { | ||
const expected = /x and y must be arrays/; | ||
expect(() => checkArrayLength(null, [1])).toThrow(expected); | ||
expect(() => checkArrayLength([], null)).toThrow(expected); | ||
expect(() => checkArrayLength()).toThrow(expected); | ||
expect(() => checkArrayLength(42, [])).toThrow(expected); | ||
expect(() => checkArrayLength([], 'hello')).toThrow(expected); | ||
}); | ||
it('does nothing if same Length', () => { | ||
checkArrayLength([1], [2]); | ||
checkArrayLength([], []); | ||
checkArrayLength(new Array(10), new Array(10)); | ||
}); | ||
it('throws if not arrays', () => { | ||
const expected = /x and y must be arrays/; | ||
expect(() => checkArrayLength(null, [1])).toThrow(expected); | ||
expect(() => checkArrayLength([], null)).toThrow(expected); | ||
expect(() => checkArrayLength()).toThrow(expected); | ||
expect(() => checkArrayLength(42, [])).toThrow(expected); | ||
expect(() => checkArrayLength([], 'hello')).toThrow(expected); | ||
}); | ||
}); |
import maybeToPrecision from '../maybeToPrecision'; | ||
describe('maybeToPrecision', () => { | ||
it('positive number - no digit', () => { | ||
expect(maybeToPrecision(0)).toEqual('0'); | ||
expect(maybeToPrecision(10)).toEqual('10'); | ||
expect(maybeToPrecision(0.052469)).toEqual('0.052469'); | ||
}); | ||
it('positive number - no digit', () => { | ||
expect(maybeToPrecision(0)).toStrictEqual('0'); | ||
expect(maybeToPrecision(10)).toStrictEqual('10'); | ||
expect(maybeToPrecision(0.052469)).toStrictEqual('0.052469'); | ||
}); | ||
it('positive number - digit', () => { | ||
expect(maybeToPrecision(0, 1)).toEqual('0'); | ||
expect(maybeToPrecision(0, 2)).toEqual('0.0'); | ||
expect(maybeToPrecision(0.52469, 3)).toEqual('0.525'); | ||
}); | ||
it('positive number - digit', () => { | ||
expect(maybeToPrecision(0, 1)).toStrictEqual('0'); | ||
expect(maybeToPrecision(0, 2)).toStrictEqual('0.0'); | ||
expect(maybeToPrecision(0.52469, 3)).toStrictEqual('0.525'); | ||
}); | ||
it('negative number - no digit', () => { | ||
expect(maybeToPrecision(-0)).toEqual('0'); | ||
expect(maybeToPrecision(-10)).toEqual('- 10'); | ||
expect(maybeToPrecision(-0.052469)).toEqual('- 0.052469'); | ||
}); | ||
it('negative number - no digit', () => { | ||
expect(maybeToPrecision(-0)).toStrictEqual('0'); | ||
expect(maybeToPrecision(-10)).toStrictEqual('- 10'); | ||
expect(maybeToPrecision(-0.052469)).toStrictEqual('- 0.052469'); | ||
}); | ||
it('negative number - digit', () => { | ||
expect(maybeToPrecision(-0, 1)).toEqual('0'); | ||
expect(maybeToPrecision(-0, 2)).toEqual('0.0'); | ||
expect(maybeToPrecision(-0.52469, 3)).toEqual('- 0.525'); | ||
expect(maybeToPrecision(-4, 3)).toEqual('- 4.00'); | ||
}); | ||
it('negative number - digit', () => { | ||
expect(maybeToPrecision(-0, 1)).toStrictEqual('0'); | ||
expect(maybeToPrecision(-0, 2)).toStrictEqual('0.0'); | ||
expect(maybeToPrecision(-0.52469, 3)).toStrictEqual('- 0.525'); | ||
expect(maybeToPrecision(-4, 3)).toStrictEqual('- 4.00'); | ||
}); | ||
it('wrong digit option', () => { | ||
expect(function () { | ||
maybeToPrecision(0, 0); | ||
}).toThrow(/argument must be between 1 and 21/); | ||
}); | ||
it('wrong digit option', () => { | ||
expect(function () { | ||
maybeToPrecision(0, 0); | ||
}).toThrow(/toPrecision\(\) argument must be between 1 and (100|21)/); | ||
}); | ||
}); |
@@ -5,61 +5,64 @@ import BaseRegression from '..'; | ||
class Basic extends BaseRegression { | ||
constructor(factor) { | ||
super(); | ||
this.factor = factor; | ||
} | ||
_predict(x) { | ||
return x * this.factor; | ||
} | ||
constructor(factor) { | ||
super(); | ||
this.factor = factor; | ||
} | ||
_predict(x) { | ||
return x * this.factor; | ||
} | ||
} | ||
describe('base regression', () => { | ||
it('should not be directly constructable', () => { | ||
expect(function () { | ||
new BaseRegression(); | ||
}).toThrow(/BaseRegression must be subclassed/); | ||
}); | ||
it('should not be directly constructable', () => { | ||
expect(function () { | ||
// eslint-disable-next-line no-new | ||
new BaseRegression(); | ||
}).toThrow(/BaseRegression must be subclassed/); | ||
}); | ||
it('should throw if _predict is not implemented', () => { | ||
const reg = new NoPredict(); | ||
expect(function () { | ||
reg.predict(0); | ||
}).toThrow(/_predict must be implemented/); | ||
}); | ||
it('should throw if _predict is not implemented', () => { | ||
const reg = new NoPredict(); | ||
expect(function () { | ||
reg.predict(0); | ||
}).toThrow(/_predict must be implemented/); | ||
}); | ||
it('should do a basic prediction', () => { | ||
const basic = new Basic(2); | ||
expect(basic.predict(1)).toEqual(2); | ||
expect(basic.predict(2)).toEqual(4); | ||
expect(basic.predict([2, 3])).toEqual([4, 6]); | ||
}); | ||
it('should do a basic prediction', () => { | ||
const basic = new Basic(2); | ||
expect(basic.predict(1)).toStrictEqual(2); | ||
expect(basic.predict(2)).toStrictEqual(4); | ||
expect(basic.predict([2, 3])).toStrictEqual([4, 6]); | ||
}); | ||
it('should throw on invalid value', () => { | ||
const basic = new Basic(2); | ||
expect(function () { | ||
basic.predict(); | ||
}).toThrow(/must be a number or array/); | ||
}); | ||
it('should throw on invalid value', () => { | ||
const basic = new Basic(2); | ||
expect(function () { | ||
basic.predict(); | ||
}).toThrow(/must be a number or array/); | ||
}); | ||
it('should implement dummy predictor functions', () => { | ||
const basic = new Basic(2); | ||
basic.train(); // should not throw | ||
expect(basic.toString()).toEqual(''); | ||
expect(basic.toLaTeX()).toEqual(''); | ||
it('should implement dummy predictor functions', () => { | ||
const basic = new Basic(2); | ||
basic.train(); // should not throw | ||
expect(basic.toString()).toStrictEqual(''); | ||
expect(basic.toLaTeX()).toStrictEqual(''); | ||
}); | ||
it('should implement a scoring function', () => { | ||
const basic = new Basic(2); | ||
expect(basic.score([1, 2], [2, 4])).toStrictEqual({ | ||
r: 1, | ||
r2: 1, | ||
chi2: 0, | ||
rmsd: 0 | ||
}); | ||
expect(basic.score([1, 2], [2, 4.1]).rmsd).toBe(0.0707106781186545); | ||
it('should implement a scoring function', () => { | ||
const basic = new Basic(2); | ||
expect(basic.score([1, 2], [2, 4])).toEqual({ | ||
r: 1, | ||
r2: 1, | ||
chi2: 0, | ||
rmsd: 0 | ||
}); | ||
expect(basic.score([1, 2], [0.5, 2])).toEqual({ | ||
r: 1, | ||
r2: 1, | ||
chi2: 6.5, | ||
rmsd: 8 | ||
}); | ||
expect(basic.score([1, 2], [0.5, 2])).toStrictEqual({ | ||
r: 1, | ||
r2: 1, | ||
chi2: 6.5, | ||
rmsd: 1.7677669529663689 | ||
}); | ||
}); | ||
}); |
export default function checkArraySize(x, y) { | ||
if (!Array.isArray(x) || !Array.isArray(y)) { | ||
throw new TypeError('x and y must be arrays'); | ||
} | ||
if (x.length !== y.length) { | ||
throw new RangeError('x and y arrays must have the same length'); | ||
} | ||
if (!Array.isArray(x) || !Array.isArray(y)) { | ||
throw new TypeError('x and y must be arrays'); | ||
} | ||
if (x.length !== y.length) { | ||
throw new RangeError('x and y arrays must have the same length'); | ||
} | ||
} |
144
src/index.js
@@ -1,86 +0,88 @@ | ||
export {default as maybeToPrecision} from './maybeToPrecision'; | ||
export {default as checkArrayLength} from './checkArrayLength'; | ||
export { default as maybeToPrecision } from './maybeToPrecision'; | ||
export { default as checkArrayLength } from './checkArrayLength'; | ||
export default class BaseRegression { | ||
constructor() { | ||
if (new.target === BaseRegression) { | ||
throw new Error('BaseRegression must be subclassed'); | ||
} | ||
constructor() { | ||
if (new.target === BaseRegression) { | ||
throw new Error('BaseRegression must be subclassed'); | ||
} | ||
} | ||
predict(x) { | ||
if (typeof x === 'number') { | ||
return this._predict(x); | ||
} else if (Array.isArray(x)) { | ||
const y = new Array(x.length); | ||
for (let i = 0; i < x.length; i++) { | ||
y[i] = this._predict(x[i]); | ||
} | ||
return y; | ||
} else { | ||
throw new TypeError('x must be a number or array'); | ||
} | ||
predict(x) { | ||
if (typeof x === 'number') { | ||
return this._predict(x); | ||
} else if (Array.isArray(x)) { | ||
const y = new Array(x.length); | ||
for (let i = 0; i < x.length; i++) { | ||
y[i] = this._predict(x[i]); | ||
} | ||
return y; | ||
} else { | ||
throw new TypeError('x must be a number or array'); | ||
} | ||
} | ||
_predict() { | ||
throw new Error('_predict must be implemented'); | ||
} | ||
_predict() { | ||
throw new Error('_predict must be implemented'); | ||
} | ||
train() { | ||
//Do nothing for this package | ||
train() { | ||
// Do nothing for this package | ||
} | ||
toString() { | ||
return ''; | ||
} | ||
toLaTeX() { | ||
return ''; | ||
} | ||
/** | ||
* Return the correlation coefficient of determination (r) and chi-square. | ||
* @param {Array<number>} x | ||
* @param {Array<number>} y | ||
* @return {object} | ||
*/ | ||
score(x, y) { | ||
if (!Array.isArray(x) || !Array.isArray(y) || x.length !== y.length) { | ||
throw new Error('x and y must be arrays of the same length'); | ||
} | ||
toString() { | ||
return ''; | ||
const n = x.length; | ||
const y2 = new Array(n); | ||
for (let i = 0; i < n; i++) { | ||
y2[i] = this._predict(x[i]); | ||
} | ||
toLaTeX() { | ||
return ''; | ||
let xSum = 0; | ||
let ySum = 0; | ||
let chi2 = 0; | ||
let rmsd = 0; | ||
let xSquared = 0; | ||
let ySquared = 0; | ||
let xY = 0; | ||
for (let i = 0; i < n; i++) { | ||
xSum += y2[i]; | ||
ySum += y[i]; | ||
xSquared += y2[i] * y2[i]; | ||
ySquared += y[i] * y[i]; | ||
xY += y2[i] * y[i]; | ||
if (y[i] !== 0) { | ||
chi2 += ((y[i] - y2[i]) * (y[i] - y2[i])) / y[i]; | ||
} | ||
rmsd += (y[i] - y2[i]) * (y[i] - y2[i]); | ||
} | ||
/** | ||
* Return the correlation coefficient of determination (r) and chi-square. | ||
* @param {Array<number>} x | ||
* @param {Array<number>} y | ||
* @return {object} | ||
*/ | ||
score(x, y) { | ||
if (!Array.isArray(x) || !Array.isArray(y) || x.length !== y.length) { | ||
throw new Error('x and y must be arrays of the same length'); | ||
} | ||
const r = | ||
(n * xY - xSum * ySum) / | ||
Math.sqrt((n * xSquared - xSum * xSum) * (n * ySquared - ySum * ySum)); | ||
const n = x.length; | ||
const y2 = new Array(n); | ||
for (let i = 0; i < n; i++) { | ||
y2[i] = this._predict(x[i]); | ||
} | ||
let xSum = 0; | ||
let ySum = 0; | ||
let chi2 = 0; | ||
let rmsd = 0; | ||
let xSquared = 0; | ||
let ySquared = 0; | ||
let xY = 0; | ||
for (let i = 0; i < n; i++) { | ||
xSum += y2[i]; | ||
ySum += y[i]; | ||
xSquared += y2[i] * y2[i]; | ||
ySquared += y[i] * y[i]; | ||
xY += y2[i] * y[i]; | ||
if (y[i] !== 0) { | ||
chi2 += (y[i] - y2[i]) * (y[i] - y2[i]) / y[i]; | ||
} | ||
rmsd = (y[i] - y2[i]) * (y[i] - y2[i]); | ||
} | ||
const r = (n * xY - xSum * ySum) / Math.sqrt((n * xSquared - xSum * xSum) * (n * ySquared - ySum * ySum)); | ||
return { | ||
r: r, | ||
r2: r * r, | ||
chi2: chi2, | ||
rmsd: rmsd * rmsd / n | ||
}; | ||
} | ||
return { | ||
r: r, | ||
r2: r * r, | ||
chi2: chi2, | ||
rmsd: Math.sqrt(rmsd / n) | ||
}; | ||
} | ||
} |
export default function maybeToPrecision(value, digits) { | ||
if (value < 0) { | ||
value = 0 - value; | ||
if (typeof digits === 'number') { | ||
return '- ' + value.toPrecision(digits); | ||
} else { | ||
return '- ' + value.toString(); | ||
} | ||
if (value < 0) { | ||
value = 0 - value; | ||
if (typeof digits === 'number') { | ||
return `- ${value.toPrecision(digits)}`; | ||
} else { | ||
if (typeof digits === 'number') { | ||
return value.toPrecision(digits); | ||
} else { | ||
return value.toString(); | ||
} | ||
return `- ${value.toString()}`; | ||
} | ||
} else { | ||
if (typeof digits === 'number') { | ||
return value.toPrecision(digits); | ||
} else { | ||
return value.toString(); | ||
} | ||
} | ||
} |
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
13741
9