Implementing Double Exponential Smoothing, aka Double Exponential Moving Average (DEMA)
If I have time series data -- a list of {x,y} pairs -- and want to smooth it, I can use an Exponential Moving Average like so:
EMA[data_, alpha_:.1] :=
Transpose @ {#1, ExponentialMovingAverage[#2, alpha]}&am开发者_如何学Cp; @@ Transpose@data
How would you implement double exponential smoothing?
DEMA[data_, alpha_, gamma_] := (* unstub me! *)
If it figured out good values for alpha and gamma by itself, that would be extra nice.
Related question about how to handle the case that there are gaps in the time-series, ie, the samples are not uniformly spread out over time:
Exponential Moving Average Sampled at Varying Times
I am not sure this is the fastest code one can get, yet the following seems to do it:
DEMA[data_, alpha_, gamma_] :=
Module[{st = First[data], bt = data[[2]] - data[[1]], btnew, stnew},
Reap[
Sow[st];
Do[
stnew = alpha y + (1 - alpha) (st + bt);
btnew = gamma (stnew - st) + (1 - gamma) bt;
Sow[stnew];
st = stnew;
bt = btnew;
, {y, Rest@data}]][[-1, 1]
]]
This is almost direct from the page you referenced. You can modify the initial condition for b in the source code. Setting bt initially to zero recovers the singly exponential smoothing.
In[81]:= DEMA[{a, b, c, d}, alpha, gamma]
Out[81]= {a, (1 - alpha) b + alpha b,
alpha c + (1 - alpha) ((1 - alpha) b +
alpha b + (-a + b) (1 - gamma) + (-a + (1 - alpha) b +
alpha b) gamma),
alpha d + (1 -
alpha) (alpha c + (1 -
gamma) ((-a + b) (1 - gamma) + (-a + (1 - alpha) b +
alpha b) gamma) + (1 - alpha) ((1 - alpha) b +
alpha b + (-a + b) (1 - gamma) + (-a + (1 - alpha) b +
alpha b) gamma) +
gamma (-(1 - alpha) b - alpha b +
alpha c + (1 - alpha) ((1 - alpha) b +
alpha b + (-a + b) (1 - gamma) + (-a + (1 - alpha) b +
alpha b) gamma)))}
Here is my formulation:
DEMA[data_, alpha_, gamma_] :=
FoldList[
Module[{x, y},
x = #[[1]] + #[[2]];
y = #2 - alpha x;
{y + x, #[[2]] + gamma * y}
] &,
{data[[1]], data[[2]] - data[[1]]},
alpha * Rest@data
][[All, 1]]
精彩评论