web-dev-qa-db-ja.com

行に対して行列を反復するための推奨される方法は何ですか?

与えられた行列m = [10i+j for i=1:3, j=1:4]、行列をスライスすることで行を反復できます。

for i=1:size(m,1)
    print(m[i,:])
end

これが唯一の可能性ですか?お勧めの方法ですか?

そして、理解はどうですか?スライスすることは、行列の行を反復する唯一の可能性ですか?

[ sum(m[i,:]) for i=1:size(m,1) ]
43
Nico

自分でリストしたソリューションとmapslicesはどちらも正常に機能します。しかし、「推奨」が本当に意味するのが「高性能」である場合、最善の答えは、行を反復しないことです。

問題は、配列が列優先で格納されているため、小さな行列以外の場合は、行優先で配列をトラバースすると キャッシュヒット率 になってしまうことです。

優れたブログ投稿 で指摘されているように、行を合計したい場合、最善の策は次のようなことです。

_msum = zeros(eltype(m), size(m, 1))
for j = 1:size(m,2)
    for i = 1:size(m,1)
        msum[i] += m[i,j]
    end
end
_

ネイティブストレージ順でmmsumの両方をトラバースするため、キャッシュラインをロードするたびにすべての値を使用し、キャッシュヒット率を1にします。行優先順でトラバースして結果をtmp変数に累積しますが、最近のマシンでは、キャッシュミスは_msum[i]_ルックアップよりもはるかにコストがかかります。

sum(m, 2)のようなregionパラメータを取るJuliaの内部アルゴリズムの多くは、これを処理します。

52
tholy

Julia 1.1以降、行列の列または行を反復するための反復ユーティリティがあります。行を反復するには:

M = [1 2 3; 4 5 6; 7 8 9]

for row in eachrow(af)
    println(row)
end

出力されます:

[1, 2, 3]
[4, 5, 6]
[7, 8, 9]
8
Seanny123

私の経験によれば、明示的な反復は内包よりもはるかに高速です。

また、列を反復処理することも良いアドバイスです。

さらに、新しいマクロ@simdおよび@inboundsを使用して、さらに高速化できます。

3
Sisyphuss