#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct Variance {
avg: Mean,
sum_2: f64,
}
impl Variance {
#[inline]
pub fn new() -> Variance {
Variance { avg: Mean::new(), sum_2: 0. }
}
#[inline]
fn increment(&mut self) {
self.avg.increment();
}
#[inline]
fn add_inner(&mut self, delta_n: f64) {
let n = self.avg.len().to_f64().unwrap();
self.avg.add_inner(delta_n);
self.sum_2 += delta_n * delta_n * n * (n - 1.);
}
#[inline]
pub fn is_empty(&self) -> bool {
self.avg.is_empty()
}
#[inline]
pub fn mean(&self) -> f64 {
self.avg.mean()
}
#[inline]
pub fn len(&self) -> u64 {
self.avg.len()
}
#[inline]
pub fn sample_variance(&self) -> f64 {
if self.avg.len() < 2 {
return f64::NAN;
}
self.sum_2 / (self.avg.len() - 1).to_f64().unwrap()
}
#[inline]
pub fn population_variance(&self) -> f64 {
let n = self.avg.len();
if n == 0 {
return f64::NAN;
}
self.sum_2 / n.to_f64().unwrap()
}
#[inline]
pub fn variance_of_mean(&self) -> f64 {
let n = self.avg.len();
if n == 0 {
return f64::NAN;
}
if n == 1 {
return 0.;
}
self.sample_variance() / n.to_f64().unwrap()
}
#[cfg(any(feature = "std", feature = "libm"))]
#[inline]
pub fn error(&self) -> f64 {
num_traits::Float::sqrt(self.variance_of_mean())
}
}
impl core::default::Default for Variance {
fn default() -> Variance {
Variance::new()
}
}
impl Estimate for Variance {
#[inline]
fn add(&mut self, sample: f64) {
self.increment();
let delta_n = (sample - self.avg.mean())
/ self.len().to_f64().unwrap();
self.add_inner(delta_n);
}
#[inline]
fn estimate(&self) -> f64 {
self.population_variance()
}
}
impl Merge for Variance {
#[inline]
fn merge(&mut self, other: &Variance) {
if other.is_empty() {
return;
}
if self.is_empty() {
*self = other.clone();
return;
}
let len_self = self.len().to_f64().unwrap();
let len_other = other.len().to_f64().unwrap();
let len_total = len_self + len_other;
let delta = other.mean() - self.mean();
self.avg.merge(&other.avg);
self.sum_2 += other.sum_2 + delta*delta * len_self * len_other / len_total;
}
}
impl_from_iterator!(Variance);
impl_from_par_iterator!(Variance);
impl_extend!(Variance);