1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
use std::{
marker::PhantomData,
ops::{AddAssign, Div, Mul},
};
use num_traits::{Float, NumOps, One, Signed};
use crate::FillWithWeighted;
#[derive(Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
pub struct WeightedMean<T = f64, W = f64, O = f64, C = u32> {
sumwt: T,
sumwt2: T,
sumw: W,
sumw2: W,
count: C,
phantom_output_type: PhantomData<O>,
}
impl<T, W, O, C> WeightedMean<T, W, O, C>
where
T: Copy,
W: Copy,
O: From<T> + From<W> + From<C> + NumOps + Signed + Copy,
C: Copy,
{
pub fn new<I>(values: I) -> Self
where
I: IntoIterator<Item = (T, W)>,
Self: FillWithWeighted<T, W> + Default,
{
let mut r = Self::default();
values
.into_iter()
.for_each(|it| r.fill_with_weighted(it.0, it.1));
r
}
pub fn get(&self) -> O {
self.mean()
}
pub fn mean(&self) -> <O as Div>::Output {
O::from(self.sumwt) / O::from(self.sumw)
}
pub fn num_samples(&self) -> C {
self.count
}
pub fn variance_of_samples(&self) -> O {
let mu = self.mean();
let mu2 = mu * mu;
mu2 + (O::from(self.sumwt2) - (O::one() + O::one()) * O::from(self.sumwt) * mu)
/ O::from(self.sumw)
}
pub fn standard_deviation_of_samples(&self) -> O
where
O: Float,
{
self.variance_of_samples().sqrt()
}
pub fn variance_of_mean(&self) -> O {
self.variance_of_samples() * O::from(self.sumw2) / (O::from(self.sumw) * O::from(self.sumw))
}
pub fn standard_error_of_mean(&self) -> O
where
O: Float,
{
self.variance_of_mean().sqrt()
}
}
impl<T, W, O, C> FillWithWeighted<T, W> for WeightedMean<T, W, O, C>
where
T: Copy + AddAssign + Mul<W, Output = T> + Mul<T, Output = T>,
W: Copy + AddAssign + Mul<W, Output = W>,
C: AddAssign + One,
{
fn fill_with_weighted(&mut self, value: T, weight: W) {
self.sumwt += value * weight;
self.sumwt2 += value * value * weight;
self.sumw += weight;
self.sumw2 += weight * weight;
self.count += C::one();
}
}