MATLABで構造体の配列を事前に割り当てるにはどうすればよいですか?この例では、サイズが何度も変更されないように「a」を事前に割り当てたいと思います。
a = []
for i = 1:100
a(i).x = i;
end
MATLABで構造体の配列を事前に割り当てるにはどうすればよいですか?この例では、サイズが何度も変更されないように「a」を事前に割り当てたいと思います。
a = []
for i = 1:100
a(i).x = i;
end
使用するrepmat
ことは、構造体を事前に割り当てるための最も効率的な方法です。
N = 10000;
b = repmat(struct('x',1), N, 1 );
これは、Matlab 2011aを使用すると、次のようにインデックスを使用して事前に割り当てるよりも約10倍高速です。
N = 10000;
b(N).x = 1
インデックス作成方法は、事前割り当てを行わない場合よりもわずかに高速です。
No preallocation: 0.075524
Preallocate Using indexing: 0.063774
Preallocate with repmat: 0.005234
確認したい場合に備えて、以下のコードを使用してください。
clear;
N = 10000;
%1) GROWING A STRUCT
tic;
for ii=1:N
a(ii).x(1)=1;
end
noPreAll = toc;
%2)PREALLOCATING A STRUCT
tic;
b = repmat( struct( 'x', 1 ), N, 1 );
for ii=1:N
b(ii).x(1)=1;
end;
repmatBased=toc;
%3)Index to preallocate
tic;
c(N).x = 1;
for ii=1:N
c(ii).x(1)=1;
end;
preIndex=toc;
disp(['No preallocation: ' num2str(noPreAll)])
disp(['Preallocate Indexing: ' num2str(preIndex)])
disp(['Preallocate with repmat: ' num2str(repmatBased)])
コマンドウィンドウでの結果:
No preallocation: 0.075524
Preallocate Indexing: 0.063774
Preallocate with repmat: 0.0052338
>>
PS 誰かがそれを説明できれば、なぜこれが真実なのか知りたいです。
これについては、ArtofMATLABブログのLorenで素晴らしい議論があります。
私があなたを正しく理解しているなら、あなたが望む構造体を初期化する方法はここにあります:
a(100).x = 100;
この方法では、要素が空の配列で埋められていることがわかります。
構造を初期化する方法はたくさんあります。たとえば、次のstruct
コマンドを使用できます。
a(1:100) = struct('x',[]);
これにより、すべてのフィールドx
が空に設定されます。
deal
そこにどのデータを入れるべきかがわかっている場合は、構造を作成して埋めるために使用することもできます
xx = num2cell(1:100);
[a(1:100).x]=deal(xx{:});
a(99).x
ans =
99
または、もう一度使用することもできますstruct
(構造体のフィールドをセル配列にする必要がある場合は、セルを中括弧で囲む必要があります)。
a = struct('x',xx)
これが行われることになっている方法、そして最も簡単なのは
a=struct('x',cell(1,N));
欠落している「tic」を修正し、このメソッドをjeradによって提示されたベンチマークコードに追加すると、上記で提案したメソッドはrepmatよりも少し遅くなりますが、実装ははるかに簡単です。出力は次のとおりです。
No preallocation: 0.10137
Preallocate Indexing: 0.07615
Preallocate with repmat: 0.01458
Preallocate with struct: 0.07588
repmatが高速である理由は、各「x」フィールドの値が、空のままにするのではなく、事前割り当て中に割り当てられるためです。上記の事前割り当て手法が変更された場合は、次のように、値(1)が割り当てられたすべてのxフィールドから開始します。
a=cell(1,N);
a(:)={1};
d=struct('x',a);
次に、ベンチマークは大幅に改善され、repmatよりも非常に近いか、またはしばらく速くなります。違いは非常に小さいので、実行するたびにどちらが速いかが変わります。ここに出力例があります:
No preallocation: 0.0962
Preallocate Indexing: 0.0745
Preallocate with repmat: 0.0259
Preallocate with struct: 0.0184
逆に、次のように、repmatの事前割り当てを変更して、フィールドを空に設定した場合
b = repmat( struct( 'x', {} ), N, 1 );
すべての速度の利点が失われます
cell2structを使用することは、私が理解できる最も速い方法です。比較するには、次のコードを確認してください。
clear;
N = 10000;
cel2s=0;
repm=0;
for i=1:100
a=0.0; b=0.0;
tic;
a = cell2struct(cell(1,N), {'x'}, 1 );
cel2s = cel2s + toc;
tic;
b = repmat(struct('x',1), N, 1 );
repm = repm + toc;
end
disp(['cell2struct preallocation: ', num2str(cel2s/100)]);
disp(['repmat preallocation : ', num2str(repm/100)]);
disp(['speedup : ', num2str(fix( repm/cel2s ) ) , ' X']);
典型的な結果は、平均で約19倍のスピードアップを示しています。wrt repmatメソッド:
cell2struct preallocation: 1.4636e-05
repmat preallocation : 0.00028794
speedup : 19 X
この回答によると、それを行う別の方法もあります:
[a.x] = deal(val);
ここで、は構造体のすべてval
の要素に割り当てる値です。
このコマンドの効果は、x
すべての構造のすべてのフィールドに値a
が割り当てられるため、他のコマンドの効果とは異なりval
ます。
構造体の配列を事前に割り当てる代わりに、ループを逆にする方が簡単な場合があります。このようにして、配列は最初の反復で割り当てられ、残りの反復は構造体を埋めるために使用されます。
a = []
for i = 100:-1:1
a(i).x = i;
end