statrs/statistics/
iter_statistics.rs1use crate::statistics::*;
2use std::borrow::Borrow;
3use std::f64;
4
5impl<T> Statistics<f64> for T
6where
7 T: IntoIterator,
8 T::Item: Borrow<f64>,
9{
10 fn min(self) -> f64 {
11 let mut iter = self.into_iter();
12 match iter.next() {
13 None => f64::NAN,
14 Some(x) => iter.map(|x| *x.borrow()).fold(*x.borrow(), |acc, x| {
15 if x < acc || x.is_nan() {
16 x
17 } else {
18 acc
19 }
20 }),
21 }
22 }
23
24 fn max(self) -> f64 {
25 let mut iter = self.into_iter();
26 match iter.next() {
27 None => f64::NAN,
28 Some(x) => iter.map(|x| *x.borrow()).fold(*x.borrow(), |acc, x| {
29 if x > acc || x.is_nan() {
30 x
31 } else {
32 acc
33 }
34 }),
35 }
36 }
37
38 fn abs_min(self) -> f64 {
39 let mut iter = self.into_iter();
40 match iter.next() {
41 None => f64::NAN,
42 Some(init) => iter
43 .map(|x| x.borrow().abs())
44 .fold(init.borrow().abs(), |acc, x| {
45 if x < acc || x.is_nan() {
46 x
47 } else {
48 acc
49 }
50 }),
51 }
52 }
53
54 fn abs_max(self) -> f64 {
55 let mut iter = self.into_iter();
56 match iter.next() {
57 None => f64::NAN,
58 Some(init) => iter
59 .map(|x| x.borrow().abs())
60 .fold(init.borrow().abs(), |acc, x| {
61 if x > acc || x.is_nan() {
62 x
63 } else {
64 acc
65 }
66 }),
67 }
68 }
69
70 fn mean(self) -> f64 {
71 let mut i = 0.0;
72 let mut mean = 0.0;
73 for x in self {
74 i += 1.0;
75 mean += (x.borrow() - mean) / i;
76 }
77 if i > 0.0 {
78 mean
79 } else {
80 f64::NAN
81 }
82 }
83
84 fn geometric_mean(self) -> f64 {
85 let mut i = 0.0;
86 let mut sum = 0.0;
87 for x in self {
88 i += 1.0;
89 sum += x.borrow().ln();
90 }
91 if i > 0.0 {
92 (sum / i).exp()
93 } else {
94 f64::NAN
95 }
96 }
97
98 fn harmonic_mean(self) -> f64 {
99 let mut i = 0.0;
100 let mut sum = 0.0;
101 for x in self {
102 i += 1.0;
103
104 let borrow = *x.borrow();
105 if borrow < 0f64 {
106 return f64::NAN;
107 }
108 sum += 1.0 / borrow;
109 }
110 if i > 0.0 {
111 i / sum
112 } else {
113 f64::NAN
114 }
115 }
116
117 fn variance(self) -> f64 {
118 let mut iter = self.into_iter();
119 let mut sum = match iter.next() {
120 None => f64::NAN,
121 Some(x) => *x.borrow(),
122 };
123 let mut i = 1.0;
124 let mut variance = 0.0;
125
126 for x in iter {
127 i += 1.0;
128 let borrow = *x.borrow();
129 sum += borrow;
130 let diff = i * borrow - sum;
131 variance += diff * diff / (i * (i - 1.0))
132 }
133 if i > 1.0 {
134 variance / (i - 1.0)
135 } else {
136 f64::NAN
137 }
138 }
139
140 fn std_dev(self) -> f64 {
141 self.variance().sqrt()
142 }
143
144 fn population_variance(self) -> f64 {
145 let mut iter = self.into_iter();
146 let mut sum = match iter.next() {
147 None => return f64::NAN,
148 Some(x) => *x.borrow(),
149 };
150 let mut i = 1.0;
151 let mut variance = 0.0;
152
153 for x in iter {
154 i += 1.0;
155 let borrow = *x.borrow();
156 sum += borrow;
157 let diff = i * borrow - sum;
158 variance += diff * diff / (i * (i - 1.0));
159 }
160 variance / i
161 }
162
163 fn population_std_dev(self) -> f64 {
164 self.population_variance().sqrt()
165 }
166
167 fn covariance(self, other: Self) -> f64 {
168 let mut n = 0.0;
169 let mut mean1 = 0.0;
170 let mut mean2 = 0.0;
171 let mut comoment = 0.0;
172
173 let mut iter = other.into_iter();
174 for x in self {
175 let borrow = *x.borrow();
176 let borrow2 = match iter.next() {
177 None => panic!("Iterators must have the same length"),
178 Some(x) => *x.borrow(),
179 };
180 let old_mean2 = mean2;
181 n += 1.0;
182 mean1 += (borrow - mean1) / n;
183 mean2 += (borrow2 - mean2) / n;
184 comoment += (borrow - mean1) * (borrow2 - old_mean2);
185 }
186 if iter.next().is_some() {
187 panic!("Iterators must have the same length");
188 }
189
190 if n > 1.0 {
191 comoment / (n - 1.0)
192 } else {
193 f64::NAN
194 }
195 }
196
197 fn population_covariance(self, other: Self) -> f64 {
198 let mut n = 0.0;
199 let mut mean1 = 0.0;
200 let mut mean2 = 0.0;
201 let mut comoment = 0.0;
202
203 let mut iter = other.into_iter();
204 for x in self {
205 let borrow = *x.borrow();
206 let borrow2 = match iter.next() {
207 None => panic!("Iterators must have the same length"),
208 Some(x) => *x.borrow(),
209 };
210 let old_mean2 = mean2;
211 n += 1.0;
212 mean1 += (borrow - mean1) / n;
213 mean2 += (borrow2 - mean2) / n;
214 comoment += (borrow - mean1) * (borrow2 - old_mean2);
215 }
216 if iter.next().is_some() {
217 panic!("Iterators must have the same length")
218 }
219 if n > 0.0 {
220 comoment / n
221 } else {
222 f64::NAN
223 }
224 }
225
226 fn quadratic_mean(self) -> f64 {
227 let mut i = 0.0;
228 let mut mean = 0.0;
229 for x in self {
230 let borrow = *x.borrow();
231 i += 1.0;
232 mean += (borrow * borrow - mean) / i;
233 }
234 if i > 0.0 {
235 mean.sqrt()
236 } else {
237 f64::NAN
238 }
239 }
240}
241
242#[rustfmt::skip]
243#[cfg(test)]
244mod tests {
245 use std::f64::consts;
246 use crate::statistics::Statistics;
247 use crate::generate::{InfinitePeriodic, InfiniteSinusoidal};
248
249 #[test]
250 fn test_empty_data_returns_nan() {
251 let data = [0.0; 0];
252 assert!(data.min().is_nan());
253 assert!(data.max().is_nan());
254 assert!(data.mean().is_nan());
255 assert!(data.quadratic_mean().is_nan());
256 assert!(data.variance().is_nan());
257 assert!(data.population_variance().is_nan());
258 }
259
260 #[test]
263 fn test_large_samples() {
264 let shorter = InfinitePeriodic::default(4.0, 1.0).take(4*4096).collect::<Vec<f64>>();
265 let longer = InfinitePeriodic::default(4.0, 1.0).take(4*32768).collect::<Vec<f64>>();
266 assert_almost_eq!((&shorter).mean(), 0.375, 1e-14);
267 assert_almost_eq!((&longer).mean(), 0.375, 1e-14);
268 assert_almost_eq!((&shorter).quadratic_mean(), (0.21875f64).sqrt(), 1e-14);
269 assert_almost_eq!((&longer).quadratic_mean(), (0.21875f64).sqrt(), 1e-14);
270 }
271
272 #[test]
273 fn test_quadratic_mean_of_sinusoidal() {
274 let data = InfiniteSinusoidal::default(64.0, 16.0, 2.0).take(128).collect::<Vec<f64>>();
275 assert_almost_eq!((&data).quadratic_mean(), 2.0 / consts::SQRT_2, 1e-15);
276 }
277}