構造体のMatlab配列:高速割り当て

structの配列を "ベクトル化"する方法はありますか?

現在、私はできる

edges(1000000) = struct('weight',1.0); //This really does not assign the value, I checked on 2009A.
for i=1:1000000; edges(i).weight=1.0; end; 

しかし、それは遅いです、私はもっと何かをしたいです

edges(:).weight=[rand(1000000,1)]; //with or without the square brackets. 

この割り当てをベクトル化するためのアイデアや提案は、より速くなるようにします。

前もって感謝します。

11
この投稿は役に立ちました: stackoverflow.com/questions/4166438/…
追加された 著者 Amro,

6 答え

これは、取引やループよりもはるかに高速です(少なくとも私のシステムでは):

N=10000;
edge(N) = struct('weight',1.0); % initialize the array
values = rand(1,N);  % set the values as a vector

W = mat2cell(values, 1,ones(1,N)); % convert values to a cell
[edge(:).weight] = W{:};

右側の中括弧を使用すると、Wのすべての値(つまりN個の出力)のカンマ区切り値リストが得られ、右側の角かっこを使用すると、N個の出力がエッジ(:)のN値に割り当てられます。

13
追加された
ニース!合理的かつ実用的な! Matlabの構文で配列を '{values} {:}'のような引数配列に展開することができればいいですね。セルの値リストを取得する機能を試しましたが、明らかに deal()と同じように varargout に割り当てるのは嫌いです。
追加された 著者 eacousineau,
Whoops、 num2cell()の代わりに mat2cell()を使用していました。関数は次のとおりです: cellexpand()
追加された 著者 eacousineau,
匿名ハンドルも使用できます。 cellexpand = @(x)x {:}; numexpand = @(x)cellexpand(num2cell(x)); 例: [a、b] = numexpand([1、2]); より具体的な例: [edge.weight] = numexpand([edge.weight] + 50);
追加された 著者 eacousineau,

Matlab関数を使用してみることができます。 deal しかし、私は入力を少し微調整する必要があることを発見しました(この質問を使用します:

9
追加された
素晴らしいよ、ありがとう。
追加された 著者 sumodds,
これらは私の時代です。オクターブの場合:この方法では100Kと.170Mの場合は.17s、100Kの場合は230sのようにforループを使用すると永遠になります。 MATLAB 2009B(差分マシン/ OS):前述のものを使用して5秒/ 49秒、forループを使用して0.22秒/ 2.2秒。
追加された 著者 sumodds,

あなたは単に書くことができます:

edges = struct('weight', num2cell(rand(1000000,1)));
7
追加された

このように構造体を特に使用する必要があるのでしょうか?

構造体の配列を、構造体の各メンバーごとに別々の配列に置き換えることを検討してください。

weights = rand(1, 1000);

構造体メンバが配列の場合、余分な次元を作ることができます:

matrices = rand(3, 3, 1000);

物事をきちんと保つだけなら、これらの配列を構造体に入れることができます:

edges.weights = weights;
edges.matrices = matrices;

しかし、構造体の配列を保持する必要がある場合、私はあなたができると思う

[edges.weight] = rand(1, 1000);
2
追加された
違いは、Matlabでは、各構造体がそれぞれのフィールドを別々の配列に格納するため、構造体の配列( "struct-organized")は非常に非効率的であるため、ベクトル化された操作はできません。ブライアンのような配列の構造体( "planar-organized")は、各フィールドをメモリ内で連続したプリミティブ配列に格納し、ベクトル化された(高速の)Matlab関数で動作します。これはMatlabの方がはるかに優れた構造であり、より慣用的です。
追加された 著者 Andrew Janke,
両方とも同じです。しかし、私は配列の構造体ではなく、構造体の配列(配列のオブジェクトを意味する)である必要があると思います(大きな配列の単一の大きな構造体)。 MATLABの2つの違いは何ですか?ありますか?メモリの割り当てを意味し、もしそうなら、その意味は何か?
追加された 著者 sumodds,
とにかく、ありがとう。 :)
追加された 著者 sumodds,

あなたの例の構造体が適切に初期化されない理由は、使用している構文が構造体配列の最後の要素のみを扱うためです。存在しない配列の場合、残りの部分は暗黙のうちにすべてのフィールドにデフォルト値 [] を持つ構造体で埋められます。

この動作を明確にするには、 clear edgesを使用して短い配列を試してください。 edges(1)edges(2)、および edge(1:3)= struct( 'weight'、1.0) code> edges(3)をクリックします。 edges(3)要素のウェイトは 1.0 です。他は [] を持っています。

構造体の配列を効率的に初期化するための構文は、これらのうちの1つです。

% Using repmat and full assignment
edges = repmat(struct('weight', 1.0), [1 1000]);

% Using indexing
% NOTE: Only correct if variable is uninitialized!!!
edges(1:1000) = struct('weight', 1.0);  % QUESTIONABLE

初期化されていないエッジ配列にインデックスを付けるときは 1000 ではなく 1:1000 に注意してください。

edges(1:1000)フォームに問題があります。 edges が既に初期化されている場合、この構文は選択された要素の値を更新します。エッジの要素数が1000を超える場合、残りの要素は変更されず、コードはバグになります。または、 edges が異なるタイプの場合、既存のデータ型に応じてエラーまたは奇妙な動作が発生する可能性があります。安全のためには、インデックス構文を使用して初期化する前にエッジをクリアする必要があります。だから、 repmat フォームを使って完全に代入する方が良いでしょう。

BUT: Regardless of how you initialize it, an array-of-structs like this is always going to be inherently slow to work with for larger data sets. You can't do real "vectorized" operations on it because your primitive arrays are all broken up in to separate mxArrays inside each struct element. That includes the field assignment in your question – it is not possible to vectorize that. Instead, you should switch a struct-of-arrays like Brian L's answer suggests.

1
追加された

逆構造体を使用して、エラーなくすべての操作を実行できます このような

x.E(1)=1;
x.E(2)=3;
x.E(2)=8;
x.E(3)=5;

次に、以下のような操作

x.E

ans =

    3     8     5

またはこのように

x.E(1:2)=2

x = 

    E: [2 2 5]

またはこれかもしれない

x.E(1:3)=[2,3,4]*5

x = 

    E: [10 15 20]

for_loopよりも速く、プログラムを遅くするために他の大きな機能は必要ありません。

0
追加された