use statrs::distribution::{ChiSquared, ContinuousCDF};
use crate::OlsFit;
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct JarqueBera {
pub statistic: f64,
pub p_value: f64,
pub skewness: f64,
pub kurtosis: f64,
}
pub fn jarque_bera(fit: &OlsFit) -> JarqueBera {
let e = fit.residuals();
let n = e.len() as f64;
let mean = e.sum() / n;
let m2: f64 = e.iter().map(|v| (v - mean).powi(2)).sum::<f64>() / n;
let m3: f64 = e.iter().map(|v| (v - mean).powi(3)).sum::<f64>() / n;
let m4: f64 = e.iter().map(|v| (v - mean).powi(4)).sum::<f64>() / n;
if m2 <= 0.0 {
return JarqueBera {
statistic: f64::NAN,
p_value: f64::NAN,
skewness: f64::NAN,
kurtosis: f64::NAN,
};
}
let skewness = m3 / m2.powf(1.5);
let kurtosis = m4 / (m2 * m2);
let statistic = (n / 6.0) * (skewness * skewness + (kurtosis - 3.0).powi(2) / 4.0);
let p_value = match ChiSquared::new(2.0) {
Ok(dist) if statistic.is_finite() && statistic >= 0.0 => 1.0 - dist.cdf(statistic),
_ => f64::NAN,
};
JarqueBera {
statistic,
p_value,
skewness,
kurtosis,
}
}