[Haskell-cafe] Help to create a function to calculate a n element moving average ??

Henning Thielemann schlepptop at henning-thielemann.de
Wed Sep 29 16:10:07 EDT 2010


S. Doaitse Swierstra schrieb:
> Avoiding repeated additions:
> 
> movingAverage :: Int -> [Float] -> [Float]
> movingAverage n l = runSums (sum . take n $l) l (drop n l)
>      where n'     = fromIntegral n
>            runSums sum (h:hs) (t:ts) = sum / n' : runSums (sum-h+t) hs ts
>            runSums _   _     []      = []

Moving average can be interpreted as convolution (*):
[1/n,1/n,1/n,...,1/n] * xs

You may drop the first (n-1) values, since they average over initial
padding zeros.

Convolution is associative and you can decompose the first operand into
simpler parts:

1/n · [1,1,1,...] * [1,0,0,....,0,0,-1] * xs
 = 1/n · integrate ([1,0,0,....,0,0,-1] * xs)

Convolution is commutative, thus you could also write
 = 1/n · [1,0,0,....,0,0,-1] * integrate xs
 but then integration of xs will yield unbounded values and thus higher
rounding errors.

This yields:

movingAverage :: Int -> [Float] -> [Float]
movingAverage n =
   drop (n-1) .
   map (/ fromIntegral n) .
   scanl1 (+) .
   (\xs -> zipWith (-) xs (replicate n 0 ++ xs))

This should be the same as the implementation above, but maybe a bit
nicer. :-)



More information about the Haskell-Cafe mailing list