Skip to main content

r2rs_stats/regression/glm/
model.rs

1// "Whatever you do, work at it with all your heart, as working for the Lord,
2// not for human masters, since you know that you will receive an inheritance
3// from the Lord as a reward. It is the Lord Christ you are serving."
4// (Col 3:23-24)
5
6use std::error::Error;
7
8use nalgebra::DMatrix;
9use num_traits::real::Real;
10use strafe_trait::{
11    Manipulator, Model, Statistic, StatisticalEstimate, StatisticalEstimator, StatisticalTest,
12};
13use strafe_type::ModelMatrix;
14
15use crate::{
16    funcs::residual_sum_of_squares,
17    regression::glm::{family::core::Family, link::core::Link, GeneralizedLinearRegression},
18    tests::{LenientAdjustedRSquaredTest, LinearEstimator, ZCoefficientBuilder},
19};
20
21impl<L: Link, F: Family<L>> Model for GeneralizedLinearRegression<L, F> {
22    fn get_x(&self) -> ModelMatrix {
23        self.x.clone()
24    }
25
26    fn get_x1(&self) -> ModelMatrix {
27        self.x1.clone()
28    }
29
30    fn get_y(&self) -> ModelMatrix {
31        self.y.clone()
32    }
33
34    fn get_weights(&self) -> ModelMatrix {
35        ModelMatrix::from(&self.final_weights)
36    }
37
38    fn get_intercept(&self) -> bool {
39        true
40    }
41
42    fn manipulator(
43        &self,
44    ) -> Result<
45        Box<dyn StatisticalEstimate<Manipulator<ModelMatrix, ModelMatrix>, ModelMatrix>>,
46        Box<dyn Error>,
47    > {
48        Ok(Box::new(
49            LinearEstimator::new()
50                .with_alpha(self.alpha)
51                .estimate(&self.model_data)?,
52        ))
53    }
54
55    fn determination(&self) -> Result<Box<dyn Statistic>, Box<dyn Error>> {
56        Ok(Box::new(
57            LenientAdjustedRSquaredTest::new()
58                .with_alpha(self.alpha)
59                .test(&self.model_data)?,
60        ))
61    }
62
63    fn parameters(
64        &self,
65    ) -> Result<Vec<Box<dyn StatisticalEstimate<f64, (f64, f64)>>>, Box<dyn Error>> {
66        Ok(ZCoefficientBuilder::new()
67            .with_alpha(self.alpha)
68            .estimate(&self.model_data)?
69            .into_iter()
70            .map(|c| {
71                let x: Box<dyn StatisticalEstimate<f64, (f64, f64)>> = Box::new(c);
72                x
73            })
74            .collect())
75    }
76
77    fn predictions(
78        &self,
79    ) -> Result<Box<dyn StatisticalEstimate<ModelMatrix, ModelMatrix>>, Box<dyn Error>> {
80        let mut linear_prediction = LinearEstimator::new()
81            .with_alpha(self.alpha)
82            .estimate(&self.model_data)?;
83
84        let mut linear_prediction_ret = linear_prediction.clone();
85        let linear_prediction_estimate: ModelMatrix = linear_prediction.estimate();
86
87        linear_prediction_ret.predictions_estimate = ModelMatrix::from(
88            self.family
89                .link()
90                .link_inverse(&linear_prediction_estimate.matrix()),
91        );
92        let lin_pred = linear_prediction_ret
93            .predictions_confidence_interval
94            .matrix();
95        let lin_pred_lower = self
96            .family
97            .link()
98            .link_inverse(&ModelMatrix::from(lin_pred.column(0).as_slice()).matrix());
99        let lin_pred_upper = self
100            .family
101            .link()
102            .link_inverse(&ModelMatrix::from(lin_pred.column(1).as_slice()).matrix());
103        linear_prediction_ret.predictions_confidence_interval =
104            ModelMatrix::from(DMatrix::<f64>::from_iterator(
105                lin_pred.nrows(),
106                2,
107                lin_pred_lower
108                    .into_iter()
109                    .chain(lin_pred_upper.into_iter())
110                    .cloned(),
111            ));
112
113        Ok(Box::new(linear_prediction_ret))
114    }
115
116    fn residuals(&self) -> Result<ModelMatrix, Box<dyn Error>> {
117        let pred = self.predictions()?.estimate();
118
119        Ok(ModelMatrix::from(
120            (self.y.matrix() - pred.matrix()).component_div(&self.family.link().mu_eta(&self.eta)),
121        ))
122    }
123
124    fn studentized_residuals(&self) -> Result<ModelMatrix, Box<dyn Error>> {
125        let x = self.x1.matrix();
126        let y = self.y.matrix();
127        let b = self.b.clone();
128        let r = self.residuals_deviance()?.matrix();
129        let pear_res = self.residuals_pearson()?.matrix();
130        let sum = residual_sum_of_squares(&x, &y, &b);
131        let denom = x.nrows() as f64 - x.ncols() as f64;
132        let hat = self.leverage();
133        let sigma = self
134            .residuals()?
135            .matrix()
136            .into_iter()
137            .zip(hat.iter())
138            .map(|(&res, &hat)| {
139                if hat < 1.0 {
140                    ((sum - res.powi(2) / (1.0 - hat)) / denom).sqrt()
141                } else {
142                    (sum / denom).sqrt()
143                }
144            })
145            .collect::<Vec<_>>();
146
147        Ok(ModelMatrix::from(
148            r.into_iter()
149                .zip(pear_res.into_iter())
150                .zip(hat.into_iter())
151                .zip(sigma.into_iter())
152                .map(|(((r, pear_res), hat), sigma)| {
153                    let mut ret =
154                        r.signum() * (r.powi(2) + (hat * pear_res.powi(2)) / (1.0 - hat)).sqrt();
155                    if self.family.set_dispersion().is_none() {
156                        ret /= sigma;
157                    }
158                    ret
159                })
160                .collect::<Vec<_>>(),
161        ))
162    }
163
164    fn standardized_residuals(&self) -> Result<ModelMatrix, Box<dyn Error>> {
165        let res = self.residuals_deviance()?.matrix();
166        let disp = self.dispersion();
167        let hat = self.leverage();
168        Ok(ModelMatrix::from(
169            res.into_iter()
170                .zip(hat.into_iter())
171                .map(|(res, hat)| res / (disp * (1.0 - hat)).sqrt())
172                .collect::<Vec<_>>(),
173        ))
174    }
175
176    fn variance(&self) -> Result<DMatrix<f64>, Box<dyn Error>> {
177        let mut w = self.final_weights.clone();
178        w.iter_mut().for_each(|w_i| *w_i = w_i.sqrt());
179
180        let mut weighted_x = self.x1.matrix();
181        weighted_x
182            .column_iter_mut()
183            .for_each(|mut row| row.component_mul_assign(&w));
184
185        let cov_unscaled = (weighted_x.clone().transpose() * weighted_x.clone())
186            .pseudo_inverse(f64::epsilon())
187            .unwrap();
188
189        Ok(self.dispersion() * cov_unscaled)
190    }
191}
192
193impl<L: Link, F: Family<L>> GeneralizedLinearRegression<L, F> {
194    pub fn dispersion(&self) -> f64 {
195        if let Some(disp) = self.family.set_dispersion() {
196            disp
197        } else {
198            let df_residual = self.x1.matrix().nrows() - self.b.len();
199            let resid = self.residuals().unwrap().matrix();
200            self.final_weights
201                .iter()
202                .zip(resid.into_iter())
203                .map(|(w_i, r_i)| w_i * r_i.powi(2))
204                .sum::<f64>()
205                / df_residual as f64
206        }
207    }
208
209    pub fn residuals_pearson(&self) -> Result<ModelMatrix, Box<dyn Error>> {
210        let r = self
211            .y
212            .matrix()
213            .iter()
214            .zip(self.mu.iter())
215            .map(|(y, mu)| y - mu)
216            .collect::<Vec<_>>();
217        let wts = self.w.matrix();
218        let var = self.family.variance(&self.mu);
219        Ok(ModelMatrix::from(
220            r.into_iter()
221                .zip(wts.into_iter())
222                .zip(var.into_iter())
223                .map(|((r, w), v)| r * w.sqrt() / v.sqrt())
224                .collect::<Vec<_>>(),
225        ))
226    }
227
228    pub fn residuals_deviance(&self) -> Result<ModelMatrix, Box<dyn Error>> {
229        let y = self.y.matrix();
230        let wts = self.w.matrix();
231        let mu = self.mu.clone();
232        let dev_res = self.family.residual_deviance(&y, &mu, &wts);
233        let ret = dev_res
234            .into_iter()
235            .zip(y.into_iter())
236            .zip(mu.into_iter())
237            .map(|((dev_res, y), mu)| {
238                let d_res = dev_res.max(0.0).sqrt();
239                if y > mu {
240                    d_res
241                } else {
242                    -d_res
243                }
244            })
245            .collect::<Vec<_>>();
246
247        Ok(ModelMatrix::from(ret))
248    }
249}