I did mention that it was one of eight implementations that I tried.
In fact you broke it with your change.
It is important ***NOT*** to keep a running sum but a running MEAN.
The line
    m := ((self at: i) - (self at: d)) / width + m
was written that way for a reason.

I did think of renaming the variables for general use, but decided to display
the actual code that I tested.  If you want polished code, here it is.

    runningMeans: width
      "This returns an array of running means as if the receiver
       were broken into overlapping segments 'width' long and the
       mean of each calculated.  This uses an adaptation of
       Welford's algorithm for stably updating the mean; it is
       important to maintain a current MEAN not a current SUM.
       This has been tested against 7 other algorithms.  It was
       the most accurate of the faster ones.  The result is an
       Array no matter what kind of sequence the receiver is.
       If the receiver is a tree (like a virtual concatenation)
       or a singly or doubly linked list you should convert the
       receiver to an Array first.  Note that there is no
       explicit check that width is an Integer or is in range;
       none is needed because those checks happen anyway."
      |result mean resultIndex|
      result := Array new: self size - width + 1.
      mean := 0.
      1 to: width do: [:i | mean := (self at: i) + mean].
      mean := mean / width.
      resultIndex := 1.
      result at: resultIndex put: mean.
      width + 1 to: self size do: [:i |
        mean := ((self at: i) - (self at: resultIndex)) / width + mean.
        resultIndex := resultIndex + 1.
        result at: resultIndex put: mean].
      ^result



On Mon, 13 Apr 2020 at 00:23, Sven Van Caekenberghe <s...@stfx.eu> wrote:
>
>
>
> > On 12 Apr 2020, at 13:53, Cédrick Béler <cdric...@gmail.com> wrote:
> >
> > Beautiful ^^
>
> I also like it.
>
> But why the single letter variable names ? Why not:
>
> SequenceableCollection>>#runningMeans: width
>   | means sum index |
>   means := Array new: self size - width + 1.
>   sum := 0.
>   1 to: width do: [ :each |
>     sum := sum + (self at: each) ].
>   index := 1.
>   means at: index put: sum / width.
>   width + 1 to: self size do: [ :each |
>     sum := sum - (self at: index) + (self at: each).
>     index := index + 1.
>     means at: index put: sum / width ].
>   ^ means
>
> A good comment, a correct initial bounds check and unit tests are also needed.
>
> > I would vote for inclusion in the base image ?
> > With your explanation as comments.
> >
> > I’ll play with it.
> >
> > Thanks
> > Cedrick
> >
> >> Le 12 avr. 2020 à 12:19, Richard O'Keefe <rao...@gmail.com> a écrit :
> >>
> >> 
> >> I have coded and benchmarked 8 different running mean algorithms.
> >> In the presence of inexact numbers it is not as accurate as
> >> redoing the sums, but it's pretty close, and it's fast.
> >> If "width" is not an integer or is out of range, an error
> >> will be reported by #new: or #at:[put:].  It's based on Welford's
> >> stable update.
> >>
> >> Of course this approach does NOT work for trimmed or Winsorised
> >> means or for medians or any kind of robust estimate of location.
> >>
> >> SequenceableCollection
> >>  methods for: 'summarising'
> >>    runningMeans: width
> >>      |a m d|
> >>      a := Array new: self size - width + 1.
> >>      m := 0.
> >>      1 to: width do: [:i |
> >>        m := (self at: i) + m].
> >>      m := m / width.
> >>      d := 1.
> >>      a at: d put: m.
> >>      width + 1 to: self size do: [:i |
> >>        m := ((self at: i) - (self at: d)) / width + m.
> >>        d := d + 1.
> >>        a at: d put: m].
> >>      ^a
> >>
> >>
> >>
> >>
> >>
> >
>
>

Reply via email to