1 //! Regression analysis 2 3 use crate::stats::bivariate::Data; 4 use crate::stats::float::Float; 5 6 /// A straight line that passes through the origin `y = m * x` 7 #[derive(Clone, Copy)] 8 pub struct Slope<A>(pub A) 9 where 10 A: Float; 11 12 impl<A> Slope<A> 13 where 14 A: Float, 15 { 16 /// Fits the data to a straight line that passes through the origin using ordinary least 17 /// squares 18 /// 19 /// - Time: `O(length)` fit(data: &Data<'_, A, A>) -> Slope<A>20 pub fn fit(data: &Data<'_, A, A>) -> Slope<A> { 21 let xs = data.0; 22 let ys = data.1; 23 24 let xy = crate::stats::dot(xs, ys); 25 let x2 = crate::stats::dot(xs, xs); 26 27 Slope(xy / x2) 28 } 29 30 /// Computes the goodness of fit (coefficient of determination) for this data set 31 /// 32 /// - Time: `O(length)` r_squared(&self, data: &Data<'_, A, A>) -> A33 pub fn r_squared(&self, data: &Data<'_, A, A>) -> A { 34 let _0 = A::cast(0); 35 let _1 = A::cast(1); 36 let m = self.0; 37 let xs = data.0; 38 let ys = data.1; 39 40 let n = A::cast(xs.len()); 41 let y_bar = crate::stats::sum(ys) / n; 42 43 let mut ss_res = _0; 44 let mut ss_tot = _0; 45 46 for (&x, &y) in data.iter() { 47 ss_res = ss_res + (y - m * x).powi(2); 48 ss_tot = ss_res + (y - y_bar).powi(2); 49 } 50 51 _1 - ss_res / ss_tot 52 } 53 } 54