Skip to main content

numeric_statistics/f64/
variance.rs

1use super::average;
2
3/// Calculate statistical variance for values.
4///
5/// Return NaN if the values are empty.
6///
7/// Filter NaN values in the stream.
8///
9/// # Example
10///
11/// ```rust
12/// #[macro_use]
13/// use numeric_statistics::assert_eq_f64;
14/// use numeric_statistics::f64::variance::*;
15/// let values = &[1.0, 2.0, 4.0];
16/// let variance = variance(values);
17/// assert_eq_f64!(variance,  2.3333333333333333 as f64);
18/// ```
19/// 
20pub fn variance<T: AsRef<[f64]>>(values: T) -> f64 {
21    let values = values.as_ref();
22    if values.is_empty() { return f64::NAN; }
23    let average = average(values);
24    variance_with_average(values, average)
25}
26
27/// Calculate statistical variance for values, 
28/// given a pre-calculated average value.
29///
30/// Return NaN if the values are empty.
31///
32/// Filter NaN values in the stream.
33/// 
34/// # Example
35///
36/// ```rust
37/// #[macro_use]
38/// use numeric_statistics::assert_eq_f64;
39/// use numeric_statistics::f64::{average::*, variance::*};
40/// let values = &[1.0, 2.0, 4.0];
41/// let average = average(values);
42/// let variance = variance_with_average(values, average);
43/// assert_eq_f64!(variance, 2.3333333333333333 as f64);
44/// ```
45/// 
46pub fn variance_with_average<T: AsRef<[f64]>>(values: T, average: f64) -> f64 {
47    let values = values.as_ref();
48    if values.is_empty() { return f64::NAN; }
49    let mut delta_square_sum: f64 = 0.0;
50    let mut len: usize = 0;
51    values.iter().for_each(|x|
52        if !x.is_nan() {
53            let delta = *x - average;
54            delta_square_sum += delta * delta;
55            len += 1;
56        }
57    );
58    match len {
59        0 => return f64::NAN,
60        1 => return 0.0,
61        x => delta_square_sum / (x - 1) as f64
62    }
63}
64
65#[cfg(test)]
66mod test {
67    use super::*;
68    use crate::assert_eq_f64;
69
70    #[test]
71    fn test_empty() {
72        let x: &[f64] = &[];
73        assert!(variance(x).is_nan());
74    }
75
76    #[test]
77    fn test_nan() {
78        let x: &[f64] = &[f64::NAN];
79        assert!(variance(x).is_nan());
80    }
81
82    #[test]
83    fn test_value() {
84        let x: &[f64] = &[1.0];
85        assert_eq_f64!(variance(x), 0.0);
86    }
87
88    #[test]
89    fn test_values_ascending() {
90        let x = &[1.0, 2.0, 4.0];
91        assert_eq_f64!(variance(x), 2.3333333333333333);
92    }
93
94    #[test]
95    fn test_values_ascending_and_nans() {
96        let x = &[1.0, f64::NAN, 2.0, f64::NAN, 4.0];
97        assert_eq_f64!(variance(x), 2.3333333333333333);
98    }
99
100}