Earlier today I wrote up a fold for somebody else for retrieving the last N elements of a sequence. That's the non-trivial bit:

http://lpaste.net/103997

The relevant part is:

    lastN :: Int -> Fold a (Seq a)
    lastN n = Fold step begin done
      where
        step s a = (if (S.length s < n) then s else S.drop 1 s) |> a
        begin = S.empty
        done  = id

Once you have that, it's as simple as applying a non-streaming average to that:

    fmap (\xs -> sum xs / genericLength xs) (lastN n)

There's no point using a streaming average for this final step since for a moving window average you have to use O(N) space no matter what approach you use. This is why I prefer exponentially-weighted moving averages. Like Tony mentioned, they are much easier to write and they run in O(1) space.

On 05/11/2014 06:42 PM, Tony Day wrote:
*Spoiler Alert* if you want to have a stab at the fold yourself.

I've been meaning to code this up for a while ...

    import           Control.Applicative
    import           Control.Foldl as L
    import           Data.Sequence (ViewR(EmptyR, (:>)), (<|))
    import qualified Data.Sequence as Seq

    maybeSum :: Fold (Maybe Double) (Maybe Double)
    maybeSum = Fold (liftA2 (+)) (Just 0) id

    sma :: Int -> Fold Double Double
    sma n = L.Fold step begin done
      where
        begin = Seq.replicate n Nothing
        av x = liftA2 (/) (L.fold maybeSum x) (pure (fromIntegral n))
        done x = case av x of
            Nothing -> 0/0
            Just x' -> x'
        step x a = Just a <| pop x
        pop x = case Seq.viewr x of
            EmptyR   -> x
            x'' :> _ -> x''

    λ> L.scan (sma 3) [1..10]
    [NaN,NaN,NaN,2.0,3.0,4.0,5.0,6.0,7.0,8.0,9.0]

or

    λ> runEffect $ each [1..5] >-> L.purely P.scan (sma 2) >-> P.print
    NaN
    NaN
    1.5
    2.5
    3.5
    4.5

I would rate this as hard, especially in comparison to the exponentially-weighted version. Is this category theory suggesting that a sliding window is the wrong way to go about moving averages, contrary to intuition?




On Thursday, March 6, 2014 2:01:23 AM UTC+10, Alex Rozenshteyn wrote:

    I feel like I must be missing something rather basic, but I have
    been trying to figure out how to use pipes to compute a moving
    average of a stream of numbers. I've written code to do the EWMA,
    but I can't figure out how to do the sliding window. It doesn't
    help that I'm a bit of a pipes beginner.

    Advice is welcome and appreciated.

    Thank you.

--
You received this message because you are subscribed to the Google Groups "Haskell Pipes" group. To unsubscribe from this group and stop receiving emails from it, send an email to [email protected] <mailto:[email protected]>. To post to this group, send email to [email protected] <mailto:[email protected]>.

--
You received this message because you are subscribed to the Google Groups "Haskell 
Pipes" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To post to this group, send email to [email protected].

Reply via email to