6

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]}& @@ 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

Community
  • 1
  • 1
dreeves
  • 26,430
  • 45
  • 154
  • 229
  • I understand almost nothing about the problem, but it seems (from http://en.wikipedia.org/wiki/Exponential_smoothing ) that you may need a trend estimate. http://reference.wolfram.com/applications/timeseries/UsersGuideToTimeSeries/PreparingDataForModeling/1.4.3.html – DavidC Apr 04 '11 at 01:07
  • please tell me if Sasha's code give the correct output – Mr.Wizard Apr 04 '11 at 04:28
  • @Mr.Wizard: It looks right to me when trying it on some data I have. (Unfortunately that also convinced me that this is not actually what I want! But that's my own problem. Hopefully this will be useful for people searching for DEMA in Mathematica in the future!) – dreeves Apr 04 '11 at 06:18
  • I used it a few times for financial (market) time series analysis. What are you using it for? – Dr. belisarius Apr 04 '11 at 11:57
  • @belisarius: I was trying to improve on The Hacker's Diet ( http://fourmilab.ch/hackdiet ). Eg, http://beeminder.com/d/mass – dreeves Apr 11 '11 at 23:14

2 Answers2

3

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)))}
Sasha
  • 5,935
  • 1
  • 25
  • 33
  • Thanks Sasha! I believe this is correct. Note that this isn't quite to spec since data is meant to be a time series with {x,y} pairs. But that's fine; this one parallels the built-in ExponentialMovingAverage. – dreeves Apr 04 '11 at 06:15
1

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]]
Mr.Wizard
  • 24,179
  • 5
  • 44
  • 125