add linear regression, swagger for documentation functions

This commit is contained in:
raymond 2025-09-05 00:17:31 +00:00
parent faa546d474
commit 80aae6b21c
2 changed files with 1524 additions and 409 deletions

101
prediction.ts Normal file
View file

@ -0,0 +1,101 @@
import * as math from 'mathjs';
// The structure for the returned regression model
export interface LinearRegressionModel {
slope: number;
intercept: number;
predict: (x: number) => number;
}
// The structure for the full forecast output
export interface ForecastResult {
forecast: number[];
predictionIntervals: {
upperBound: number[];
lowerBound: number[];
};
modelParameters: {
slope: number;
intercept: number;
};
}
/**
* Calculates the linear regression model from a time series.
* @param yValues The historical data points (e.g., sales per month).
* @returns {LinearRegressionModel} An object containing the model's parameters and a predict function.
*/
export function calculateLinearRegression(yValues: number[]): LinearRegressionModel {
if (yValues.length < 2) {
throw new Error('At least two data points are required for linear regression.');
}
const xValues = Array.from({ length: yValues.length }, (_, i) => i);
const meanX = Number(math.mean(xValues));
const meanY = Number(math.mean(yValues));
const stdDevX = Number(math.std(xValues, 'uncorrected'));
const stdDevY = Number(math.std(yValues, 'uncorrected'));
// Ensure stdDevX is not zero to avoid division by zero
if (stdDevX === 0) {
// This happens if all xValues are the same, which is impossible in this time series context,
// but it's good practice to handle. A vertical line has an infinite slope.
// For simplicity, we can return a model with zero slope.
return { slope: 0, intercept: meanY, predict: (x: number) => meanY };
}
// Cast the result of math.sum to a Number
const correlationNumerator = Number(math.sum(xValues.map((x, i) => (x - meanX) * (yValues[i] - meanY))));
const correlation = correlationNumerator / ((xValues.length - 1) * stdDevX * stdDevY);
const slope = correlation * (stdDevY / stdDevX);
const intercept = meanY - slope * meanX;
const predict = (x: number): number => slope * x + intercept;
return { slope, intercept, predict };
}
/**
* Generates a forecast for a specified number of future periods.
* @param model The calculated linear regression model.
* @param historicalDataLength The number of historical data points.
* @param forecastPeriods The number of future periods to predict.
* @returns {number[]} An array of forecasted values.
*/
export function generateForecast(model: LinearRegressionModel, historicalDataLength: number, forecastPeriods: number): number[] {
const forecast: number[] = [];
const startPeriod = historicalDataLength;
for (let i = 0; i < forecastPeriods; i++) {
const futureX = startPeriod + i;
forecast.push(model.predict(futureX));
}
return forecast;
}
/**
* Calculates prediction intervals to show the range of uncertainty.
* @param yValues The original historical data.
* @param model The calculated linear regression model.
* @param forecast The array of forecasted values.
* @returns An object with upperBound and lowerBound arrays.
*/
export function calculatePredictionIntervals(yValues: number[], model: LinearRegressionModel, forecast: number[]) {
const n = yValues.length;
const residualsSquaredSum = yValues.reduce((sum, y, i) => {
const predictedY = model.predict(i);
return sum + (y - predictedY) ** 2;
}, 0);
const stdError = Math.sqrt(residualsSquaredSum / (n - 2));
const zScore = 1.96; // For a 95% confidence level
const marginOfError = zScore * stdError;
const upperBound = forecast.map(val => val + marginOfError);
const lowerBound = forecast.map(val => val - marginOfError);
return { upperBound, lowerBound };
}

1156
server.ts

File diff suppressed because it is too large Load diff