朱莉娅的移动平均线

Moving average in Julia

我想在 Julia 中计算数组的简单移动平均值。我有一个简单的数组,但我找到的所有包都需要一个 TimeArray 来计算移动平均值。有没有不需要我人为创建TimeArray的包?

怎么样:

moving_average(vs,n) = [sum(@view vs[i:(i+n-1)])/n for i in 1:(length(vs)-(n-1))]

这可以通过制定标准 for 循环、预先分配结果数组并在每次迭代中仅减去和添加输入数组的一个元素来进一步优化。然而,对于大多数应用程序,上面的简单代码就足够了。

你可以像我一样写自己的移动平均线

function movingaverage(X::Vector,numofele::Int)
    BackDelta = div(numofele,2) 
    ForwardDelta = isodd(numofele) ? div(numofele,2) : div(numofele,2) - 1
    len = length(X)
    Y = similar(X)
    for n = 1:len
        lo = max(1,n - BackDelta)
        hi = min(len,n + ForwardDelta)
        Y[n] = mean(X[lo:hi])
    end
    return Y
end
julia> using ImageFiltering, OffsetArrays

julia> v = zeros(20); v[10] = 1   # test vector to perform moving average
1

julia> kernel = OffsetArray(fill(1/8, 8), -5:2)  # moving average of 5 previous, current, and 2 ahead
8-element OffsetArray(::Array{Float64,1}, -5:2) with eltype Float64 with indices -5:2:
 0.125
 0.125
 0.125
 0.125
 0.125
 0.125
 0.125
 0.125

julia> [v imfilter(v, kernel)]
20×2 Array{Float64,2}:
 0.0  0.0  
 0.0  0.0  
 0.0  0.0  
 0.0  0.0  
 0.0  0.0  
 0.0  0.0  
 0.0  0.0  
 0.0  0.125
 0.0  0.125
 1.0  0.125
 0.0  0.125
 0.0  0.125
 0.0  0.125
 0.0  0.125
 0.0  0.125
 0.0  0.0  
 0.0  0.0  
 0.0  0.0  
 0.0  0.0  
 0.0  0.0  

我尝试实现了几个版本:

function rolling_sum(arr, n)
    so_far = sum(arr[1:n])
    out = zero(arr[n:end])
    out[1] = so_far
    for (i, (start, stop)) in enumerate(zip(arr, arr[n+1:end]))
        so_far += stop - start
        out[i+1] = so_far
    end
    return out
end

rolling_mean(arr, n) = rolling_sum(arr, n) ./ n

function rolling_mean2(arr, n)
    return imfilter(arr, OffsetArray(fill(1/n, n), -n), Inner())
end

function rolling_mean3(arr, n)
    so_far = sum(arr[1:n])
    out = zero(arr[n:end])
    out[1] = so_far
    for (i, (start, stop)) in enumerate(zip(arr, arr[n+1:end]))
        so_far += stop - start
        out[i+1] = so_far / n
    end
    return out
end

function rolling_mean4(arr, n)
    rs = cumsum(arr)[n:end] .- cumsum([0.0; arr])[1:end-n]
    return rs ./ n
end

julia> v = rand(50_000);
julia> @btime(rolling_mean($v, 200));
  125.362 μs (9 allocations: 1.52 MiB)

julia> @btime(rolling_mean2($v, 200));
  1.089 ms (127 allocations: 3.06 MiB)

julia> @btime(rolling_mean3($v, 200));
  93.137 μs (7 allocations: 1.14 MiB)

julia> @btime(rolling_mean4($v, 200));
  161.613 μs (12 allocations: 2.28 MiB)

在这种情况下,在每一步添加和删除元素的专用版本看起来要快得多。

这是一个双线,在(可能)你已经在某处有一个 mean 函数的情况下变成一个单线。

using Statistics: mean
movingaverage(g, n) = [i < n ? mean(g[begin:i]) : mean(g[i-n+1:i]) for i in 1:length(g)]

与发布的一些较长的答案一样,这具有保留输入向量长度的优点 g,这对于绘图很有用。