「マルチコア」を使用するためにRスクリプトを最適化する方法


15

4 CPUのUbuntu-Lucid PCでGNU Rを使用しています。4つのCPUをすべて使用するために、「r-cran-multicore」パッケージをインストールしました。パッケージのマニュアルには理解できる実用的な例がないため、4つのCPUをすべて使用するためにスクリプトを最適化する方法についてアドバイスが必要です。

私のデータセットは、50,000行と1600列のdata.frame(P1と呼ばれます)です。行ごとに、最大値、合計値、平均値を計算します。私のスクリプトは次のようになります。

p1max <- 0
p1mean <- 0
p1sum <-0
plength <- length(P1[,1])
for(i in 1:plength){
   p1max <- c(p1max, max(P1[i,]))
   p1mean <- c(p1mean, mean(P1[i,]))
   p1sum <- c(p1sum, sum(P1[i,]))
}

4つのCPUをすべて使用するために、スクリプトを変更して実行する方法を教えてください。


上記のプログラムにエラーがあります。行は「for(i in 1:plength)」である必要があります
サイモンバーン

あなたは元気です、thx!
プロドニス

1
これはStackOverflowに属していませんか?
R_Coholic

1
これはStackOverflowに属します。ここには統計に関する質問はまったくありません。一般的なプログラミングの質問のみ。
JDロング

回答:


11

foreachdoMCを使用します。詳細な説明はこちらにあります。スクリプトはほとんど変わりません。

for(i in 1:plength){

に変更する必要があります

foreach(i=1:plength) %dopar% { 

これらのパッケージを使用するマルチタスクスクリプトの前提条件は次のとおりです。

library(foreach)
library(doMC)
registerDoMC()

注意の注意。ドキュメントによると、GUIでこれを使用することはできません。

あなたの問題に関しては、本当にマルチタスクが必要ですか?data.frameは約1.2GBのRAMを必要とするため、メモリに収まるはずです。したがって、単にapplyを使用できます。

p1smry <- apply(P1,1,summary)

結果は、各行の要約を含むマトリックスになります。

パッケージマルチコアにある関数mclapplyを使用することもできます。次に、スクリプトは次のようになります。

loopfun <- function(i) {
     summary(P1[i,])
}

res <- mclapply(1:nrow(P1),loopfun)

これはリストを返します。i番目の要素はi番目の行の要約になります。sapplyを使用してマトリックスに変換できます

mres <- sapply(res,function(x)x)

どうもありがとうございました。あなたは正しい、「適用」でスクリプトを最適化できた。メッセージを伝えるために最小限の例としてスクリプトを使用しました...たくさん、あなたの答えはまさに私が探していたものです!!
プロデュニス

15

複数のコアを使用する方法については既に回答がありますが、実際の問題はループの記述方法にあります。ループの各反復で結果ベクトル/オブジェクトを拡張しないでください。これを行うと、Rに結果のベクトル/オブジェクトをコピーさせ、それを拡張するよう強制します。代わりに、ループを開始する前に十分なストレージスペースを事前に割り当てて、作業を進めてください。以下に例を示します。

set.seed(1)
p1 <- matrix(rnorm(10000), ncol=100)
system.time({
p1max <- p1mean <- p1sum <- numeric(length = 100)
for(i in seq_along(p1max)){
   p1max[i] <- max(p1[i,])
   p1mean[i] <- mean(p1[i,])
   p1sum[i ]<- sum(p1[i,])
}
})

   user  system elapsed 
  0.005   0.000   0.005

または、次の方法でこれらを実行できますapply()

system.time({
p1max2 <- apply(p1, 1, max)
p1mean2 <- apply(p1, 1, mean)
p1sum2 <- apply(p1, 1, sum)
})
   user  system elapsed 
  0.007   0.000   0.006 

ただし、これはループを適切に実行するよりも速くはなく、時には遅くなることに注意してください。

ただし、ベクトル化されたコードには常に注意を払ってください。あなたは使用して行和と手段を行うことができますrowSums()し、rowMeans()どのループまたはいずれよりも速くしているapplyバージョン:

system.time({
p1max3 <- apply(p1, 1, max)
p1mean3 <- rowMeans(p1)
p1sum3 <- rowSums(p1)
})

   user  system elapsed 
  0.001   0.000   0.002 

私が賭け人である場合foreach()、マトリックスの速度テストでのビートまたは他のマルチコアオプションについて言及した3番目のアプローチにはお金があります。異なるCPUコアからファームアウトされた個別のプロセス。

更新:@shabbychefからのコメントに従って、一度合計を行って平均の計算に再利用する方が速いですか?

system.time({
    p1max4 <- apply(p1, 1, max)
    p1sum4 <- rowSums(p1)
    p1mean4 <- p1sum4 / ncol(p1)
    })

   user  system elapsed 
  0.002   0.000   0.002

この試運転ではありませんが、これは徹底的なものではありません...


FWIW、Matlabは事前割り当てと拡張ベクトルに関して同じ問題を抱えており、古典的なコード「blooper」です。賭け金に加えて、それはおそらくより高速の結果を使用することですrowSums(私はに関する何かが欠けていない限り、行手段を計算するために、例えばナトリウムまたはNaN)。3番目のアプローチのコードは、各列を2回合計します。
みすぼらしいシェフ

@shabbychefびっくりするでしょう(編集済みの回答をご覧ください)。はい和が、概念的二回計算されますが、rowSumsrowMeans非常にコンパイルされたコードと、私たちが一度だけの合計を計算する際にゲインを最適化されて、我々は解釈コードで平均計算を行う際に再び失います。
モニカの復活-G.シンプソン

@Gavin Simpson:それほど速くない:代わりsystem.time({ for (iii in c(1:1000)) { p1max3 <- apply(p1, 1, max) p1mean3 <- rowMeans(p1) p1sum3 <- rowSums(p1) } })に同じように試してくださいsystem.time({ for (iii in c(1:1000)) { p1max4 <- apply(p1, 1, max) p1sum4 <- rowSums(p1) p1mean4 <- p1sum4 / ncol(p1) } })。合計を再計算しないバージョンでは、コンピューターで1.368秒かかります。行うのは1.396です。再び、徹底的ではありませんが、より説得力のある...
shabbychef

私たちがあるか、説得力はない;-)実際には何にさまざまなアイデアを持っている必要があります@shabbychef、あなたのより厳密なシミュレーションがようことを、私の主なポイントを強化rowMeansし、rowSums彼らはビートすることは困難であることを行っている、効率的、最適化されたコンパイルされたコードで実装されています。
復帰モニカ-G.シンプソン

@ギャビンシンプソン。実際、私の例の問題は、最大値を計算するために適用部分でほとんどの時間がかかることです。のようなcベースのベクトル化された関数は、のようなrowMean汎用Rツールを介して勝つのは難しいだろうということに同意します*apply。ただし、1回だけでなく1回ではなく2回で 10000の数値を合計しrowMeanrowSumRの組み込み除算演算子を使用する方が速いことを示唆しているようです。Rにはいくつかの効率性の問題(例えば、最近の中括弧と括弧の問題が発見された)がありますが、それはおかしいようです。
みすぼらしいシェフ

1

見ていた雪降雪のパッケージを。それらの例がたくさん...

Rと並列処理について学習するのではなく、特定のコードを高速化する場合は、これを行う必要があります

P1 = matrix(rnorm(1000), ncol=10, nrow=10
apply(P1, 1, max)
apply(P1, 1, mean)
apply(P1, 1, sum)

スクリプトの変更を手伝ってください
...-Produnis

2
これらはあなたからループを隠しています。@Produnisコードの実際の問題は、ループの各反復で結果ベクトルが拡張されているため、強制コピーが行われていることです。
モニカの復職-G.シンプソン

snowfallパッケージは、「ケーキ」と言うようなGavinのソリューションを拡張できます。パッケージには、マルチコアリングを行うために修正された多数の適用関数があります。適用機能については、sfApply(<適用する引数>)を使用します。降雪も十分に文書化されています。マルチコアプロセッサでこれを実行するために追加のソフトウェアは必要ないことを指摘しておきます。sfLapplyの例については、stackoverflow.com / questions / 4164960 /…を参照してください。
ローマンルシュトリック
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.