use num_traits::Float;
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct Skewness {
avg: MeanWithError,
sum_3: f64,
}
impl Skewness {
#[inline]
pub fn new() -> Skewness {
Skewness {
avg: MeanWithError::new(),
sum_3: 0.,
}
}
#[inline]
fn increment(&mut self) {
self.avg.increment();
}
#[inline]
fn add_inner(&mut self, delta: f64, delta_n: f64) {
let n = self.len().to_f64().unwrap();
let term = delta * delta_n * (n - 1.);
self.sum_3 += term * delta_n * (n - 2.)
- 3.*delta_n * self.avg.sum_2;
self.avg.add_inner(delta_n);
}
#[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 {
self.avg.sample_variance()
}
#[inline]
pub fn population_variance(&self) -> f64 {
self.avg.population_variance()
}
#[inline]
pub fn error_mean(&self) -> f64 {
self.avg.error()
}
#[inline]
pub fn skewness(&self) -> f64 {
if self.is_empty() {
return f64::NAN;
}
if self.sum_3 == 0. {
return 0.;
}
let n = self.len().to_f64().unwrap();
let sum_2 = self.avg.sum_2;
debug_assert_ne!(sum_2, 0.);
Float::sqrt(n) * self.sum_3 / Float::sqrt(sum_2*sum_2*sum_2)
}
}
impl Default for Skewness {
fn default() -> Skewness {
Skewness::new()
}
}
impl Estimate for Skewness {
#[inline]
fn add(&mut self, x: f64) {
let delta = x - self.avg.avg.avg;
self.increment();
let n = self.len().to_f64().unwrap();
self.add_inner(delta, delta/n);
}
#[inline]
fn estimate(&self) -> f64 {
self.skewness()
}
}
impl Merge for Skewness {
#[inline]
fn merge(&mut self, other: &Skewness) {
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();
let delta_n = delta / len_total;
self.sum_3 += other.sum_3
+ delta*delta_n*delta_n * len_self*len_other*(len_self - len_other)
+ 3.*delta_n * (len_self * other.avg.sum_2 - len_other * self.avg.sum_2);
self.avg.merge(&other.avg);
}
}
impl_from_iterator!(Skewness);
impl_from_par_iterator!(Skewness);
impl_extend!(Skewness);