Julia 朱莉娅:当行号存储在数组中时,如何取消选择矩阵中的行

Julia 朱莉娅:当行号存储在数组中时,如何取消选择矩阵中的行,julia,Julia,我想从矩阵a中删除行 我要删除的行号存储在数组B中 例如: B=[1,2,3]意味着我要从矩阵A中删除行1、2和3。如何使用Julia语言实现这一点?如果您不想安装任何其他软件包,那么我所知道的最新解决方案是: x = randn(5, 2) inds_to_remove = [1,3,4] x[setdiff(1:size(x,1), inds_to_remove), :] 这个问题归根结底是如何反转一组已经被问到和回答过的指数。从链接的问题中,请注意还有一个用于此的包,它将适用于任意维度的

我想从矩阵
a
中删除行

我要删除的行号存储在数组
B

例如


B=[1,2,3]
意味着我要从矩阵
A
中删除行1、2和3。如何使用Julia语言实现这一点?

如果您不想安装任何其他软件包,那么我所知道的最新解决方案是:

x = randn(5, 2)
inds_to_remove = [1,3,4]
x[setdiff(1:size(x,1), inds_to_remove), :]
这个问题归根结底是如何反转一组已经被问到和回答过的指数。从链接的问题中,请注意还有一个用于此的包,它将适用于任意维度的集合

还值得注意的是,如果您只想删除一行,那么:

x[1:end .!= i, :]
是一种快速、简洁的解决方案。

另一种更快(但不那么简洁)的可能性是

vcat(deleteat!([A[r,:]' for r in 1:size(A, 1)], inds)...)
i、 e.提取行作为向量,删除相关行,转换回矩阵形状

示例:

julia> A = randn(5, 2)
5×2 Array{Float64,2}:
  0.0204771   0.641602
 -0.51661     0.0314303
 -0.0667214  -1.61672
 -0.303866    2.0537
 -1.31845    -1.44462

julia>     inds = [1,3,4]
3-element Array{Int64,1}:
 1
 3
 4

julia>     vcat(deleteat!([A[r,:]' for r in 1:size(A, 1)], inds)...)
2×2 Array{Float64,2}:
 -0.51661   0.0314303
 -1.31845  -1.44462
julia> @btime vcat(deleteat!([$(A)[r,:]' for r in 1:size($A, 1)], $inds)...);
  405.335 ns (17 allocations: 912 bytes)

julia> @btime $(A)[setdiff(1:size($A,1), 1:3), :]; # @ColinTBowers answer
  5.049 μs (58 allocations: 2.16 KiB)
请注意,生成的矩阵是一个副本,
a
没有被修改,就像@ColinTBowers answer中一样

基准测试:

julia> A = randn(5, 2)
5×2 Array{Float64,2}:
  0.0204771   0.641602
 -0.51661     0.0314303
 -0.0667214  -1.61672
 -0.303866    2.0537
 -1.31845    -1.44462

julia>     inds = [1,3,4]
3-element Array{Int64,1}:
 1
 3
 4

julia>     vcat(deleteat!([A[r,:]' for r in 1:size(A, 1)], inds)...)
2×2 Array{Float64,2}:
 -0.51661   0.0314303
 -1.31845  -1.44462
julia> @btime vcat(deleteat!([$(A)[r,:]' for r in 1:size($A, 1)], $inds)...);
  405.335 ns (17 allocations: 912 bytes)

julia> @btime $(A)[setdiff(1:size($A,1), 1:3), :]; # @ColinTBowers answer
  5.049 μs (58 allocations: 2.16 KiB)
在后者中,
setdiff
似乎是一个很大的瓶颈:

julia> @btime setdiff(1:size($A,1), $inds)
  3.253 μs (40 allocations: 1.59 KiB)
手动执行

就速度而言,以上所有内容都应与快速手动实现进行比较。类似于

rmrows(A, inds) = begin
  rows, cols = size(A)
  out = similar(A, rows-length(inds), cols)
  for c in 1:cols
    i = 1
    for r in 1:rows
      if !(r in inds)
         @inbounds out[i,c] = A[r,c]
         i+=1
      end
    end
  end
  out
end
这导致了

julia> @btime rmrows($A, $inds);
  60.581 ns (1 allocation: 112 bytes)
更新1:手动执行


更新2:更快的手动实现

我本来打算投票以的副本结束,但经过再三考虑,也许是因为OP是在问矩阵,而不是向量,这个问题完全不同,不可能是副本。是的,invertedices.jl使这只是一个[not(B),:]但你们喜欢基本的Julia答案,对吗?@ColinTBowers如果您想从向量中删除行(即元素),只需执行
deleteat!(vec,inds)
。这很整洁(!),但不幸的是没有表现出来。请参阅下面的我的基准。@crstnbr请参阅我对您的基准的反驳:-)我认为您可以在手动实现中按列操作,获得更快的解决方案,尤其是对于更大尺寸的阵列。可能还有其他一些优化(如果
inds
大于矩阵大小的一半,则首先将其反转,以便在for循环中更快地搜索
if
)。因此,考虑到包开发人员(可能)自己做这种优化,选择包通常是最好的选择。@hckr同意。我只是想得到一个粗略的估计手动实现。伟大的答案!然而,请注意,对于这个问题,算法效率高度依赖于输入的大小。在我的机器上,当您真正放大问题时,
setdiff
方法很容易占主导地位,例如尝试删除10000行、500列和500行。