Linear Regression Least Squares Fit

Fit a least-squares line to x/y points and return slope, intercept, R-squared and a prediction function with validation.

TypescriptData Integrity

Code

snippet
export interface Point {
  x: number;
  y: number;
}

export interface RegressionResult {
  slope: number;
  intercept: number;
  rSquared: number;
  predict: (x: number) => number;
}

export function linearRegression(points: readonly Point[]): RegressionResult {
  if (!Array.isArray(points) || points.length < 2) {
    throw new RangeError("points must contain at least two items");
  }
  for (const point of points) {
    if (!Number.isFinite(point.x) || !Number.isFinite(point.y)) {
      throw new TypeError("points must contain finite coordinates");
    }
  }
  const count = points.length;
  const meanX = points.reduce((total, point) => total + point.x, 0) / count;
  const meanY = points.reduce((total, point) => total + point.y, 0) / count;
  let numerator = 0;
  let denominator = 0;
  let total = 0;
  for (const point of points) {
    const dx = point.x - meanX;
    const dy = point.y - meanY;
    numerator += dx * dy;
    denominator += dx * dx;
    total += dy * dy;
  }
  if (denominator === 0) throw new RangeError("x values must not all be equal");
  const slope = numerator / denominator;
  const intercept = meanY - slope * meanX;
  const rSquared = total === 0 ? 1 : (numerator * numerator) / (denominator * total);
  return { slope, intercept, rSquared, predict: (x) => intercept + slope * x };
}