use std::iter;
use itertools::izip;
use num_traits::cast::ToPrimitive;
pub fn mse<'a, T: ToPrimitive>(data: &'a [T], estimate: &'a [T]) -> impl Iterator<Item = f64> + 'a {
data.iter()
.enumerate()
.zip(estimate)
.scan(0.0, |state, ((cnt, observe), est)| {
*state += (observe.to_f64().unwrap() - est.to_f64().unwrap()).powi(2);
Some(*state / (cnt + 1) as f64)
})
}
pub fn rmse<'a, T: ToPrimitive>(
data: &'a [T],
estimate: &'a [T],
) -> impl Iterator<Item = f64> + 'a {
data.iter()
.enumerate()
.zip(estimate)
.scan(0.0, |state, ((cnt, observe), est)| {
*state += (observe.to_f64().unwrap() - est.to_f64().unwrap()).powi(2);
Some((*state / (cnt + 1) as f64).sqrt())
})
}
pub fn mae<'a, T: ToPrimitive>(data: &'a [T], estimate: &'a [T]) -> impl Iterator<Item = f64> + 'a {
data.iter()
.enumerate()
.zip(estimate)
.scan(0.0, |state, ((cnt, observe), est)| {
*state += (observe.to_f64().unwrap() - est.to_f64().unwrap()).abs();
Some(*state / (cnt + 1) as f64)
})
}
pub fn mape<'a, T: ToPrimitive>(
data: &'a [T],
estimate: &'a [T],
) -> impl Iterator<Item = f64> + 'a {
data.iter()
.enumerate()
.zip(estimate)
.scan(0.0, |state, ((cnt, observe), est)| {
*state += ((observe.to_f64().unwrap() - est.to_f64().unwrap())
/ observe.to_f64().unwrap())
.abs();
Some(100.0 * *state / (cnt + 1) as f64)
})
}
pub fn smape<'a, T: ToPrimitive>(
data: &'a [T],
estimate: &'a [T],
) -> impl Iterator<Item = f64> + 'a {
data.iter()
.enumerate()
.zip(estimate)
.scan(0.0, |state, ((cnt, observe), est)| {
*state += ((observe.to_f64().unwrap() - est.to_f64().unwrap()).abs()
/ ((observe.to_f64().unwrap().abs() + est.to_f64().unwrap().abs()) / 2.0))
.max(0.0);
Some(100.0 * *state / (cnt + 1) as f64)
})
}
pub fn mda<'a, T: ToPrimitive>(data: &'a [T], estimate: &'a [T]) -> impl Iterator<Item = f64> + 'a {
iter::once(f64::NAN).chain(data[1..].iter().enumerate().zip(&estimate[1..]).scan(
(0.0, data[0].to_f64().unwrap()),
|state, ((cnt, observe), est)| {
let dir = ((observe.to_f64().unwrap() - state.1).signum()
== (est.to_f64().unwrap() - state.1).signum()) as u8 as f64;
*state = (state.0 + dir, observe.to_f64().unwrap());
Some(state.0 / (cnt + 1) as f64)
},
))
}
pub fn mase<'a, T: ToPrimitive>(
data: &'a [T],
estimate: &'a [T],
) -> impl Iterator<Item = f64> + 'a {
let mae_est = mae(data, estimate);
let mae_naive = data.windows(2).zip(1..).scan(0.0, |state, (w, cnt)| {
*state += (w[1].to_f64().unwrap() - w[0].to_f64().unwrap()).abs();
Some(*state / cnt as f64)
});
iter::once(f64::NAN).chain(
mae_est
.skip(1)
.zip(mae_naive)
.map(|(est, naive)| est / naive),
)
}
pub fn emae<'a, T: ToPrimitive>(
data: &'a [T],
estimate: &'a [T],
) -> impl Iterator<Item = f64> + 'a {
izip!(data, estimate, 1..).scan((0.0, 0.0), |state, (actual, est, n)| {
let actual = actual.to_f64().unwrap();
let est = est.to_f64().unwrap();
*state = (state.0 + (actual - est).abs(), state.1 + actual.max(est));
Some(state.0 / state.1 * 100. / n as f64)
})
}