-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathEWMean.jl
84 lines (67 loc) · 2.15 KB
/
EWMean.jl
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
"""
Calculates the expontentially weighted moving average (EWMA) with bias correction.
The parameter `alpha` is the weight of the new value, and should be in the range [0, 1].
A higher alpha value discounts older observations faster,
hence the model is more reactive to recent changes.
# Formulas
## Corrected
`` S_t = [ (1 - alpha) * S_{t-1} + alpha * X_t ] / (1 - (1-alpha)^t) ``
## Uncorrected
`` S_0 = X_0 ``
`` S_t = (1 - alpha) * S_{t-1} + alpha * X_t ``
# Arguments
- `alpha::Out`: The weight of the new value, should be in the range [0, 1]. A new value has a weight of `alpha`, and the previous value has a weight of `1 - alpha`.
- `corrected::Bool=true`: Whether to adjust the initial value to account for the bias in the first few observations.
# References
Incremental calculation of weighted mean and variance, Tony Finch, Feb 2009
https://blog.fugue88.ws/archives/2017-01/The-correct-way-to-start-an-Exponential-Moving-Average-EMA
"""
mutable struct EWMean{In<:Number,Out<:Number,corrected} <: StreamOperation
const alpha::Out
const c::Out # 1 - alpha
const corrected::Bool # bias correction
M::Out
ci::Out
n::Int
EWMean{In,Out}(
;
alpha::Out,
corrected=true
) where {In<:Number,Out<:Number} =
new{In,Out,corrected}(
alpha,
one(Out) - alpha, # c
corrected,
zero(Out), # M
corrected ? one(Out) : zero(Out), # ci
0 # n
)
end
# uncorrected mean
@inline function (op::EWMean{In,Out,false})(executor, value::In) where {In,Out}
if op.n == 0
op.M = value
else
op.M = op.c * op.M + op.alpha * value
end
op.n += 1
nothing
end
# bias corrected mean
@inline function (op::EWMean{In,Out,true})(executor, value::In) where {In,Out}
op.M = op.c * op.M + op.alpha * value
op.n += 1
op.ci *= op.c
nothing
end
@inline function is_valid(op::EWMean)
op.n > 0
end
# uncorrected mean
@inline function get_state(op::EWMean{In,Out,false})::Out where {In,Out}
op.M
end
# bias corrected mean
@inline function get_state(op::EWMean{In,Out,true})::Out where {In,Out}
op.M / (one(Out) - op.ci)
end