MATLABでn次元行列の各要素を反復処理するにはどうすればよいですか?


87

私は問題があります。MATLABのn次元行列のすべての要素を反復処理する必要があります。問題は、任意の数の次元に対してこれを行う方法がわからないことです。私は言うことができることを知っています

for i = 1:size(m,1)
    for j = 1:size(m,2)
        for k = 1:size(m,3)

などですが、任意の数の次元に対してそれを行う方法はありますか?


13
Matlabの用語に関する注意:Matlabには少数のコアデータ型があります。最も重要なのは、構造体、行列、およびセル配列です。マトリックスの一部を参照する場合、「要素」という用語を使用し、「セル」という用語を予約してセル配列の一部を参照するのが一般的です。セルの配列と行列は、どちらもN次元のデータ構造ですが、構文上および意味上の違いが多数あります。
Fooz氏2009

3
何のためにイテレーションが必要か聞いてもいいですか?たぶん、代わりにそれを行うには、「ベクトル化」の方法は...そこにある
Hosamアリー

回答:


92

線形インデックスを使用して、各要素にアクセスできます。

for idx = 1:numel(array)
    element = array(idx)
    ....
end

これは、i、j、kが何であるかを知る必要がない場合に役立ちます。ただし、現在のインデックスを知る必要がない場合は、arrayfun()を使用することをお勧めします。


1
また、何らかの理由でインデックスを回復したい場合でも、次の2つの簡単なコマンドを使用できます I = cell(1, ndims(array)); [I{:}] = ind2sub(size(array),idx);
knedlsepp 2015年

34

matlabの配列の線形インデックスのアイデアは重要です。MATLABの配列は、実際には単なる要素のベクトルであり、メモリ内に配置されています。MATLABでは、行と列のインデックス、または単一の線形インデックスのいずれかを使用できます。例えば、

A = magic(3)
A =
     8     1     6
     3     5     7
     4     9     2

A(2,3)
ans =
     7

A(8)
ans =
     7

配列をベクトルに展開することで、要素がメモリに格納される順序を確認できます。

A(:)
ans =
     8
     3
     4
     1
     5
     9
     6
     7
     2

ご覧のとおり、8番目の要素は数値7です。実際、関数findはその結果を線形インデックスとして返します。

find(A>6)
ans =
     1
     6
     8

その結果、単一のループを使用して、一般的なnd配列の各要素に順番にアクセスできます。たとえば、Aの要素を二乗したい場合(はい、これを行うためのより良い方法があることはわかっています)、次のようにすることができます。

B = zeros(size(A));
for i = 1:numel(A)
  B(i) = A(i).^2;
end

B
B =
    64     1    36
     9    25    49
    16    81     4

線形インデックスの方が便利な状況はたくさんあります。線形インデックスと2つ(またはそれ以上)の次元の添え字の間の変換は、sub2ind関数とind2sub関数を使用して実行されます。

線形インデックスは、一般に、MATLABのすべての配列に適用されます。したがって、構造体やセル配列などで使用できます。線形インデックスの唯一の問題は、それらが大きくなりすぎる場合です。MATLABは、32ビット整数を使用してこれらのインデックスを格納します。したがって、配列に合計2 ^ 32を超える要素が含まれている場合、線形インデックスは失敗します。これは、スパース行列を頻繁に使用する場合にのみ問題になりますが、問題が発生する場合があります。(私は64ビットのMATLABリリースを使用していませんが、使用している幸運な個人の問題は解決されたと思います。)


64ビットMATLABでのインデックス作成では、64ビットの添え字が正しく許可されます。例:x = ones(1,2^33,'uint8'); x(2^33)期待どおりに機能します。
Edric 2012年

@ Edric-もちろん、これは私がその発言をしてから数年(そして多くのリリース)で確かに変わったであろう振る舞いです。チェックしてくれてありがとう。

:)コメントするまで、答えが何歳かわかりませんでした。質問はRSSフィードに表示されたばかりで、自分も答えたことに気づいていませんでした。
Edric 2012年

15

他のいくつかの回答で指摘されているように、単一のforループでからからまでの線形インデックスAを使用して、(任意の次元の)行列内のすべての要素を反復処理できます。使用できる関数もいくつかあります:と。1numel(A)arrayfuncellfun

まず、A(と呼ばれるmy_func)の各要素に適用する関数があると仮定します。まず、この関数への関数ハンドルを作成します。

fcn = @my_func;

場合はA、任意の寸法の(double型の、単一、など)行列では、使用することができますarrayfun適用するmy_func各要素に:

outArgs = arrayfun(fcn, A);

場合Aであるセル配列の任意の次元のは、あなたが使用することができますcellfun適用するにはmy_func、各セルに:

outArgs = cellfun(fcn, A);

関数my_funcA入力として受け入れる必要があります。からの出力がある場合my_func、これらはに配置されますoutArgs。これは、と同じサイズ/寸法になりAます。

場合は出力に1つの警告は...my_funcさまざまなサイズと種類のリターン出力は、それが別の要素に動作している場合Aは、outArgsセル配列に行う必要があります。これは、いずれarrayfuncellfunを呼び出すか、追加のパラメーター/値のペアを使用して実行されます。

outArgs = arrayfun(fcn, A, 'UniformOutput', false);
outArgs = cellfun(fcn, A, 'UniformOutput', false);

13

もう一つのトリックは使用することですind2subsub2indnumelおよびと組み合わせてsize、これにより、次のような処理を実行できます。これにより、N次元配列が作成され、「対角」上のすべての要素が1に設定されます。

d = zeros( 3, 4, 5, 6 ); % Let's pretend this is a user input
nel = numel( d );
sz = size( d );
szargs = cell( 1, ndims( d ) ); % We'll use this with ind2sub in the loop
for ii=1:nel
    [ szargs{:} ] = ind2sub( sz, ii ); % Convert linear index back to subscripts
    if all( [szargs{2:end}] == szargs{1} ) % On the diagonal?
        d( ii ) = 1;
    end
end

MATLABがダックタイピングを破る方法の良い例を示すための+1。
フィリップクラウド

1

再帰関数に作業を行わせることができます

  • しましょう L = size(M)
  • しましょう idx = zeros(L,1)
  • length(L)最大深度として取る
  • ループ for idx(depth) = 1:L(depth)
  • 深さがlength(L)である場合は、要素操作を実行します。それ以外の場合は、で関数を再度呼び出します。depth+1

すべてのポイントをチェックしたい場合はベクトル化されたメソッドほど速くはありませんが、それらのほとんどを評価する必要がない場合は、かなりの時間を節約できます。


1

これらのソリューションは、使用するよりも高速です(約11%)numel;)

for idx = reshape(array,1,[]),
     element = element + idx;
end

または

for idx = array(:)',
    element = element + idx;
end

UPD。最後の回答で検出されたエラーのtnx @ rayryeng


免責事項

この投稿が参照しているタイミング情報は、作成された基本的なタイプミスのために不正確で不正確です(以下のコメントストリームと編集履歴を参照してください-特にこの回答の最初のバージョンを見てください)。 警告エンプター


1
1 : array(:)と同等1 : array(1)です。これはすべての要素を反復するわけではないため、実行時間が速くなります。さらに、浮動小数点数をrand生成します。これを行うと、ステートメントが初期値が1で、終了値が1以外の範囲の浮動小数点数である増加ベクトルを見つけようとしているため、空の配列が生成されます。1.のステップ。そのような可能なベクトルはなく、結果として空のベクトルになります。あなたのループは実行されないので、あなたの主張は誤りです。-1票。ごめんなさい。1 : array(:)[0,1)for
rayryeng 2015

@rayryengあなたは正しくありません。array(:)は1:array(1)と同等ではありません。好きreshape(...)です。
mathcow 2015

@rayryeng matlab r2013a + linux-動作します!;)私もそのコードを実行しました
mathcow 2015

1 : array(:)作成後、コマンドプロンプトにonと入力しますarray 。空行列を取得しますか?はいの場合、コードは機能しません。あなたが虚偽の情報を提供しているので、私は投票を辞めます。
rayryeng 2015

@rayryengわかりました!はい、あなたは正しいです、愚かな論争をお詫びします
mathcow 2015

-1

他の用途をsize詳しく調べると、各次元のサイズのベクトルを実際に取得できることがわかります。このリンクは、ドキュメントを示しています。

www.mathworks.com/access/helpdesk/help/techdoc/ref/size.html

サイズベクトルを取得した後、そのベクトルを繰り返し処理します。このようなもの(大学以来Matlabを使用していないので構文を許してください):

d = size(m);
dims = ndims(m);
for dimNumber = 1:dims
   for i = 1:d[dimNumber]
      ...

これを実際のMatlab-legal構文にすると、あなたが望むことを実行できると思います。

また、ここで説明するように、線形インデックスを作成できるはずです


ループの順序が行列のすべての要素でどのように繰り返されるかはよくわかりません。たとえば、3行4列の行列(12要素)がある場合、内部ループは7回しか繰り返されません。
gnovice

マトリックスの各次元で反復する必要があります。外側のループはディメンションを反復処理し、内側のループはそのディメンションのサイズを反復処理します。少なくとも、それがアイデアです。他の誰もが述べているように、彼が望むのが各セルだけである場合、ライナーのインデックス付けが最適です。彼が各次元を反復したい場合、彼はこれと同様のことをしなければなりません。
Erich Mirabal

また、編集していただきありがとうございます。私のリンクはちょっと複雑で、通常のリンク方法では正しく機能しませんでした。また、私の声明を拡張するには、彼はまだインデックスの他の多くの追跡を行う必要があります(カウンターなどを使用して)。あなたやアンドリューのアプローチは、彼がやろうとしていることよりも簡単だと思います。
Erich Mirabal

-1

n-nestedforループをシミュレートしたいとします。

n次元配列を反復処理すると、n桁の数値が増加することがわかります。

各寸法には、寸法の長さと同じ数の桁があります。

例:

配列(行列)があるとします

int[][][] T=new int[3][4][5];

「表記法」では、次のようになります。

for(int x=0;x<3;x++)
   for(int y=0;y<4;y++)
       for(int z=0;z<5;z++)
          T[x][y][z]=...

これをシミュレートするには、「n桁の数値表記」を使用する必要があります

3桁の数字があり、1桁目は3桁、2桁目は4桁、3桁目は5桁です。

数を増やす必要があるので、シーケンスを取得します

0 0 0
0 0 1
0 0 2    
0 0 3
0 0 4
0 1 0
0 1 1
0 1 2
0 1 3
0 1 4
0 2 0
0 2 1
0 2 2
0 2 3
0 2 4
0 3 0
0 3 1
0 3 2
0 3 3
0 3 4
and so on

したがって、このようなn桁の数字を増やすためのコードを書くことができます。数値の任意の値から開始して、任意の数値で桁を増減できるようにすることができます。このようにして、テーブルのどこかで始まり、最後ではなく終了するネストされたforループをシミュレートできます。

ただし、これは簡単な作業ではありません。残念ながら、MATLAB表記は手伝うことができません。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.