2009-04-23 9 views
14

マトリックス(myPointMatrix)にn次元点(n> 1)を挿入するMATLABコードがあり、最初の点を挿入する方法について考えています。空のMATLAB行列にベクトルを追加する

ポイントを挿入する前に、プログラムはmyPointMatrixのサイズをチェックします。 1x1の場合、myPointMatrixは現在のポイントに等しく設定されます。それ以外の場合は、現在のポイントが追加されます。このifは、一度だけ真実ですが、ポイントを挿入するたびに評価されます。非常に頻繁に使用されます。

ifを削除し、myPointMatrixに追加しようとすると、MATLABは行列の次元が一貫していないと不平に不満を持ちます。 ifステートメントとmyPointMatrix = 0のイニシャル化の両方を削除すると、MATLABはmyPointMatrixが未定義であると判断します。また理解できる。

myPointMatrixを初期化するにはどうすればifの記述を削除できますか?または、他にもスマートなソリューションがありますか?

myPointMatrix = 0; 
for x=0:limit 
    for y=0:limit 
     for z=0:limit 
      tempPoint = [x y z]; 
      if (length(myPointMatrix) == 1) 
       myPointMatrix = tempPoint; 
      else 
       myPointMatrix = [myPointMatrix; tempPoint]; 
      end 
     end 
    end 
end 

答えて

13

myPointMatrix = [];を使用してマトリックスを初期化します。

大きいほどmyPointMatrixは、より遅く追加されます。ポイントを追加するたびに、新しいサイズの新しいマトリックスが割り当てられ、古いマトリックスから新しいポイントまでの情報が新しいマトリックスにコピーされるので、遅くなり、遅くなります。

MyPointMatrixを最終サイズで初期化し、ポイントをマトリックスの所定の位置に挿入する方が良いです。

+2

+1最後の文章です。それがMATLABの行列を初期化する最も効率的な方法です。 –

3

最良の選択肢は、マトリックスを事前に配置してループ変数を使用することです。これははるかに速くなければなりません。

limit = 9; 
myPointMatrix = nan((limit+1)^3,3); 

loopVar = 1; 
for x=0:limit 
    for y=0:limit 
     for z=0:limit 
      myPointMatrix(loopVar,:) = [x y z]; 
      loopVar = loopVar + 1; 
     end 
    end 
end 
0

私はその後、最初に割り当て

myPointMatrix = [myPointMatrix; tempPoint]; 

が正しく動作しますつまり

myPointMatrix = zeros(0, 3); 

、あなたが探している溶液を0行と3列の行列にmyPointMatrixを初期化することであると信じて、それに続くものも含まれます。割り当てを書くための同等の方法が

myPointMatrix(end+1,:) = tempPoint; 

しかしそのようなマトリックスの成長よりも、心に留めておくが、IFS最終的なサイズでmyPointMatrixを初期化し、アンナルが言うように、効率的ではないが、知られている場合は、よりよい解決策です。

28

行列やベクトルを任意の行列に追加する方法はいくつかありますが、空でもそうでもありません。多くは、マトリックスのサイズと追加回数によって異なります。 (希薄な行列はまったく別の動物であり、別々に扱う必要があることに注意してください。)

単純な方式では連結を使用します。たとえば、ランダムな配列を作成します。私はrandへの呼び出しがここでは適切な解決策になることを知っていますが、私はそれを比較目的のためだけにしています。

n = 10000; 
tic 
A = []; 
for i = 1:n 
    Ai = rand(1,3); 
    A = [A;Ai]; 
end 
toc 

Elapsed time is 9.537194 seconds. 

必要な時間が相当に長く、私がrandを直接呼び出したよりもはるかに多いことがわかります。

tic,rand(n,3);toc 
Elapsed time is 0.008036 seconds. 

追加する他の方法も同様です。たとえば、索引付けを追加することもできます。

A = []; 
A(end+1,:) = rand(1,3); 
A 
A = 
     0.91338  0.63236  0.09754 

これは、連結を介して追加するのに似ています。興味深いことに、新しい行を配列に追加することは、新しい列を追加することと微妙に異なります。列よりも行を追加するのに少し時間がかかります。これは、要素がMATLABに格納される方法のためです。新しい行を追加すると、要素が実際にメモリ内でシャッフルされなければならないことを意味します。

A = zeros(10000,3); 
B = zeros(3,10000); 

tic,for i = 1:100,A(end+1,:) = rand(1,3);end,toc 
Elapsed time is 0.124814 seconds. 

tic,for i = 1:100,B(:,end+1) = rand(3,1);end,toc 
Elapsed time is 0.116209 seconds. 

任意の追加操作に問題は全くMATLABは、Aのために必要なメモリを再割り当てし、その行列のサイズが大きくなるたびに、しなければならないということです。 Aのサイズは線形に増加するので、必要な全体の時間はnで2次的に増加します。私たちはnのサイズを2倍にしました。動的に成長したAは、構築するのに4倍の時間がかかります。この二次的な振る舞いは、MATLAB配列が動的に拡張されるときにMATLAB配列を事前に割り当てるように指示する理由です。実際に、エディタでmlintフラグを見ると、MATLABはこれを見てあなたに警告します。

Aの最終的なサイズを知っていれば、Aを最終的なサイズにあらかじめ割り当てることをお勧めします。これは、動的に成長し、アレイよりもはるかに優れているが、その後。

tic 
A = zeros(n,3); 
for i = 1:n 
    A(i,:) = rand(1,3); 
end 
toc 

Elapsed time is 0.156826 seconds. 

でちょうどインデックスが、それはまだランドのベクトル化の使用よりもはるかに悪いです。可能な限り、このような関数のベクトル化された形式を使用してください。

問題は、最終的にいくつの要素が残っているか分かりません。不快な二次的な成長を避けるために使用できるいくつかのトリックはまだあります。

最後に、Aの最終サイズを推測することです。インデックス作成を使用して新しい値をAに挿入しますが、新しいエントリがAの境界を超えて流出するときは注意してください。起こるには、Aのサイズを倍にして、最後に1つの大きなブロックのゼロを付け加えます。今度は、新しい要素をAに索引付けすることに戻ります。追加された要素の数を別々にカウントしてください。このプロセスの最後に、未使用の要素を削除します。これにより、いくつかの追加ステップしか実行されないので、不快な二次的な振る舞いの多くを回避します。 (あなたが追加をしなければならないときは、Aのサイズを2倍にしていることを覚えておいてください)。

2番目のトリックはポインタを使用することです。 MATLABは実際にポインタの方法で多くの機能を提供するわけではありませんが、セル配列はその方向の一歩です。

tic 
C = {}; 
for i = 1:n 
    C{end+1} = rand(1,3); 
end 
A = cat(1,C{:}); 
toc 

Elapsed time is 3.042742 seconds. 

これは、成長したアレイよりも短い時間で完了しました。どうして?私たちは、細胞へのポインタの配列を構築していました。これについての良いことは、各追加ステップに行数が可変であれば、それでもうまくいきます。

セル配列に問題があります。追加する要素が何百万個ある場合は、それほど効率的ではありませんか?なぜなら、各ステップでポインタの配列を増やしているからです。

この問題の解決策は、上記の2つのスタイルのアマルガムを使用することです。したがって、セルアレイの各セルを適度に大きく定義する。今度はインデックス作成を使ってAの新しい行をセルに入れる。現在のセルを次の追加ステップで大きくしなければならない場合は、新しいセルをセル配列に追加するだけです。

数年前、この議論がMATLABニュースグループで行われ、これらの行に沿ったいくつかの解決策が提案されました。私は、growdata & growdata2というソリューションをMATLAB Central File Exchange上のファイルとして投稿しました。 Growdata2は関数ハンドルを使用して問題を解決しました。

tic 
Ahandle = growdata2; 
for i = 1:n 
    Ahandle(rand(1,3)) 
end 
% unpack the object into a normal array 
A = Ahandle(); 
toc 

Elapsed time is 1.572798 seconds. 

当時、永続変数を使用するのはやや高速でした。

tic 
growdata 
for i = 1:n 
    growdata(rand(1,3)) 
end 
A = growdata; 
toc 

Elapsed time is 2.048584 seconds. 

それ以来、関数ハンドルの実装はMATLABでは明らかに改善されているため、関数ハンドルがより高速になりました。

これらのスキームの利点は、数百万の追加ステップを可能にしながら、二次的なパフォーマンスのペナルティを持たないことです。

まあ、これは、質問がされたときに最初に要求されたよりも確かに多くの情報です。多分誰かがそれから何かを得るでしょう。

0

これは、あなたが

myPointMatrix=[]; 
for x=0:limit 
for y=0:limit 
for x=0:limit 
    myPointMatrix(:,end+1)=[x y z]; 
end 
end 
end 

だけあなたがそれを割り当てる前に、[X用のy z]はといくつかの非線形動作を行う場合に必要なものです。その後、次のように上記の行を書くことができない場合は、次のいずれかがedit kron.mにしたいとlogicalでいくつかのfindを置き換えるかもしれませんが

myPointMatrix=[]; 
myPointMatrix(1,:)=kron([1:limit],ones(1,limit^2)); 
myPointMatrix(2,:)=kron([1:limit^2],ones(1,limit)); 
myPointMatrix(3,:)=kron(ones(1,limit^2),[1:limit]); 

上記完全に、ベクトル化されています...しかし、あなたはあなた自身私が思うことを行うことができます。.. 。:D

0
%appending to matlab array "f": 

lfg=[697 770 852 941]; 
hfg=[1209 1336 1477]; 
f=[]; 
for i=1:4, 
    for j=1:3, 
     %f = [ f [lfg(i);hfg(j)] ]; 
     append(f , [lfg(i);hfg(j)]); 
    end 
end 
f 
関連する問題