UNPKG

loess

Version:

JavaScript implementation of the Locally-Weighted Regression package originally written in C by Cleveland, Grosse and Shyu (1992)

128 lines (110 loc) 3.9 kB
'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); exports.weightFunc = weightFunc; exports.normalize = normalize; exports.transpose = transpose; exports.euclideanDist = euclideanDist; exports.distMatrix = distMatrix; exports.weightMatrix = weightMatrix; exports.polynomialExpansion = polynomialExpansion; exports.weightedLeastSquare = weightedLeastSquare; var _mathjs = require('mathjs'); var _mathjs2 = _interopRequireDefault(_mathjs); var _lodash = require('lodash.sortby'); var _lodash2 = _interopRequireDefault(_lodash); var _lodash3 = require('lodash.zip'); var _lodash4 = _interopRequireDefault(_lodash3); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function weightFunc(d, dmax, degree) { return d < dmax ? Math.pow(1 - Math.pow(d / dmax, degree), degree) : 0; } function normalize(referenceArr) { var cutoff = Math.ceil(0.1 * referenceArr.length); var trimmed_arr = (0, _lodash2.default)(referenceArr).slice(cutoff, referenceArr.length - cutoff); var sd = _mathjs2.default.std(trimmed_arr); return function (outputArr) { return outputArr.map(function (val) { return val / sd; }); }; } function transpose(X) { var transposed = []; var _loop = function _loop(i) { transposed.push(X.map(function (x) { return x[i]; })); }; for (var i = 0; i < X[0].length; i++) { _loop(i); } return transposed; } function euclideanDist(orig, dest) { if (orig.length < 2) { return Math.abs(orig[0] - dest[0]); } else { return Math.sqrt(orig.reduce(function (acc, val, idx) { return acc + Math.pow(val - dest[idx], 2); }, 0)); } } function distMatrix(origSet, destSet) { return origSet.map(function (orig) { return destSet.map(function (dest) { return euclideanDist(orig, dest); }); }); } function weightMatrix(distMat, inputWeights, bandwidth) { return distMat.map(function (distVect) { var sorted = (0, _lodash2.default)((0, _lodash4.default)(distVect, inputWeights), function (v) { return v[0]; }); var cutoff = _mathjs2.default.sum(inputWeights) * bandwidth; var sumOfWeights = 0; var cutoffIndex = sorted.findIndex(function (v) { sumOfWeights += v[1]; return sumOfWeights >= cutoff; }); var dmax = bandwidth > 1 ? sorted[sorted.length - 1][0] * bandwidth : sorted[cutoffIndex][0]; return _mathjs2.default.dotMultiply(distVect.map(function (d) { return weightFunc(d, dmax, 3); }), inputWeights); }); } function polynomialExpansion(factors, degree) { var expandedSet = []; var constTerm = 1; if (Array.isArray(factors[0])) constTerm = Array(factors[0].length).fill(1); function crossMultiply(accumulator, pointer, n) { if (n > 1) { for (var i = pointer; i < factors.length; i++) { crossMultiply(_mathjs2.default.dotMultiply(accumulator, factors[i]), i, n - 1); } } else { expandedSet.push(accumulator); } } for (var d = 0; d <= degree; d++) { crossMultiply(constTerm, 0, d + 1); }return expandedSet; } function weightedLeastSquare(predictors, response, weights) { try { var weightedY = _mathjs2.default.matrix(_mathjs2.default.dotMultiply(weights, response)); var weightedX = _mathjs2.default.transpose(_mathjs2.default.matrix(predictors.map(function (x) { return _mathjs2.default.dotMultiply(weights, x); }))); var LHS = _mathjs2.default.multiply(predictors, weightedX); var RHS = _mathjs2.default.multiply(predictors, weightedY); var beta = _mathjs2.default.multiply(_mathjs2.default.inv(LHS), RHS); var yhat = _mathjs2.default.squeeze(_mathjs2.default.multiply(beta, predictors)); var residual = _mathjs2.default.subtract(response, yhat); return { beta: beta, yhat: yhat, residual: residual }; } catch (err) { return { error: err }; } }