【问题标题】:What's the most efficient/elegant way to delete elements from a matrix in MATLAB?在 MATLAB 中从矩阵中删除元素的最有效/最优雅的方法是什么?
【发布时间】:2009-03-25 21:15:26
【问题描述】:

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

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

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

【问题讨论】:

    标签: matlab matrix delete-record


    【解决方案1】:

    试试这个单线(其中 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),:);
    

    请注意! =)


    一些基本的时间安排:

    如果有人真的对效率感兴趣,我只是对三种不同的方法来获取矩阵的子索引做了一些简单的计时(我上面列出的两个选项和Fanfan'sSTRMATCH选项):

    >> % 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
    

    【讨论】:

    • 我几乎有一个矢量解决方案,但并不比你的详细一点。漂亮的单线。
    【解决方案2】:

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

    由于我们希望删除 A 中也在 B 中的行,只需执行以下操作:

    A(ismember(A,B,'rows'),:) = []
    
    A = 
          -4          0.5
           2            3
           4          0.5
    

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

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

    【讨论】:

    • +1 我忘记了 ISMEMBER 如何跨行操作。另外,欢迎来到 SO! ;)
    【解决方案3】:

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

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

    如果您需要删除多行,例如矩阵 B 中的所有行,请对其进行迭代:

    for b = B'
       A(strmatch(b, A),:) = [];
    end
    

    【讨论】:

    • +1 非常狡猾地使用 STRMATCH 来做到这一点!我不知道为什么有人不赞成它......我只是自己尝试过,它似乎工作得很好。我做了一些简单的计时,发现使用 STRMATCH 获取矩阵索引的速度与我上面的第一个选项差不多,但我的第二个选项最快。
    【解决方案4】:

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

    【讨论】:

      猜你喜欢
      • 2012-07-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-08-05
      • 1970-01-01
      • 2014-09-11
      • 1970-01-01
      相关资源
      最近更新 更多