-
Notifications
You must be signed in to change notification settings - Fork 7
/
reservoir.go
76 lines (56 loc) · 1.04 KB
/
reservoir.go
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
package onlinestats
import (
"math"
"math/rand"
)
type Reservoir struct {
data []float64
n int
sum float64
}
func NewReservoir(capacity int) *Reservoir {
return &Reservoir{
data: make([]float64, 0, capacity),
}
}
func (r *Reservoir) Push(n float64) {
index := r.n
r.n++
// not enough samples yet -- add it
if index < cap(r.data) {
r.data = append(r.data, n)
return
}
ridx := rand.Intn(r.n) // == index+1, so we're 0..index inclusive
if ridx >= len(r.data) {
// ignore this one
return
}
// add to our sample
old := r.data[ridx]
r.data[ridx] = n
r.sum -= old
r.sum += n
}
func (r *Reservoir) Len() int {
return len(r.data)
}
func (r *Reservoir) Mean() float64 {
return r.sum / float64(r.Len())
}
func (r *Reservoir) Var() float64 {
n := float64(r.Len())
mean := r.Mean()
l := r.Len()
sum1 := 0.0
sum2 := 0.0
for i := 0; i < l; i++ {
xm := r.data[i] - mean
sum1 += xm * xm
sum2 += xm
}
return (sum1 - (sum2*sum2)/n) / (n - 1)
}
func (r *Reservoir) Stddev() float64 {
return math.Sqrt(r.Var())
}