iterstats/
lib.rs

1#![doc=include_str!("../README.md")]
2#![deny(warnings, missing_docs, unsafe_code)]
3
4pub mod argsort;
5pub mod fill_nan;
6pub mod mean;
7pub mod median;
8pub mod normalize;
9pub mod range;
10pub mod rank;
11pub mod stddev;
12pub mod sum_of_squares;
13pub mod variance;
14mod welford_online;
15pub mod zscore;
16
17use argsort::{ArgSort, ArgSortIter};
18pub use fill_nan::FillNan;
19use fill_nan::FillNanIter;
20pub use mean::Mean;
21pub use median::Median;
22pub use normalize::Normalize;
23use normalize::NormalizeIter;
24use range::Range;
25use rank::{Rank, RankIter};
26pub use stddev::StdDev;
27pub use sum_of_squares::SumOfSquares;
28pub use variance::Variance;
29pub use zscore::ZScore;
30use zscore::ZScoreIter;
31
32/// This trait allows you to call all the [`iterstats`](crate) calculations as iterator methods.
33///
34/// # Example
35///
36/// ```rust
37/// use iterstats::Iterstats;
38///
39/// let data = [1f32, 2., 3., 4.];
40/// let mean = data.iter().mean();
41/// assert_eq!(mean, 2.5);
42/// let variance = data.iter().variance();
43/// assert_eq!(variance, 1.25);
44/// let stddev = data.iter().stddev();
45/// assert_eq!(stddev, 1.25f32.sqrt());
46/// let zscores = data.iter().zscore().collect::<Vec<_>>();
47/// assert_eq!(zscores, vec![-1.3416407, -0.4472136, 0.4472136, 1.3416407]);
48/// ```
49pub trait Iterstats<A>: Iterator {
50    /// Calculate the mean of the collection.
51    fn mean(self) -> <A as Mean>::Output
52    where
53        Self: Sized + Iterator<Item = A> + Clone,
54        A: Mean,
55    {
56        A::mean(self)
57    }
58
59    /// Calculate the variance of the collection.
60    fn variance(self) -> <A as Variance>::Output
61    where
62        Self: Sized + Iterator<Item = A>,
63        A: Variance,
64    {
65        A::variance(self)
66    }
67
68    /// Calculate the population standard deviation of the collection.
69    fn stddev(self) -> <A as StdDev>::Output
70    where
71        Self: Sized + Iterator<Item = A>,
72        A: StdDev,
73    {
74        A::stddev(self)
75    }
76
77    /// Calculate the Z-score of each item of the collection.
78    fn zscore(self) -> ZScoreIter<<A as ZScore>::Output>
79    where
80        Self: Sized + Iterator<Item = A> + Clone,
81        A: ZScore,
82    {
83        A::zscore(self)
84    }
85
86    /// Normalize each item of the collection to a specified range.
87    ///
88    /// ```rust
89    /// use iterstats::Iterstats;
90    ///
91    /// let data = [-1.0f64, -2., 3., 8.];
92    /// let norm = data.iter().normalize(0., 100.).collect::<Vec<_>>();
93    /// assert_eq!(vec![10., 0., 50., 100.], norm);
94    /// ```
95    fn normalize(
96        self,
97        min: <A as Normalize>::Output,
98        max: <A as Normalize>::Output,
99    ) -> NormalizeIter<<A as Normalize>::Output>
100    where
101        Self: Sized + Iterator<Item = A> + Clone,
102        A: Normalize,
103    {
104        A::normalize(self, min, max)
105    }
106
107    /// Calculate the total sum of squares of the collection.
108    fn sum_of_squares(self) -> <A as SumOfSquares>::Output
109    where
110        Self: Sized + Iterator<Item = A>,
111        A: SumOfSquares,
112    {
113        A::sum_of_squares(self)
114    }
115
116    /// Calculate the median of the collection.
117    ///
118    /// For integer types this may be inexact if there are an even number of elements and the true
119    /// median is a non-integer number.
120    fn median(self) -> <A as Median>::Output
121    where
122        Self: Sized + Iterator<Item = A>,
123        A: Median,
124    {
125        A::median(self)
126    }
127
128    /// Calculate the range of the collection.
129    ///
130    /// This gets the minimum & maximum in 1 pass. Returned is a tuple of `Some((min, max))`,
131    /// unless the iterator is empty, in which case `None` is returned.
132    fn range(self) -> Option<(<A as Range>::Output, <A as Range>::Output)>
133    where
134        Self: Sized + Iterator<Item = A>,
135        A: Range,
136    {
137        A::range(self)
138    }
139
140    /// Replace NANs with another value.
141    fn fill_nan(
142        self,
143        repl: <A as FillNan>::Output,
144    ) -> FillNanIter<impl Iterator<Item = <A as FillNan>::Output>, <A as FillNan>::Output>
145    where
146        Self: Sized + Iterator<Item = A>,
147        A: FillNan,
148    {
149        A::fill_nan(self, repl)
150    }
151
152    /// Get the indexes that would produce a sorted iterator.
153    fn argsort(self) -> ArgSortIter<<A as ArgSort>::Output>
154    where
155        Self: Sized + Iterator<Item = A>,
156        A: ArgSort,
157    {
158        A::argsort(self)
159    }
160
161    /// Get the rank order of each element in an iterator.
162    fn rank(self) -> RankIter
163    where
164        Self: Sized + Iterator<Item = A>,
165        A: Rank,
166    {
167        A::rank(self)
168    }
169}
170
171impl<I, A> Iterstats<A> for I where I: Iterator + ?Sized {}
172
173#[cfg(test)]
174mod tests {
175    use super::*;
176
177    #[test]
178    fn mean() {
179        let data = [1., 2., 3., 4.];
180        let exp = 2.5;
181        assert_eq!(data.iter().mean(), exp);
182        assert_eq!(data.into_iter().mean(), exp);
183    }
184
185    #[test]
186    fn variance() {
187        let data = [1., 2., 3., 4.];
188        let exp = 1.25;
189        assert_eq!(data.iter().variance(), exp);
190        assert_eq!(data.into_iter().variance(), exp);
191    }
192
193    #[test]
194    fn stddev() {
195        let data = [1., 2., 3., 4.];
196        let exp = 1.25f64.sqrt();
197        assert_eq!(data.iter().stddev(), exp);
198        assert_eq!(data.into_iter().stddev(), exp);
199    }
200
201    #[test]
202    fn zscore() {
203        let data = [1., 2., 3., 4.];
204        let exp = vec![
205            -1.3416407864998738,
206            -0.4472135954999579,
207            0.4472135954999579,
208            1.3416407864998738,
209        ];
210        assert_eq!(data.iter().zscore().collect::<Vec<_>>(), exp);
211        assert_eq!(data.into_iter().zscore().collect::<Vec<_>>(), exp);
212    }
213
214    #[test]
215    fn normalize() {
216        let data = [1., 2., 3., 5.];
217        let normmin = 0.;
218        let normmax = 1.;
219        let exp = vec![0., 0.25, 0.5, 1.];
220        assert_eq!(
221            data.iter().normalize(normmin, normmax).collect::<Vec<_>>(),
222            exp
223        );
224        assert_eq!(
225            data.into_iter()
226                .normalize(normmin, normmax)
227                .collect::<Vec<_>>(),
228            exp
229        );
230    }
231
232    #[test]
233    fn sum_of_squares() {
234        let data = [1., 2., 3., 5.];
235        let exp = 8.75;
236        assert_eq!(data.iter().sum_of_squares(), exp);
237        assert_eq!(data.into_iter().sum_of_squares(), exp);
238    }
239
240    #[test]
241    fn median() {
242        let data = [2, 7, 198, 2, 2, 7];
243        let exp = 4;
244        assert_eq!(data.iter().median(), exp);
245        assert_eq!(data.into_iter().median(), exp);
246    }
247
248    #[test]
249    fn range() {
250        let data = [2, 7, -198, 2, 7];
251        let exprange = (-198, 7);
252        assert_eq!(data.iter().range().unwrap(), exprange);
253        assert_eq!(data.into_iter().range().unwrap(), exprange);
254    }
255
256    #[test]
257    fn fillnan() {
258        let data = [1., 100., 2., f32::NAN, 3., 5.];
259        let fill = 100.;
260        let exp = vec![1., 100., 2., 100., 3., 5.];
261        assert_eq!(data.iter().fill_nan(fill).collect::<Vec<_>>(), exp);
262        assert_eq!(data.into_iter().fill_nan(fill).collect::<Vec<_>>(), exp);
263    }
264
265    #[test]
266    fn argsort() {
267        let data = [
268            f64::NAN,
269            4.2,
270            0.0,
271            f64::NEG_INFINITY,
272            -0.0,
273            f64::INFINITY,
274            -f64::NAN,
275        ];
276        let exp = vec![6, 3, 4, 2, 1, 5, 0];
277        assert_eq!(data.iter().argsort().collect::<Vec<_>>(), exp);
278        assert_eq!(data.into_iter().argsort().collect::<Vec<_>>(), exp);
279    }
280
281    #[test]
282    fn rank() {
283        let data = [
284            f64::NAN,
285            4.2,
286            0.0,
287            f64::NEG_INFINITY,
288            -0.0,
289            f64::INFINITY,
290            -f64::NAN,
291        ];
292        let exp = vec![6, 4, 3, 1, 2, 5, 0];
293        assert_eq!(data.iter().rank().collect::<Vec<_>>(), exp);
294        assert_eq!(data.into_iter().rank().collect::<Vec<_>>(), exp);
295    }
296}