r2rs_stats/regression/glm/
model.rs1use 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}