Last active
March 29, 2023 09:20
-
-
Save danielhaim1/e9ee7187f238b72590b5d634523cd631 to your computer and use it in GitHub Desktop.
Holt-Winters Forecasting Algorithm
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function holtWinters(alpha, beta, gamma, period, data) { | |
let seasonals = {}; | |
let r = []; | |
let initialSeasonals = []; | |
let detrended = []; | |
let forecast = []; | |
let dataPoints = data.length; | |
let avgSmooth = []; | |
let trendSmooth = []; | |
let seasonalSmooth = []; | |
//initialize seasonals to the average of each cycle | |
for (let i = 0; i < period; i++) { | |
seasonals[i] = []; | |
for (let j = i; j < dataPoints; j += period) { | |
seasonals[i].push(data[j]); | |
} | |
initialSeasonals[i] = (seasonals[i].reduce((a, b) => a + b, 0) / seasonals[i].length); | |
} | |
//initialize first level of smoothed averages | |
for (let i = 0; i < period; i++) { | |
avgSmooth[i] = (data.slice(i, i + period).reduce((a, b) => a + b, 0) / period); | |
} | |
//initialize first level of smoothed trends | |
for (let i = 0; i < period; i++) { | |
trendSmooth[i] = ((data[period + i] - data[i]) / period); | |
} | |
//initialize seasonalSmooth | |
for (let i = 0; i < period; i++) { | |
seasonalSmooth[i] = initialSeasonals[i] - avgSmooth[i]; | |
} | |
//determine r | |
for (let i = 0; i < dataPoints - period; i++) { | |
r[i] = data[period + i] - (avgSmooth[i] + trendSmooth[i]); | |
} | |
//smooth the detrended values | |
for (let i = 0; i < dataPoints - period; i++) { | |
detrended[i] = (alpha * (data[period + i] - seasonalSmooth[i])) + ((1 - alpha) * (detrended[i - 1] || r[0])); | |
} | |
//smooth the trend | |
for (let i = 0; i < period; i++) { | |
trendSmooth[period + i] = (beta * (detrended[i] - detrended[i - period])) + ((1 - beta) * trendSmooth[i]); | |
} | |
//smooth the seasonals | |
for (let i = 0; i < period; i++) { | |
seasonalSmooth[i] = (gamma * (data[period + i] - avgSmooth[i] - detrended[i])) + ((1 - gamma) * seasonalSmooth[i]); | |
} | |
//calculate the forecast | |
for (let i = 0; i < period; i++) { | |
forecast[i] = avgSmooth[i] + ((i + 1) * trendSmooth[period + i]) + seasonalSmooth[i - period]; | |
} | |
return forecast; | |
} | |
// Input data for the time series | |
const data = [ | |
100, | |
120, | |
130, | |
140, | |
150, | |
160, | |
170, | |
180, | |
190, | |
200, | |
210, | |
220, | |
230, | |
240, | |
250, | |
260, | |
270, | |
280, | |
290, | |
300, | |
]; | |
// Apply Holt-Winters method with alpha=0.2, beta=0.1, gamma=0.1, and period=4 | |
const forecast = hw(data, { | |
alpha: 0.2, | |
beta: 0.1, | |
gamma: 0.1, | |
period: 4, | |
forecastLength: 5, | |
}); | |
// Output the forecast values | |
console.log(forecast); | |
// Level: L(t) = alpha * Y(t) + (1 - alpha) * (L(t-1) + T(t-1)) | |
// Trend: T(t) = beta * (L(t) - L(t-1)) + (1 - beta) * T(t-1) | |
// Seasonality: S(t) = gamma * (Y(t) - L(t)) + (1 - gamma) * S(t-m) | |
// F(t+h) = L(t) + h * T(t) + S(t-m+1+(h-1)modm) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment