locutus
Version:
Locutus other languages' standard libraries to JavaScript for fun and educational purposes
51 lines (50 loc) • 2.32 kB
JavaScript
import { assertStatisticsArray, statisticsMeanFromSequence, sumProducts, toStatisticNumber, } from "../_helpers/_statistics.js";
export function linear_regression(x, y, proportional = false) {
// discuss at: https://locutus.io/python/statistics/linear_regression/
// parity verified: Python 3.12
// original by: Kevin van Zonneveld (https://kvz.io)
// note 1: Returns ordinary least-squares slope and intercept, mirroring Python's named tuple as a plain object.
// example 1: linear_regression([1, 2, 3], [2, 4, 6])
// returns 1: {slope: 2, intercept: 0}
// example 2: linear_regression([1, 2, 3], [1, 2, 2])
// returns 2: {slope: 0.5, intercept: 0.6666666666666667}
// example 3: linear_regression([1, 2, 3], [2, 4, 6], true)
// returns 3: {slope: 2, intercept: 0}
const xValues = assertStatisticsArray(x, 'linear_regression').map((value) => toStatisticNumber(value, 'linear_regression'));
const yValues = assertStatisticsArray(y, 'linear_regression').map((value) => toStatisticNumber(value, 'linear_regression'));
const n = xValues.length;
if (yValues.length !== n) {
throw new Error('linear regression requires that both inputs have same number of data points');
}
if (n < 2) {
throw new Error('linear regression requires at least two data points');
}
if (proportional) {
const sxy = sumProducts(xValues, yValues) + 0;
const sxx = sumProducts(xValues, xValues);
if (sxx === 0) {
throw new Error('x is constant');
}
return { slope: sxy / sxx, intercept: 0 };
}
const xbar = statisticsMeanFromSequence({
values: xValues,
integral: xValues.every(Number.isInteger),
});
const ybar = statisticsMeanFromSequence({
values: yValues,
integral: yValues.every(Number.isInteger),
});
const centeredX = xValues.map((value) => value - xbar);
const centeredY = yValues.map((value) => value - ybar);
const sxy = sumProducts(centeredX, centeredY) + 0;
const sxx = sumProducts(centeredX, centeredX);
if (sxx === 0) {
throw new Error('x is constant');
}
const slope = sxy / sxx;
return {
slope,
intercept: ybar - slope * xbar,
};
}