JuliaStats / TimeSeries.jl

Time series toolkit for Julia
Other
352 stars 69 forks source link

Feature Request: Centered Moving Average #429

Open mthelm85 opened 5 years ago

mthelm85 commented 5 years ago

It's pretty easy to compute a one-sided moving average with the mean function passed to moving, but it would be nice to be able to compute a centered moving average. It would be nice if this could be done by simply passing a center::Bool keyword argument to moving as is done in R's forecast package with the ma function.

I wrote a function for computing it that looks like this (I'm a Julia newbie):

function centered_moving_avg(ta::TimeArray, order::Int64)::TimeArray
    if isodd(order)
        dist = convert(Int64, (order - 1) / 2)
        cma = [mean(values(ta)[i-dist:i+dist]) for i in dist+1:length(values(ta))-dist]
        return TimeArray(timestamp(ta)[dist+1:end-dist], cma)
    else
        dist = convert(Int64, round((order - 1) / 2))
        cma = [mean(values(ta)[i-dist-1:i+dist]) for i in dist+2:length(values(ta))-dist]
        return TimeArray(timestamp(ta)[dist+2:end-dist], cma)
    end
end

Anyways, just a thought. I love the package, thanks!

iblislin commented 5 years ago

Hi @mthelm85, Thanks for this report, I will dig into the details later. (quite busy at this moment)

LRBaalmann commented 2 years ago

I stumbled over this problem a few days ago as well. To be honest, I thought a centred moving average would be the default behaviour; it just seems very odd to me that applying a moving average to a function (e.g. a sine) should result in a shifted phase. My (stupidly simple) workaround is to simply shift the timestamps by half the width of the moving average's window. This will probably be fairly problematic for non-equidistant timestamps, but, oh, well. As a MWE:

using Statistics
using Plots

# generate some data
t = collect(-2*pi:0.01:2*pi)
x = sin.(t)
dt = Array{DateTime}(undef, length(x))
for i in 1:length(x)
    dt[i] = DateTime(1900,1,1) + Second(i)
end

# generate TimeArrays
mw = 50
ta = TimeArray(dt, x)
tb = moving(mean, ta, mw*2+1, padding=true)
tc = TimeArray(timestamp(tb)[1:end-mw], values(tb)[1+mw:end])

# plot TimeArrays
plot(ta, label="raw data")
plot!(tb, label="moving average")
plot!(tc, label="shifted average")

mwe