【问题标题】:Creating a row vector from slice of matrix从矩阵切片创建行向量
【发布时间】:2020-04-28 00:56:28
【问题描述】:

我想知道是否有人有明确的方法从矩阵的切片返回行向量?

matrix[k,:]

实际上返回大小为(n,) 的向量,因此Julia 会自动将其视为 向量,而不是行向量。到目前为止,我一直在使用语法

matrix[k,:]'

表示大小为(1,n) 的行向量,但不知何故,这看起来很笨重,而且一点也不直观,因为这是行向量而不是列向量。与我交谈过的大多数数学家都错误地认为这不是行向量。

有没有更 Julianic 的方式来获取行向量切片,​​更清晰?

【问题讨论】:

    标签: vector julia slice


    【解决方案1】:
    julia> m=rand(1:10,3,4)
    3×4 Array{Int64,2}:
     4  5  3  9
     6  8  1  5
     4  5  3  4
    
    julia> m[[1],:]
    1×4 Array{Int64,2}:
     4  5  3  9
    

    请注意,最好使用views 来避免数据复制:

    julia> @view m[[1],:]
    1×4 view(::Array{Int64,2}, [1], :) with eltype Int64:
     4  5  3  9
    

    说明:

    Array 元素的选择可以通过使用标量或使用迭代来完成。使用标量会导致给定维度被删除。另一方面,使用集合不会删除维度。为了更好地解释,请考虑另一个示例:

    julia> m[1:1,1:1]
    1×1 Array{Int64,2}:
     4
    

    您可以看到只选择了一个元素,但维度没有被删除。因此,您最终拥有一个只有一行和一列的Matrix(即二维Array)。

    编辑(Colin T Bowers 评论 - 谢谢!)

    决定是否使用视图并不是琐事——主要是你的代码是否从缓冲中受益。然而,令人惊讶的是,views 通常会更好。

    julia> const vals = rand(200,200);
    
    julia> using BenchmarkTools
    
    julia> @btime sum(view(vals,1,:))
      169.392 ns (1 allocation: 48 bytes)
    95.08924081258299
    
    julia> @btime sum(vals[1,:])
      184.384 ns (1 allocation: 1.77 KiB)
    95.08924081258299
    

    让我们定义自己的求和函数。

    julia> function mysum(a::AbstractVector{A}) where A <: Number
        v = zero(A)
        @inbounds @simd for i in 1:length(a)
            v += a[i]
        end
        v
    end;
    
    julia> @btime mysum(view(vals,1,:))
      141.931 ns (0 allocations: 0 bytes)
    95.08924081258299
    
    julia> @btime mysum(vals[1,:])
      174.934 ns (1 allocation: 1.77 KiB)
    95.08924081258297
    

    可以清楚地看到,当你对行求和一次时,views 仍然更好。 最后但并非最不重要的一点是,按列求和当然要快几倍,而且复制数据非常昂贵:

    julia> @btime sum(view(vals,:,1))
      25.828 ns (1 allocation: 48 bytes)
    96.04440265541243
    
    julia> @btime mysum(view(vals,:,1))
      13.927 ns (0 allocations: 0 bytes)
    96.04440265541243
    
    julia> @btime sum(vals[:,1])
      167.745 ns (1 allocation: 1.77 KiB)
    96.04440265541243
    

    【讨论】:

    • 太棒了!正是我想要的。如果您可以在答案中添加为什么 m[[1],:]m[1,:] 不同,我很乐意接受。
    • 令人惊讶的是,对于行向量,有时使用view会好得多。这是因为 Julia 中的矩阵以列优先顺序存储,因此矩阵中的行切片在内存中不连续。当输入在内存中是连续的时,许多常见的 BLAS 操作(例如对向量求和)具有出色的优化,因此在许多情况下,创建行切片的新副本所浪费的时间超过了新副本是连续的事实所抵消的在内存中,并且可以利用 BLAS 优化。
    • @NoseKnowsAll 我根据您的要求添加了解释。
    • @ColinTBowers 令人惊讶地查看或不​​查看决定并不总是那么明显。我的经验是您每次都需要进行基准测试 - 请参阅我的扩展编辑。
    • @PrzemyslawSzufel 哇,我实际上并没有要求您添加解释,但是您做得很好。完全同意,如果您的例程对性能至关重要,那么最好的选择是进行基准测试,因为并不总是清楚哪种方法将占主导地位。话虽如此,sum 上的 view 性能令人印象深刻,以及您优化的例程。我对在 v0.3 上做这个测试有一个模糊的记忆,当时制作一个新副本是明显的赢家。语言已经走过了漫长的道路!
    猜你喜欢
    • 2017-02-02
    • 2019-12-13
    • 2014-07-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-08-08
    • 2016-01-16
    • 1970-01-01
    相关资源
    最近更新 更多