行列の列を反復処理する最良の方法は何ですか?
-
03-07-2019 - |
質問
MATLABを使用して、行列内のすべての列に関数を適用します。たとえば、マトリックスをベクトルとしてスムーズに扱うのではなく、マトリックスのすべての列でスムーズを呼び出すことができます( smooth(matrix)
を呼び出す場合のデフォルトの動作です) )。
これを行うためのより慣用的な方法があるはずですが、見つけられないため、 map_column
関数を定義しました:
function result = map_column(m, func)
result = m;
for col = 1:size(m,2)
result(:,col) = func(m(:,col));
end
end
次のように呼び出すことができます:
smoothed = map_column(input, @(c) (smooth(c, 9)));
このコードには何か問題がありますか?どうすれば改善できますか?
解決
あなたの解決策は問題ありません。
horizcatは、大きな行列に対してかなりのパフォーマンスペナルティを課すことに注意してください。コードをO(N)ではなくO(N ^ 2)にします。 100x10,000マトリックスの場合、私のマシンでの実装には2.6秒かかりますが、horizcatの実装には64.5秒かかります。 100x5000マトリックスの場合、horizcatの実装には15.7秒かかります。
必要に応じて、関数を少し一般化し、最終的な次元または任意の次元(列だけでなく)で反復できるようにすることができます。
他のヒント
MATLAB" for"ステートメントは実際に提供されているものの列をループします-通常、forに渡されるベクトル(上記の例のように)は行ベクトルなので、これは単にスカラーのシーケンスになります。つまり、上記のコードを次のように書き換えることができます。
function result = map_column(m, func)
result = [];
for m_col = m
result = horzcat(result, func(m_col));
end
funcが列ベクトルを返さない場合、次のようなものを追加できます
f = func(m_col);
result = horzcat(result, f(:));
列に強制的に挿入します。
おそらく、 '演算子でマトリックスを変換してから、結果を元に戻すことができます。
smoothed = smooth(input', 9)';
少なくともfft関数で動作します。
行列の列で暗黙的なループを発生させる方法は、cellfunを使用することです。つまり、最初に行列をセル配列に変換する必要があります。各セルには1列が保持されます。次に、cellfunを呼び出します。例:
A = randn(10,5);
ここで、各列の標準偏差を計算しました。
cellfun(@std,mat2cell(A,size(A,1),ones(1,size(A,2))))
ans =
0.78681 1.1473 0.89789 0.66635 1.3482
もちろん、MATLABの多くの関数は、ユーザーが示すように、配列の行または列で動作するように既に設定されています。これはもちろんstdにも当てはまりますが、これは cellfun
が正常に機能したことをテストする便利な方法です。
std(A,[],1)
ans =
0.78681 1.1473 0.89789 0.66635 1.3482
大きな行列を扱う場合は、結果の行列を事前に割り当てることを忘れないでください。そうしないと、CPUは新しい行/列を追加するたびに行列の再割り当てを繰り返し多くのサイクルを費やします。
これが関数の一般的なユースケースである場合、入力がベクトルではない場合、列を介して関数を自動的に反復処理することをお勧めします。
これはあなたの問題を正確に解決するわけではありませんが、関数の使用法を単純化します。その場合、出力もマトリックスである必要があります。
m(:, :) = m(:)
を使用して、マトリックスを1つの長い列に変換することもできます。ただし、これが意味をなすかどうかは、関数に依存します。