add linear regression, swagger for documentation functions
This commit is contained in:
parent
faa546d474
commit
80aae6b21c
2 changed files with 1524 additions and 409 deletions
101
prediction.ts
Normal file
101
prediction.ts
Normal 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 };
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue