我想从矩阵中删除几个特定值(如果存在)。极有可能在矩阵中有多个值副本。
例如,考虑N乘2矩阵intersections
。如果值[a b]
和[c d]
对存在于该矩阵中的行,我想删除它们。
假设我要在以下矩阵中删除[-2.0 0.5]
和[7 7]
等行:
intersections =
-4.0000 0.5000
-2.0000 0.5000
2.0000 3.0000
4.0000 0.5000
-2.0000 0.5000
所以删除后我得到:
intersections =
-4.0000 0.5000
2.0000 3.0000
4.0000 0.5000
最有效/优雅的方法是什么?
答案 0 :(得分:13)
试试这个单行( A 是您的交叉矩阵, B 是要移除的值):
A = [-4.0 0.5;
-2.0 0.5;
2.0 3.0;
4.0 0.5;
-2.0 0.5];
B = [-2.0 0.5];
A = A(~all(A == repmat(B,size(A,1),1),2),:);
然后只需为要删除的每个新 B 重复最后一行。
修改强>
......这是另一种选择:
A = A((A(:,1) ~= B(1)) | (A(:,2) ~= B(2)),:);
警告:此处的答案最适用于不期望小浮点错误的情况(即使用整数值)。如此follow-up question中所述,使用“==”和“〜=”运算符会导致不需要的结果。在这种情况下,应修改上述选项以使用关系运算符而不是相等运算符。例如,我添加的第二个选项将更改为:
tolerance = 0.001; % Or whatever limit you want to set
A = A((abs(A(:,1)-B(1)) > tolerance) | (abs(A(:,2)-B(2)) > tolerance),:);
快速抬头! =)
某些RUDIMENTARY时间安排:
如果有人真的对效率感兴趣,我只是做了一些简单的时间,以三种不同的方式获得矩阵的子索引(我在上面列出的两个选项和{{3} STRMATCH选项):
>> % Timing for option #1 indexing:
>> tic; for i=1:10000, index = ~all(A == repmat(B,size(A,1),1),2); end; toc;
Elapsed time is 0.262648 seconds.
>> % Timing for option #2 indexing:
>> tic; for i=1:10000, index = (A(:,1) ~= B(1)) | (A(:,2) ~= B(2)); end; toc;
Elapsed time is 0.100858 seconds.
>> % Timing for STRMATCH indexing:
>> tic; for i=1:10000, index = strmatch(B,A); end; toc;
Elapsed time is 0.192306 seconds.
正如您所看到的,STRMATCH选项比我的第一个建议更快,但我的第二个建议是所有三个中最快的。但是请注意,我的选项和Fanfan的做法略有不同:我的选项将行的逻辑索引返回到 keep ,而Fanfan将行的线性索引返回到 remove 。这就是STRMATCH选项使用以下形式的原因:
A(index,:) = [];
虽然我使用表格:
A = A(index,:);
但是,我的索引可以否定使用第一种形式(将行索引到删除):
A(all(A == repmat(B,size(A,1),1),2),:) = []; % For option #1
A((A(:,1) == B(1)) & (A(:,2) == B(2)),:) = []; % For option #2
答案 1 :(得分:7)
这里的简单解决方案是设置成员函数,即setdiff,union和ismember。
A = [-4 0.5;
-2 0.5;
2 3;
4 0.5;
-2 0.5];
B = [-2 .5;7 7];
查看成员对两个数组的作用。使用'rows'选项。
ismember(A,B,'rows')
ans =
0
1
0
0
1
由于我们希望删除也在B中的A行,只需执行以下操作:
A(ismember(A,B,'rows'),:) = []
A =
-4 0.5
2 3
4 0.5
请注意,集合成员函数会查找完全匹配。等于1/2的整数或1/2的倍数满足该要求。它们在MATLAB中用浮点运算表示。
如果这些数字是真正的浮点数,我会更加小心。在那里,我已经对差异使用了容忍度。在这种情况下,我可能已经计算了两组数字之间的点间距离矩阵,只有当它落在B行之一的给定距离内时才删除A行。
答案 2 :(得分:5)
您还可以滥用strmatch函数以满足您的需要:以下代码删除矩阵A中给定行b的所有出现
A(strmatch(b, A),:) = [];
如果您需要删除多行,例如矩阵B中的所有行,请迭代它们:
for b = B'
A(strmatch(b, A),:) = [];
end
答案 3 :(得分:0)
不确定何时引入此功能(使用2012b),但您可以这样做:
setdiff(A, B, 'rows')
ans =
-4.0000 0.5000
2.0000 3.0000
4.0000 0.5000
基于:
A = [-4.0 0.5;
-2.0 0.5;
2.0 3.0;
4.0 0.5;
-2.0 0.5];
B = [-2.0 0.5];