///|
pub struct ForecastPoint {
prediction : Double
lower : Double
upper : Double
residual : Double
}
///|
pub fn ForecastPoint::new(
prediction : Double,
residual : Double,
uncertainty? : Double = 0.0,
) -> ForecastPoint {
let width = if uncertainty < 0.0 { 0.0 } else { uncertainty }
{ prediction, lower: prediction - width, upper: prediction + width, residual }
}
///|
pub struct LinearForecaster {
window : DoubleWindow
horizon : Int
uncertainty_multiplier : Double
}
///|
pub fn LinearForecaster::new(
window_size? : Int = 16,
horizon? : Int = 1,
uncertainty_multiplier? : Double = 2.0,
) -> LinearForecaster {
{
window: DoubleWindow::new(if window_size < 2 { 2 } else { window_size }),
horizon: if horizon < 1 {
1
} else {
horizon
},
uncertainty_multiplier: if uncertainty_multiplier < 0.0 {
0.0
} else {
uncertainty_multiplier
},
}
}
///|
pub fn LinearForecaster::fit(
self : LinearForecaster,
value : Double,
) -> ForecastPoint {
let prediction = if self.window.length() < 2 {
value
} else {
let slope = self.window.slope()
match self.window.last() {
None => value
Some(last) => last + slope * self.horizon.to_double()
}
}
let residual = if self.window.length() == 0 {
0.0
} else {
value - self.window.mean()
}
let uncertainty = self.window.standard_deviation() *
self.uncertainty_multiplier
ignore(self.window.push(value))
ForecastPoint::new(prediction, residual, uncertainty~)
}
///|
pub struct HoltForecaster {
mut level : Double
mut trend : Double
alpha : Double
beta : Double
mut count : Int
}
///|
pub fn HoltForecaster::new(
alpha? : Double = 0.2,
beta? : Double = 0.1,
) -> HoltForecaster {
{
level: 0.0,
trend: 0.0,
alpha: clamp_probability(alpha),
beta: clamp_probability(beta),
count: 0,
}
}
///|
pub fn HoltForecaster::update(
self : HoltForecaster,
value : Double,
horizon? : Int = 1,
) -> ForecastPoint {
if !is_finite(value) {
return ForecastPoint::new(self.level, 0.0)
}
if self.count == 0 {
self.level = value
self.count = 1
return ForecastPoint::new(value, 0.0)
}
let prediction = self.level + self.trend * horizon.to_double()
let previous_level = self.level
self.level = self.alpha * value +
(1.0 - self.alpha) * (self.level + self.trend)
self.trend = self.beta * (self.level - previous_level) +
(1.0 - self.beta) * self.trend
self.count += 1
ForecastPoint::new(
prediction,
value - prediction,
uncertainty=absolute(self.trend),
)
}
///|
pub struct Ar1Forecaster {
mut mean : Double
mut covariance : Double
mut variance : Double
mut previous : Double
mut count : Int
forgetting : Double
}
///|
pub fn Ar1Forecaster::new(forgetting? : Double = 0.05) -> Ar1Forecaster {
{
mean: 0.0,
covariance: 0.0,
variance: 1.0,
previous: 0.0,
count: 0,
forgetting: clamp_probability(forgetting),
}
}
///|
pub fn Ar1Forecaster::update(
self : Ar1Forecaster,
value : Double,
) -> ForecastPoint {
if self.count == 0 {
self.mean = value
self.previous = value
self.count = 1
return ForecastPoint::new(value, 0.0)
}
let denominator = if self.variance < 1.0e-12 { 1.0 } else { self.variance }
let phi = self.covariance / denominator
let prediction = self.mean + phi * (self.previous - self.mean)
let residual = value - prediction
let alpha = self.forgetting
self.mean += alpha * (value - self.mean)
self.covariance = (1.0 - alpha) * self.covariance +
alpha * (self.previous - self.mean) * (value - self.mean)
self.variance = (1.0 - alpha) * self.variance +
alpha * (value - self.mean) * (value - self.mean)
self.previous = value
self.count += 1
ForecastPoint::new(
prediction,
residual,
uncertainty=self.variance.sqrt() * 2.0,
)
}
///|
pub fn forecast_mae(
actual : Array[Double],
predicted : Array[Double],
) -> Double {
let n = if actual.length() < predicted.length() {
actual.length()
} else {
predicted.length()
}
if n == 0 {
return 0.0
}
let mut total = 0.0
for i in 0.. Double {
let n = if actual.length() < predicted.length() {
actual.length()
} else {
predicted.length()
}
if n == 0 {
return 0.0
}
let mut total = 0.0
for i in 0.. Double {
let n = if actual.length() < predicted.length() {
actual.length()
} else {
predicted.length()
}
if n == 0 {
return 0.0
}
let mut total = 0.0
let mut count = 0
for i in 0.. 1.0e-12 {
total += absolute((actual[i] - predicted[i]) / actual[i])
count += 1
}
}
if count == 0 {
0.0
} else {
total / count.to_double()
}
}