2016-05-19 12 views
2

のために、私は、次のループベクトル化するために願っています:ベクタライズ分()行列

for (i in 1:n) { 
    for (j in 1:m) { 
     temp_mat[i,j]=min(temp_mat[i,j],1); 
    } 
} 

を私はtemp_mat=min(temp_mat,1)を行うことができると思ったが、これは私の望ましい結果を与えていません。はるかに高速にするために、このループをベクトル化する方法はありますか?

答えて

10

temp_mat <- pmin(temp_mat, 1)を使用してください。パラレルミニマムの詳細については、?pminを参照してください。

例:あなたは計算科学のバックグラウンドを持っているので

set.seed(0); A <- matrix(sample(1:3, 25, replace = T), 5) 
#> A 
#  [,1] [,2] [,3] [,4] [,5] 
#[1,] 3 1 1 3 3 
#[2,] 1 3 1 2 3 
#[3,] 2 3 1 3 1 
#[4,] 2 2 3 3 2 
#[5,] 3 2 2 2 1 
B <- pmin(A, 2) 
#> B 
#  [,1] [,2] [,3] [,4] [,5] 
#[1,] 2 1 1 2 2 
#[2,] 1 2 1 2 2 
#[3,] 2 2 1 2 1 
#[4,] 2 2 2 2 2 
#[5,] 2 2 2 2 1 

更新

、私はより多くの情報を提供したいと思います。

pminは高速ですが、高性能ではありません。接頭辞「parallel」はelement-wiseを示唆しています。 Rの「ベクトル化」の意味は、HPCの「SIMDベクトル化」と同じではありません。 Rは解釈言語なので、Rの「ベクトル化」は、RレベルループではなくCレベルループを選択することを意味します。したがって、pminはちょっとしたCループでコーディングされています。

実際の高性能コンピューティングでは、SIMDのベクトル化が役立ちます。私はあなたがSSE/AVX組み込み関数を知っていると信じています。だから、のコードを書いてからSSE2を入力すると、pminから2倍のスピードアップが得られます。 AVXの_mm256_min_pdが表示されている場合、pminから〜4倍のスピードアップが得られます。

残念ながら、R自体はSIMDを実行できません。この問題に関しては、Does R leverage SIMD when doing vectorized calculations?の投稿への回答があります。ご質問の場合、HPC BLASにRをリンクしてもpminにはBLAS操作が含まれていないため、pminはSIMDの恩恵を受けません。コンパイルされたコードを自分で書く方が良いでしょう。

+0

私はそれはRが列優先であることとは何かを持っているとは思いません。 'pmin'は渡された項目間の要素的な最小値を返します。そのため、1は同じ次元のオブジェクトに強制的に変換されます。たとえば、異なるサイズベクトルが渡された場合、リサイクルされる要素についての警告が表示されます。 – Gabe

+2

OPが要求したものではありませんでしたが、Rで大規模並列計算を実現するにはいくつかの方法があります。例としては、 'snow'、' multicore'、 'foreach'、' Rmpi​​'、 'Rth'、' gputools'パッケージと、これまでに別々のパッケージのいくつかを統合した 'parallel'のパッケージがあります。このトピックの最新技術については、[参考文献](https://books.google.com/books/about/Parallel_Computing_for_Data_Science.html?id=SsbECQAAQBAJ)をご覧ください。 – RHertel

+0

"たとえば、OPの問題はこのフォームの恩恵を受けることはできません。メモリにバインドされているため、複数のスレッドを設定すると速度が低下します。どうして?並列プログラミングでは、マトリックスを別々のチャンクに分割し、それぞれを別々のスレッドで処理させるのが標準タスクではないでしょうか?この場合、スレッド間で通信する必要はありません。これは私には恥ずかしいほど平行な状況の標準的な例のようで、Rで簡単に扱うことができます。 – RHertel

4

min()がベクトル化されているため、少し混乱します。この特定の場合に望ましい結果を得るためには、この関数を使う必要はありません。 論理サブセットは、おそらくより効率的な(そしてもっとコンパクトな)代替手段を提供します。

私が正しくあなたの所望の出力を理解している場合、あなたのコード内でネストされたループを実行した場合と同様に、マトリックスの変更は、単一のコマンドで実現することができるに:

temp_mat[temp_mat > 1] <- 1 

は、この情報がお役に立てば幸いです。


set.seed(123) 
temp_mat <- matrix(2*runif(50),10) 
#> temp_mat 
#   [,1]  [,2]  [,3]  [,4]  [,5] 
# [1,] 0.5751550 1.91366669 1.7790786 1.92604847 0.2856000 
# [2,] 1.5766103 0.90666831 1.3856068 1.80459809 0.8290927 
# [3,] 0.8179538 1.35514127 1.2810136 1.38141056 0.8274487 
# [4,] 1.7660348 1.14526680 1.9885396 1.59093484 0.7376909 
# [5,] 1.8809346 0.20584937 1.3114116 0.04922737 0.3048895 
# [6,] 0.0911130 1.79964994 1.4170609 0.95559194 0.2776121 
# [7,] 1.0562110 0.49217547 1.0881320 1.51691908 0.4660682 
# [8,] 1.7848381 0.08411907 1.1882840 0.43281587 0.9319249 
# [9,] 1.1028700 0.65584144 0.5783195 0.63636202 0.5319453 
#[10,] 0.9132295 1.90900730 0.2942273 0.46325157 1.7156554 
temp_mat[temp_mat > 1] <- 1 
#> temp_mat 
#   [,1]  [,2]  [,3]  [,4]  [,5] 
# [1,] 0.5751550 1.00000000 1.0000000 1.00000000 0.2856000 
# [2,] 1.0000000 0.90666831 1.0000000 1.00000000 0.8290927 
# [3,] 0.8179538 1.00000000 1.0000000 1.00000000 0.8274487 
# [4,] 1.0000000 1.00000000 1.0000000 1.00000000 0.7376909 
# [5,] 1.0000000 0.20584937 1.0000000 0.04922737 0.3048895 
# [6,] 0.0911130 1.00000000 1.0000000 0.95559194 0.2776121 
# [7,] 1.0000000 0.49217547 1.0000000 1.00000000 0.4660682 
# [8,] 1.0000000 0.08411907 1.0000000 0.43281587 0.9319249 
# [9,] 1.0000000 0.65584144 0.5783195 0.63636202 0.5319453 
#[10,] 0.9132295 1.00000000 0.2942273 0.46325157 1.0000000