web-dev-qa-db-ja.com

(スパースでない)行列からゼロを効率的に削除するにはどうすればよいですか?

私はマトリックスを持っています:

x = [0 0 0 1 1 0 5 0 7 0];

次のように、すべてのゼロを削除する必要があります。

x = [1 1 5 7];

私が使用している行列は大きく(1x15000)、これを複数回(5000+)行う必要があるため、効率が重要です!

11
Barry S

一方通行:

_x(x == 0) = [];
_

タイミングに関する注意:

woodchips で述べたように、この方法は KitsuneYMG で使用されている方法に比べて遅いようです。これは、ローレンが彼女の1人で指摘しています MathWorksブログ投稿 。これを何千回も実行する必要があるとおっしゃっていたので、違いに気付くかもしれません。その場合は、最初にx = x(x~=0);を試してみます。

警告:整数以外の数値を使用している場合は注意してください。たとえば、非常に小さい数があり、それが削除されるようにゼロに十分近いと見なしたい場合、上記のコードはそれを削除しません。 exactゼロのみが削除されます。以下は、ゼロに「十分に近い」数値を削除するのにも役立ちます。

_tolerance = 0.0001;  % Choose a threshold for "close enough to zero"
x(abs(x) <= tolerance) = [];
_
16
gnovice

これらは3つの一般的な解決策です。違いを確認するのに役立ちます。

x = round(Rand(1,15000));

y = x;

tic,y(y==0) = [];toc

Elapsed time is 0.004398 seconds.

y = x;

tic,y = y(y~=0);toc

Elapsed time is 0.001759 seconds.

y = x;

tic,y = y(find(y));toc

Elapsed time is 0.003579 seconds.

ご覧のとおり、最も安価な方法は、保持する要素を選択する直接論理インデックスです。 matlabはこれらの要素を検索し、それらのリストを返し、ベクトルにインデックスを付けるため、検索のコストは高くなります。

11
user85109

ただ違う:

x=x(x~=0);

または

x=x(abs(x)>threshold);

これには、複素数で作業するというボーナスもあります

11
KitsuneYMG

これが別の方法です

y = x(find(x))

あなたが試みるさまざまなアプローチの相対的な効率を理解するのはあなたに任せます-書いて、私たち全員に知らせてください。

私のタイミングの結果は、それが大幅に速いかどうかを決定するものではありませんが、これが最も速くて簡単なアプローチのようです。

y = nonzeros(y) 
2
x = [0 0 0 1 1 0 5 0 7 0]
y = [0 2 0 1 1 2 5 2 7 0]

次に、x2とy2は次のように取得できます。

x2=x(~(x==0 & y==0))
y2=y(~(x==0 & y==0))

x2 = [0     1     1     0     5     0     7]
y2 = [2     1     1     2     5     2     7]

お役に立てれば!

0