loess
Version:
JavaScript implementation of the Locally-Weighted Regression package originally written in C by Cleveland, Grosse and Shyu (1992)
140 lines (113 loc) • 5.17 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol ? "symbol" : typeof obj; };
exports.validateModel = validateModel;
exports.validatePredict = validatePredict;
exports.validateGrid = validateGrid;
function validateIsArray(target, msg) {
if (!Array.isArray(target)) throw new Error(msg);
}
function validateIsNumber(target, msg) {
if (typeof target !== 'number') throw new Error(msg);
}
function validateIsInteger(target, msg) {
validateIsNumber(target, msg);
if (target - Math.floor(target) > 0) throw new Error(msg);
}
function validateModel(data, options) {
if (!data) throw new Error('no data passed in to constructor');
if ((typeof data === 'undefined' ? 'undefined' : _typeof(data)) !== 'object') throw new Error('no data passed in to constructor');
var y = data.y;
var x = data.x;
var x2 = data.x2;
var w = data.w;
validateIsArray(y, 'Invalid type: y should be an array');
validateIsArray(x, 'Invalid type: x should be an array');
y.forEach(function (v) {
return validateIsNumber(v, 'Invalid type: y should include only numbers');
});
x.forEach(function (v) {
return validateIsNumber(v, 'Invalid type: x should include only numbers');
});
var n = y.length;
if (x.length !== n) throw new Error('y and x have different length');
x = [x];
if (x2) {
validateIsArray(x2, 'Invalid type: x2 should be an array');
x2.forEach(function (v) {
return validateIsNumber(v, 'Invalid type: x2 should include only numbers');
});
if (x2.length !== n) throw new Error('y and x2 have different length');
x.push(x2);
}
if (w) {
validateIsArray(w, 'Invalid type: w should be an array');
w.forEach(function (v) {
return validateIsNumber(v, 'Invalid type: w should include only numbers');
});
if (w.length !== n) throw new Error('y and w have different length');
} else {
w = Array(n).fill(1);
}
if (!options || (typeof options === 'undefined' ? 'undefined' : _typeof(options)) !== 'object') throw new Error('Invalid type: options should be passed in as an object');
options = Object.assign({
span: 0.75,
band: 0,
degree: 2,
normalize: true,
robust: false,
iterations: 4
}, options);
if (typeof options.degree === 'string') {
options.degree = ['constant', 'linear', 'quadratic'].indexOf(options.degree);
}
validateIsNumber(options.span, 'Invalid type: options.span should be a number');
if (options.span <= 0) throw new Error('options.span should be greater than 0');
validateIsNumber(options.band, 'Invalid type: options.band should be a number');
if (options.band < 0 || options.band > 0.99) throw new Error('options.band should be between 0 and 1');
validateIsInteger(options.degree, 'Invalid type: options.degree should be an integer');
if (options.degree < 0 || options.degree > 2) throw new Error('options.degree should be between 0 and 2');
if (typeof options.normalize !== 'boolean') throw new Error('Invalid type: options.normalize should be a boolean');
if (typeof options.robust !== 'boolean') throw new Error('Invalid type: options.robust should be a boolean');
validateIsInteger(options.iterations, 'Invalid type: options.iterations should be an integer');
if (options.iterations < 1) throw new Error('options.iterations should be at least 1');
if (!options.robust) options.iterations = 1;
var d = x2 ? 2 : 1;
var bandwidth = options.span > 1 ? Math.pow(options.span, 1 / d) : options.span;
return { y: y, x: x, w: w, n: n, d: d, options: options, bandwidth: bandwidth };
}
function validatePredict(data) {
if (!data) data = { x: this.x[0], x2: this.x[1] };
if ((typeof data === 'undefined' ? 'undefined' : _typeof(data)) !== 'object') throw new Error('Invalid type: data should be supplied as an object');
var _data = data;
var x = _data.x;
var _data$x = _data.x2;
var x2 = _data$x === undefined ? null : _data$x;
validateIsArray(x, 'Invalid type: x should be an array');
x.forEach(function (v) {
return validateIsNumber(v, 'Invalid type: x should include only numbers');
});
var x_new = [x];
var n = x.length;
if (this.d > 1) {
validateIsArray(x2, 'Invalid type: x2 should be an array');
x2.forEach(function (v) {
return validateIsNumber(v, 'Invalid type: x2 should include only numbers');
});
if (x2.length !== n) throw new Error('x and x2 have different length');
x_new.push(x2);
} else if (x2) {
throw new Error('extra variable x2');
}
return { x_new: x_new, n: n };
}
function validateGrid(cuts) {
validateIsArray(cuts, 'Invalid type: cuts should be an array');
cuts.forEach(function (cut) {
validateIsInteger(cut, 'Invalid type: cuts should include only integers');
if (cuts < 3) throw new Error('cuts should include only integers > 2');
});
if (cuts.length !== this.d) throw new Error('cuts.length should match dimension of predictors');
}