]> git.proxmox.com Git - proxmox-backup.git/blob - src/tools/statistics.rs
remove wrong calls to systemd_notify
[proxmox-backup.git] / src / tools / statistics.rs
1 //! Helpers for common statistics tasks
2 use num_traits::NumAssignRef;
3 use num_traits::cast::ToPrimitive;
4
5 /// Calculates the sum of a list of numbers
6 /// ```
7 /// # use proxmox_backup::tools::statistics::sum;
8 /// # use num_traits::cast::ToPrimitive;
9 ///
10 /// assert_eq!(sum(&[0,1,2,3,4,5]), 15);
11 /// assert_eq!(sum(&[-1,1,-2,2]), 0);
12 /// assert!((sum(&[0.0, 0.1,0.2]).to_f64().unwrap() - 0.3).abs() < 0.001);
13 /// assert!((sum(&[0.0, -0.1,0.2]).to_f64().unwrap() - 0.1).abs() < 0.001);
14 /// ```
15 pub fn sum<T>(list: &[T]) -> T
16 where
17 T: NumAssignRef + ToPrimitive
18 {
19 let mut sum = T::zero();
20 for num in list {
21 sum += num;
22 }
23 sum
24 }
25
26 /// Calculates the mean of a variable x
27 /// ```
28 /// # use proxmox_backup::tools::statistics::mean;
29 ///
30 /// assert!((mean(&[0,1,2,3,4,5]).unwrap() - 2.5).abs() < 0.001);
31 /// assert_eq!(mean::<u64>(&[]), None)
32 /// ```
33 pub fn mean<T>(list: &[T]) -> Option<f64>
34 where
35 T: NumAssignRef + ToPrimitive
36 {
37 let len = list.len();
38 if len == 0 {
39 return None
40 }
41 Some(sum(list).to_f64()?/(list.len() as f64))
42 }
43
44 /// Calculates the variance of a variable x
45 /// ```
46 /// # use proxmox_backup::tools::statistics::variance;
47 ///
48 /// assert!((variance(&[1,2,3,4]).unwrap() - 1.25).abs() < 0.001);
49 /// assert_eq!(variance::<u64>(&[]), None)
50 /// ```
51 pub fn variance<T>(list: &[T]) -> Option<f64>
52 where
53 T: NumAssignRef + ToPrimitive
54 {
55 covariance(list, list)
56 }
57
58 /// Calculates the (non-corrected) covariance of two variables x,y
59 pub fn covariance<X, Y> (x: &[X], y: &[Y]) -> Option<f64>
60 where
61 X: NumAssignRef + ToPrimitive,
62 Y: NumAssignRef + ToPrimitive,
63 {
64 let len_x = x.len();
65 let len_y = y.len();
66 if len_x == 0 || len_y == 0 || len_x != len_y {
67 return None
68 }
69
70 let mean_x = mean(x)?;
71 let mean_y = mean(y)?;
72
73 let covariance: f64 = (0..len_x).map(|i| {
74 let x = x[i].to_f64().unwrap_or(0.0);
75 let y = y[i].to_f64().unwrap_or(0.0);
76 (x - mean_x)*(y - mean_y)
77 }).sum();
78
79 Some(covariance/(len_x as f64))
80 }
81
82 /// Returns the factors `(a,b)` of a linear regression `y = a + bx`
83 /// for the variables `[x,y]` or `None` if the lists are not the same length
84 /// ```
85 /// # use proxmox_backup::tools::statistics::linear_regression;
86 ///
87 /// let x = &[0,1,2,3,4];
88 /// let y = &[-4,-2,0,2,4];
89 /// let (a,b) = linear_regression(x,y).unwrap();
90 /// assert!((a - -4.0).abs() < 0.001);
91 /// assert!((b - 2.0).abs() < 0.001);
92 /// ```
93 pub fn linear_regression<X, Y> (x: &[X], y: &[Y]) -> Option<(f64, f64)>
94 where
95 X: NumAssignRef + ToPrimitive,
96 Y: NumAssignRef + ToPrimitive
97 {
98 let len_x = x.len();
99 let len_y = y.len();
100 if len_x == 0 || len_y == 0 || len_x != len_y {
101 return None
102 }
103
104 let mean_x = mean(x)?;
105 let mean_y = mean(y)?;
106
107 let mut covariance = 0.0;
108 let mut variance = 0.0;
109
110 for i in 0..len_x {
111 let x = x[i].to_f64()?;
112 let y = y[i].to_f64()?;
113
114 let x_mean_x = x - mean_x;
115
116 covariance += x_mean_x*(y - mean_y);
117 variance += x_mean_x * x_mean_x;
118 }
119
120 let beta = covariance/variance;
121 let alpha = mean_y - beta*mean_x;
122 Some((alpha,beta))
123 }