Skip to main content

r2rs_stats/tests/
residuals.rs

1use nalgebra::DMatrix;
2use strafe_trait::{
3    Assumption, Concept, Conclusion, Normal, NormalResiduals, NotNormalResiduals, RejectionStatus,
4    Statistic, StatisticalTest,
5};
6use strafe_type::{Alpha64, ModelMatrix};
7
8use crate::{
9    funcs::residuals,
10    tests::swilk::{ShapiroWilkStatistic, ShapiroWilkTest},
11};
12
13#[derive(Copy, Clone, Debug)]
14pub struct NormalResidualTest {
15    alpha: Alpha64,
16}
17
18impl StatisticalTest for NormalResidualTest {
19    type Input = (ModelMatrix, DMatrix<f64>, DMatrix<f64>, DMatrix<f64>);
20    type Output = Result<NormalResidualStatistic, Box<dyn std::error::Error>>;
21
22    fn assumptions() -> Vec<Box<dyn Assumption>> {
23        ShapiroWilkTest::assumptions()
24    }
25
26    fn null_hypotheses() -> Vec<Box<dyn Conclusion>> {
27        vec![Box::new(NormalResiduals::new())]
28    }
29
30    fn alternate_hypotheses() -> Vec<Box<dyn Conclusion>> {
31        vec![Box::new(NotNormalResiduals::new())]
32    }
33
34    fn test(&mut self, (x, y, model, w): &Self::Input) -> Self::Output {
35        let x = x.matrix();
36        let mut weighted_x = x.clone();
37        weighted_x
38            .column_iter_mut()
39            .for_each(|mut row| row.component_mul_assign(w));
40        let weighted_y = y.component_mul(w);
41
42        let shapiro_wilk_statistic = ShapiroWilkTest::new().with_alpha(self.alpha).test(
43            &residuals(&weighted_y, &weighted_x, model)
44                .as_slice()
45                .to_vec(),
46        )?;
47        Ok(NormalResidualStatistic {
48            shapiro_wilk_statistic,
49        })
50    }
51}
52
53#[derive(Copy, Clone, Debug)]
54pub struct NormalResidualStatistic {
55    shapiro_wilk_statistic: ShapiroWilkStatistic,
56}
57
58impl Statistic for NormalResidualStatistic {
59    fn alpha(&self) -> Alpha64 {
60        self.shapiro_wilk_statistic.alpha
61    }
62
63    fn statistic(&self) -> f64 {
64        self.shapiro_wilk_statistic.w
65    }
66
67    fn probability_value(&self) -> f64 {
68        self.shapiro_wilk_statistic.p
69    }
70
71    fn conclusion(&self) -> RejectionStatus {
72        let shapiro_wilk_conclusion = self.shapiro_wilk_statistic.conclusion();
73        if shapiro_wilk_conclusion.unwrap().is::<Normal>() {
74            RejectionStatus::RejectInFavorOf(Box::new(NormalResiduals {}))
75        } else {
76            RejectionStatus::FailToReject(Box::new(NotNormalResiduals {}))
77        }
78    }
79}
80
81impl Default for NormalResidualTest {
82    fn default() -> Self {
83        Self { alpha: 0.05.into() }
84    }
85}
86
87impl NormalResidualTest {
88    pub fn new() -> Self {
89        Self::default()
90    }
91
92    pub fn with_alpha<A: Into<Alpha64>>(self, alpha: A) -> Self {
93        Self {
94            alpha: alpha.into(),
95        }
96    }
97}