【问题标题】:How to remove those rows of matrix A, which have equal values with matrix B in specified columns in Matlab?如何删除矩阵A的那些行,这些行在Matlab的指定列中与矩阵B具有相等的值?
【发布时间】:2014-06-19 06:21:46
【问题描述】:

我在 Matlab A 和 B 中有两个矩阵,它们的列数相同,但行数不同。 B中的行数也小于A中的行数。B实际上是A的子集。

如何有效地从 A 中删除这些行,其中 A 的第 1 列和第 2 列中的值等于矩阵 B 的第 1 列和第 2 列中的值?

目前我正在这样做:

for k = 1:size(B, 1)
     A(find((A(:,1) == B(k,1) & A(:,2) == B(k,2))), :) = [];
end

Matlab 抱怨这效率低下,我应该尝试使用any,但我不确定如何使用any。有人可以帮我解决这个问题吗? =)

我试过了,但它不起作用:

A(any(A(:,1) == B(:,1) & A(:,2) == B(:,2), 2), :) = [];

它抱怨以下内容:

Error using  == 
Matrix dimensions must agree.

我想要的示例:

结果中的A-B表示从A中删除B的行。A-C也是如此。

【问题讨论】:

  • setdiff 是最好的解决方案,但是要将您的第一次尝试转换为 any保持您的循环)这是 Matlab 的建议(您实际上想要@ 987654330@ 而不是 any 在你的情况下):A(all(A == B(k,:),2), :) = [];
  • 顺便说一句,我没有意识到您只是在比较前两列,所以将我的最后一条评论更新为 A(all(A(:,1:2) == B(k,1:2),2), :) = [];
  • 谢谢大家的精彩回答 =) 原来的运行时间(我的数据)是:0.198072 秒。通过使用 bsxfun 方法,我得到了大约 0.007 秒的运行时间。通过使用setdiff(A(:,1:2),B(:,1:2),'rows'),我得到了运行时间:0.004120 秒。
  • @jjepsuomi 希望你也可以在更大的数据大小上做一些基准测试,看到这些结果也会很有趣。
  • +1 @Divakar 我将尝试使用不同的数据集并发布我的结果 =) 这需要几分钟 =)

标签: performance matlab matrix vectorization


【解决方案1】:

尝试使用setdiff。例如:

c=setdiff(a,b,'rows')

注意,如果顺序很重要,请使用:

c = setdiff(a,b,'rows','stable')

编辑:阅读已编辑的问题和对此答案的cmets,您寻找的setdiff的具体用法是(如Shai所注意到的):

[temp c] = setdiff(a(:,1:2),b(:,1:2),'rows','stable')
c = a(c,:)

替代方案:

你可以使用ismember:

a(~ismember(a(:,1:2),b(:,1:2),'rows'),:)

【讨论】:

  • +1 但是你不需要setdiff(A(:,1:2),B(:,1:2),'rows') 吗?
  • 当我写下我的答案时,有两个数组的问题与答案中的数组相似,现在已被编辑掉。那就是我一直写的:“例如,...”如果您理解答案,则无论如何都可以将其应用于问题。
  • @jjepsuomi 可以发回您在编辑之前在帖子中的屏幕截图吗?
  • 从所有混乱中我想到了ismember的替代解决方案... :)
  • @natan haha​​ 避免混乱的方法!超出+1 :)
【解决方案2】:

使用:

compare = bsxfun( @eq, permute( A(:,1:2), [1 3 2]), permute( B(:,1:2), [3 1 2] ) );
twoEq = all( compare, 3 );
toRemove = any( twoEq, 2 ); 
A( toRemove, : ) = [];

解释代码:

首先,我们使用bsxfun 将所有第一对与AB 的列进行比较,从而得到大小为numRowsA-by-numRowsB-by-2 和truecompare compare( ii, jj, kk ) = A(ii,kk) == B(jj,kk).
然后我们使用all 创建大小为numRowsA-by-numRowsBtwoEq,其中每个条目表示AB两个 对应条目是否相等。
最后,我们使用any 来选择至少匹配一行BA 行。

原代码有什么问题:

通过删除循环内的A 行(即A( ... ) = []),您实际上几乎在每次迭代时都会调整A 的大小。请参阅this post,了解为什么这是一个不好的做法

使用setdiff

为了仅在前两列上使用setdiff(由natan 建议),您需要使用它的第二个输出参数:

[ignore, ia] = setdiff( A(:,1:2), B(:,1:2), 'rows', 'stable' );
A = A( ia, : ); % keeping only relevant rows, beyond first two columns.

【讨论】:

  • 感谢您的努力 =) 您的回答很棒! =)
【解决方案3】:

这是另一个 bsxfun 实现 -

A(~any(squeeze(all(bsxfun(@eq,A(:,1:2),permute(B(:,1:2),[3 2 1])),2)),2),:)

还有一个危险地接近Shai's solution,但仍然避免two permuteone permute -

A(~any(all(bsxfun(@eq,A(:,1:2),permute(B(:,1:2),[3 2 1])),2),3),:)

【讨论】:

  • @natan haha​​ 谢谢,同样在这里 :)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-06-13
  • 1970-01-01
  • 1970-01-01
  • 2021-10-12
  • 1970-01-01
相关资源
最近更新 更多