代码之家  ›  专栏  ›  技术社区  ›  Kamran Bigdely

在matlab中,从矩阵中删除元素的最有效/最优雅的方法是什么?

  •  10
  • Kamran Bigdely  · 技术社区  · 17 年前

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

    例如,考虑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 回复  |  直到 11 年前
        1
  •  13
  •   Community Mohan Dere    9 年前

    试试这个衬垫(在哪 是你的交集矩阵和 是要删除的值):

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

    然后对每一个新的重复最后一行 您要删除。

    编辑:

    …还有另一个选择:

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

    快抬头!=)


    一些基本的时间安排:

    以防有人 真的? 对于效率感兴趣,我只做了三种不同的方法来获得矩阵的子索引(上面列出的两个选项和 Fanfan's 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
    
        2
  •  7
  •   thelatemail    12 年前

    这里的简单解决方案是寻找设置成员函数,即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
    

    请注意,集合成员函数寻找完全匹配的值。整数或1/2的倍数,如满足该要求的整数或倍数。它们在matlab的浮点运算中得到了精确的表示。

    如果这些数字是真正的浮点数,我会更加小心。在那里,我可以容忍这种差异。在这种情况下,我可能已经计算了两组数字之间的点间距离矩阵,仅当A行落在B行之一的给定距离内时,才删除A行。

        3
  •  5
  •   Fanfan    17 年前

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

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

    如果需要删除多行(如矩阵B中的所有行),请对它们进行迭代:

    for b = B'
       A(strmatch(b, A),:) = [];
    end
    
        4
  •  0
  •   Morgan    12 年前

    不确定何时引入此功能(使用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];