【问题标题】:View on Julia array using sliding window使用滑动窗口查看 Julia 数组
【发布时间】:2020-12-25 10:10:56
【问题描述】:

使用例如滑动窗口=2 在数组上创建视图的最有效方法是什么

假设我们有:

x = collect(1:1:6)
# 1 2 3 4 5 6

我想创建一个这样的视图:

# 1 2
# 2 3
# 3 4
# 4 5
# 5 6

到目前为止,我只找到了这个选项,但不确定它是否是最佳选项:

y = Array{Float32, 2}(undef, nslides, window)
@inbounds for i in 1:window
    y[:, i] = @view x[i:end-(window-i)]
end

【问题讨论】:

    标签: arrays performance julia rolling-computation sliding-window


    【解决方案1】:

    一个班轮是:

    view.(Ref(x), (:).(1:length(x)-1,2:length(x)))
    

    测试:

    julia> x=collect(1:6);
    
    julia> view.(Ref(x), (:).(1:length(x)-1,2:length(x)))
    5-element Array{SubArray{Int64,1,Array{Int64,1},Tuple{UnitRange{Int64}},true},1}:
     [1, 2]
     [2, 3]
     [3, 4]
     [4, 5]
     [5, 6]
    

    解释:

    • views 的创建由点运算符 . 向量化
    • 我们不想对x 的元素进行矢量化,因此请改用Ref(x)
    • (:) 只是 UnitRange 的更短形式,我们再次使用点运算符 . 进行矢量化

    我使用2作为窗口大小,当然你可以写view.(Ref(x), (:).(1:length(x)-(window-1),window:length(x)))

    编辑:

    如果你想要一个库函数,这对你有用:

    julia> using ImageFiltering
    
    julia> mapwindow(collect, x, 0:1,border=Inner())
    5-element OffsetArray(::Array{Array{Int64,1},1}, 1:5) with eltype Array{Int64,1} with indices 1:5:
     [1, 2]
     [2, 3]
     [3, 4]
     [4, 5]
     [5, 6]
    

    当然你可以把它们放在你想在滑动窗口上运行的功能,而不仅仅是收集。

    【讨论】:

    • 我们不是有那个吗 :) 现在我找到了我正在寻找的包:RollingFunctions.jl
    • 也许会更整洁:reduce(vcat, @views [x[i-1:i]' for i in 2:length(x)])。这也将切片连接为矩阵的行。
    • 然而,这会返回 Matrix 而不是 view,因此 x 中的原始数据将被复制,并且基准测试速度要慢 3.5 倍。
    • @phipsgabler 是的!这是一个很好的!但是,这允许您在滚动窗口上运行函数,而不是自己获取窗口(至少我没有看到无需聚合就生成窗口的代码)
    • 当然,reduce(vcat, ...') 可以应用于或不应用于任何一种形式。这个问题既创建了一个矩阵,又表示了视图。也许还值得注意的是,如果x 包含复数或字符串,这里的' 将是错误的。
    【解决方案2】:

    一个带有包的解决方案(嗯,我的包)是这样的:

    julia> using Tullio
    
    julia> x = 1:6; window = 2;
    
    julia> @tullio y[r,c] := x[r+c-1]  (c in 1:window)
    5×2 Matrix{Int64}:
     1  2
     2  3
     3  4
     4  5
     5  6
    

    【讨论】:

    • 这很好,但是基准测试比我的代码慢 40%。
    • 没看过,但对我来说,在长度为 6 时确实慢了 20ns。然后在长度为 25 时大约相等,从 100 到 10^6 快 3 倍。使用@tullio threads=false ... 会快一点,因为宏不够聪明,无法提前知道多线程永远不会在这里支付。这样一来,编写@inbounds for r in axes(y,1), c in axes(y,2); y[r, c] = x[(r + c) - 1]; end end 并考虑范围和分配只是一种更易读的方式。
    • 我刚刚检查过了——确实对于大型数组Tullio 快​​了 3 倍。看起来很棒!
    猜你喜欢
    • 2021-01-15
    • 1970-01-01
    • 1970-01-01
    • 2012-12-30
    • 2021-10-29
    • 2022-01-03
    • 2018-05-10
    • 2014-09-09
    相关资源
    最近更新 更多