10

我想从矩阵中删除几个特定值(如果它们存在)。矩阵中的值很可能存在多个副本。

例如,考虑一个 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

最有效/最优雅的方法是什么?

4

4 回答 4

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)),:);

警告:此处的答案最适用于不期望出现小浮点错误的情况(即整数值)。如本后续问题所述,使用“==”和“~=”运算符可能会导致不需要的结果。在这种情况下,应修改上述选项以使用关系运算符而不是相等运算符。例如,我添加的第二个选项将更改为:

tolerance = 0.001;   % Or whatever limit you want to set
A = A((abs(A(:,1)-B(1)) > tolerance) | (abs(A(:,2)-B(2)) > tolerance),:);

只是快速抬头!=)


一些基本的时间安排:

如果有人真的对效率感兴趣,我只是为三种不同的方法获取矩阵的子索引(我上面列出的两个选项和Fanfan 的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 的做法略有不同:我的选项返回要保留的行的逻辑索引,而 Fanfan 的返回要删除的行的线性索引。这就是 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
于 2009-03-25T22:28:34.390 回答
7

这里的简单解决方案是查看设置成员函数,即 setdiff、union 和 ismember。

A = [-4  0.5;
   -2    0.5;
    2    3;
    4    0.5;
   -2    0.5];

B = [-2 .5;7 7];

看看 ismember 对这两个数组做了什么。使用“行”选项。

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

请注意,集合成员函数会寻找精确匹配。诸如 A 中的 1/2 的整数或倍数满足该要求。它们在 MATLAB 中以浮点算法精确表示。

如果这些数字是真正的浮点数,我会更加小心。我会在差异上使用公差。在这种情况下,我可能已经计算了两组数字之间的点间距离矩阵,只有当 A 的一行落在 B 的其中一行的某个给定距离内时才删除它。

于 2009-03-31T14:26:02.707 回答
5

您还可以滥用 strmatch 函数来满足您的需要:以下代码删除矩阵 A 中给定行 b 的所有出现

A(strmatch(b, A),:) = [];

如果您需要删除多行,例如矩阵 B 中的所有行,请遍历它们:

for b = B'
   A(strmatch(b, A),:) = [];
end
于 2009-03-25T23:56:00.577 回答
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];
于 2013-10-31T14:17:04.770 回答