[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