JSFiddle - React, Tailwind, and code Playground
by sberube
HTML
<!DOCTYPE html>
<html>
<head>
<title>Holt's Linear Exponential Smoothing</title>
</head>
<body>
<script>
</script>
</body>
</html>
JavaScript
/**
* RubyGarage.
* https://rubygarage.org/
*
* Copyright (c) 2016 RubyGarage.
* Licensed under the MIT license.
*/
/**
* Returns augumented dataset, seasonal coefficients and errors.
*
* @param {Array<Number>} data - input data
* @param {Number} m - extrapolated future data points
*
* @returns {Object}
*/
function getAugumentedDataset(data, m) {
var initialparams = [0.0, 0.1, 0.2, 0.4, 0.6, 0.8, 1.0]
var alpha, beta, gamma, period, prediction
var err = Infinity
// TODO: rewrite this bruteforce with Levenberg-Marquardt equation
initialparams.forEach(function(a) {
initialparams.forEach(function(b) {
initialparams.forEach(function(g) {
for (var p = 1; p < data.length / 2; p++) {
var currentPrediction = getForecast(data, a, b, g, p, m)
var error
if (currentPrediction) {
error = mse(data, currentPrediction, p)
}
if (error && err > error) {
err = error
alpha = a
beta = b
gamma = g
period = p
prediction = currentPrediction
}
}
})
})
})
var augumentedDataset = prediction.slice()
for (var i = 0; i < data.length; i++) {
augumentedDataset[i] = data[i]
}
return {
augumentedDataset: augumentedDataset,
alpha: alpha,
beta: beta,
gamma: gamma,
period: period,
mse: mse(data, prediction, period),
sse: sse(data, prediction, period),
mpe: mpe(data, prediction, period)
}
}
function getForecast(data, alpha, beta, gamma, period, m) {
var seasons, seasonal, st1, bt1
if (!validArgs(data, alpha, beta, gamma, period, m)) {
return
}
seasons = Math.floor(data.length / period)
st1 = data[0]
bt1 = initialTrend(data, period)
seasonal = seasonalIndices(data, period, seasons)
return calcHoltWinters(
data,
st1,
bt1,
alpha,
beta,
gamma,
seasonal,
period,
m
)
}
function mse(origin,...