3

私はMatlabで書いた動的にメモリを行列に割り当てるスクリプトを高速化しようとしています(基本的に、ファイルからデータの行を読み取り、それを行列に書き込み、次に別の行を読み取り、より大きな行列に多くのメモリを割り当てます)次の行を保存します)。zeroes() などを使用してメモリを事前に割り当てる代わりにこれを行った理由は、すべてのデータを保持するために行列が必要とする正確なサイズがわからないためです。また、マトリックスの最大サイズがわからないため、最大サイズを事前に割り当ててから、使用しなかったメモリを取り除くことはできません。これは少量のデータには問題ありませんでしたが、今ではスクリプトをスケールアップして何百万ものデータ ポイントを読み取る必要があり、この動的割り当ての実装は遅すぎます。

スクリプトを高速化するための試みは次のとおりです。ゼロ関数を使用して大きなブロックにメモリを割り当てようとしました。ブロックがいっぱいになると、別の大きなブロックを割り当てます。サンプルコードは次のとおりです。

data = [];   
count = 0;

for ii = 1:num_filelines    
   if mod(count, 1000) == 0  
       data = [data; zeroes(1000)];  %after 1000 lines are read, allocate another 1000 line
   end  
   data(ii, :) = line_read(file);  %line_read reads a line of data from 'file'
end

残念ながら、これは機能しません。実行すると、「連結されている行列の vertcat ディメンションの使用中にエラーが発生しました」というエラーが表示されます。

だからここに私の質問があります:大きなブロックにメモリを割り当てるこの方法は、実際には増分動的割り当てよりも高速ですか?また、上記のコードが実行されないのはなぜですか? 助けてくれてありがとう。

4

3 に答える 3

4

私がお勧めすることは、行数を知っていて、許容可能な列の数が十分に大きいと推測できる場合は、sparse matrix.

% create a sparse matrix
mat = sparse(numRows,numCols)

スパース行列はすべてのゼロ要素を保存するわけではなく、ゼロ以外のインデックスへのポインターのみを保存します。これにより、多くのスペースを節約できます。これらは、他のマトリックスと同じように使用およびアクセスされます。それは、最初からマトリックス形式で本当に必要な場合のみです。

そうでない場合は、すべてを として行うことができますcellcell arrayファイル内の行と同じ数の要素を事前に割り当てます。

data = cell(1,numLines);
% get matrix from line
for i = 1:numLines
    % get matrix from line
    data{i} = lineData;
end
data = cell2mat(data);

このメソッドは、すべてをセル配列に入れ、「動的」に格納してから通常の行列に変換できます。

添加

疎行列法を実行している場合、完了後に行列をトリミングするには、行列が必要以上に大きくなる可能性があるため、これを簡単にトリミングしてから通常の行列にキャストできます。

[val,~] = max(sum(mat ~= 0,2));
mat(:,val:size(mat,2)) = [];
mat = full(mat); % use this only if you really need the full matrix

これにより、不要な列が削除され、0 要素を含む完全な行列にキャストされます。完全なマトリックスにキャストすることはお勧めしません。これにはさらに多くのスペースが必要ですが、本当に必要な場合は使用してください。

アップデート

ファイル内の行数を簡単に取得するには、MATLAB の perl インタープリターを使用します

というファイルを作成し、countlines.pl下の 2 行に貼り付けます

while (<>) {};
print $.,"\n";

次に、次のようにファイルでこのスクリプトを実行できます

numLines = str2double(perl('countlines.pl','data.csv'));

問題が解決しました。

ここの MATLAB フォーラム スレッドから

技術的には、特に大きなファイルの場合、shai の方法を実行すると大量の再割り当てが行われるため、事前にすべてを事前に割り当てることが常に最善であることを覚えておいてください。

于 2013-08-05T14:36:20.063 に答える
1

エラーを解決するには、割り当て時にこの構文を使用するだけです

data = [data; zeroes(1000, size(data,2))];

ループの外側の最初の行を読みたいと思うかもしれませんdata.

于 2013-08-05T14:39:45.153 に答える
0

書かれたコードに固執したい場合は、データの初期化を代用しますdata = []

data = zeros(1,1000); 

@MZimmerman6 からの警告: zeros(1000)1000 x 1000 の配列が生成されることに注意してください。zerosすべてのステートメントをに変更したい場合がありますzeros( ... ,Nc)。ここで、Nc = 行の長さ (文字数)。

于 2013-08-06T11:33:11.467 に答える