2009-03-25 41 views
10

マトリックスからいくつかの特定の値を削除したい(存在する場合)。マトリックスに複数の値のコピーが存在する可能性は非常に高いです。MATLABの行列から要素を削除する最も効率的でエレガントな方法は何ですか?

例えば、N行2列の行列intersectionsを考えてみましょう。値がと[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 

を行うための最も効率的な/エレガントな方法は何この?

答えて

13

(どこあなたの交差点行列であると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のための最後の行を繰り返します削除する。

EDIT:

A = A((A(:,1) ~= B(1)) | (A(:,2) ~= B(2)),:); 

WARNING:ここで回答は最高の小さな浮動小数点エラーが期待されていない場合に使用されている(つまり、と

...と、ここでは別のオプションです整数値)。このfollow-up questionに記載されているように、 "=="および "〜="演算子を使用すると、望ましくない結果が生じる可能性があります。そのような場合、上記のオプションは、等価演算子の代わりに関係演算子を使用するように変更する必要があります。たとえば、私が追加した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),:); 

に変更されました。誰もが効率が本当に興味があった場合、私はちょうど行列のためのサブインデックスを取得するための3つの異なる方法のためのいくつかの簡単なタイミングをした

(2:=)


初歩的なタイミングオプションI)は、上記と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オプションは、私の最初の提案よりも高速ですが、私の2番目の提案は3つの中で最速です。私のオプションは、行の論理インデックスをとし、Fanfanは行の線形インデックスをに返します。を削除します。鉱山は、フォームを使用しながら、

A(index,:) = []; 

:STRMATCHオプションはフォームを使用する理由です

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 
+0

は、私はほとんどベクター溶液があったが、あなたよりも少し冗長ではありません。ニースワンライナー。 – Azim

+0

うわー...そうエレガントな方法.... –

5

また、あなたのニーズに合わせてstrmatch機能を悪用することができます。次のコードは、行列で与えられたB列のすべての出現箇所を削除します

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

あなたは、このような行列Bからすべての行として、複数の行を削除する必要がある場合は、それらを反復:

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

+1これを行うためにSTRMATCHを使用して非常に卑劣な!なぜ誰かがそれを落としたのか分かりません...私はそれを自分で試したところ、うまくいくようです。私は簡単なタイミングをとって、STRMATCHを使って行列インデックスを得るのは、上記の最初のオプションとほぼ同じ速度ですが、私の2番目の選択肢は最速です。 – gnovice

7

ここに簡単な解決策は、すなわち、メンバーシップ関数を設定するために見ています、 setdiff、union、およびismemberです。

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

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

2つの配列でismemberの動作を確認してください。 「行」オプションを使用します。私たちは、Bにもあるというの行を削除したいので

ismember(A,B,'rows') 

ans = 
    0 
    1 
    0 
    0 
    1 

ちょうどこの操作を行います。

A(ismember(A,B,'rows'),:) = [] 

A = 
     -4   0.5 
     2   3 
     4   0.5 

は、そのセットのメンバーシップ関数は、EXACT一致するものを探しに注意してください。 Aのような1/2の整数または倍数は、その要件を満たす。これらは、MATLABの浮動小数点演算で正確に表されます。

は、これらの数字は、実際の浮動小数点数をされて、私はより慎重になっていると思い持っていました。そこに私は差異に対する許容差を使用していただろう。その場合、私はそれがB.

+1

+1 ISMEMBERが行間でどのように動作するか忘れてしまった。また、SOにようこそ! ;) – gnovice

0

ませんこの関数とした場合確認の行の1つの、いくつかの所定の距離内に入った場合にのみ、Aの列を除去する、数字の2つのセットの間の点間距離行列を計算している可能性があります導入された(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]; 
関連する問題