R Language
並列処理
サーチ…
備考
リモートマシンでの並列化では、各マシンにライブラリをダウンロードする必要があります。 package::function()
が好きです。いくつかのパッケージには、 caret
、 pls
、 plyr
などの並列化がネイティブに組み込まれていcaret
。
Microsoft R Open (Revolution R)は、多くの共通機能を本質的に並列化するマルチスレッドBLAS / LAPACKライブラリも使用します。
foreachパッケージによる並列処理
foreach
パッケージは並列処理能力をRにもたらしますが、マルチコアCPUを使用する前にマルチコアクラスタを割り当てる必要があります。 doSNOW
パッケージは1つの可能性があります。
foreachループの簡単な使い方は、平方根と1から100000までのすべての数の平方和を計算することです。
library(foreach)
library(doSNOW)
cl <- makeCluster(5, type = "SOCK")
registerDoSNOW(cl)
f <- foreach(i = 1:100000, .combine = c, .inorder = F) %dopar% {
k <- i ** 2 + sqrt(i)
k
}
foreach
の出力の構造は、 .combine
引数によって制御されます。デフォルトの出力構造はリストです。上記のコードでは、代わりにc
を使用してベクトルを返します。 "+"
などの計算関数(または演算子)を使用して計算を実行し、さらに処理されたオブジェクトを返すこともできます。
それぞれのforeach-loopの結果が最後の呼び出しであることに言及することは重要です。したがって、この例では、 k
が結果に加算されます。
パラメータ | 詳細 |
---|---|
.combine | 関数を結合する。ループの結果をどのように組み合わせるかを決定します。可能な値はc 、 cbind 、 rbind 、 "+" 、 "*" ...です。 |
。順番に | TRUE の場合、結果は反復可能な順序(ここではi )に従って並べられます。 FALSE 、結果は順序付けされません。これは、計算時間に影響を与える可能性があります。 |
パッケージ | base 以外のパッケージ、例えばmass 、 randomForest などで提供される関数の場合、これらのパッケージにはc("mass", "randomForest") を指定する必要があります |
並列パッケージによる並列処理
基本パッケージparallel
は、フォーク、ソケット、および乱数生成による並列計算を可能にします。
ローカルホスト上に存在するコアの数を検出します。
parallel::detectCores(all.tests = FALSE, logical = TRUE)
localhostにコアのクラスタを作成します。
parallelCluster <- parallel::makeCluster(parallel::detectCores())
まず、並列化に適した関数を作成する必要があります。 mtcars
データセットを考えてみましょう。 cyl
各レベルについて個別の回帰モデルを作成することで、 mpg
の回帰を改善できます。
data <- mtcars
yfactor <- 'cyl'
zlevels <- sort(unique(data[[yfactor]]))
datay <- data[,1]
dataz <- data[,2]
datax <- data[,3:11]
fitmodel <- function(zlevel, datax, datay, dataz) {
glm.fit(x = datax[dataz == zlevel,], y = datay[dataz == zlevel])
}
zlevels
すべての可能な反復をループすることができる関数を作成します。これはまだシリアルで行われていますが、並列化される正確なプロセスを決定する重要なステップです。
fitmodel <- function(zlevel, datax, datay, dataz) {
glm.fit(x = datax[dataz == zlevel,], y = datay[dataz == zlevel])
}
for (zlevel in zlevels) {
print("*****")
print(zlevel)
print(fitmodel(zlevel, datax, datay, dataz))
}
カレーこの機能:
worker <- function(zlevel) {
fitmodel(zlevel,datax, datay, dataz)
}
パラレルを使用parallel
並列コンピューティングは、地球環境にはアクセスできません。幸運なことに、各機能はローカル環境のparallel
アクセスを作成します。ラッパー関数を作成すると、並列化が可能になります。適用される機能も環境内に配置する必要があります。
wrapper <- function(datax, datay, dataz) {
# force evaluation of all paramters not supplied by parallelization apply
force(datax)
force(datay)
force(dataz)
# these variables are now in an enviroment accessible by parallel function
# function to be applied also in the environment
fitmodel <- function(zlevel, datax, datay, dataz) {
glm.fit(x = datax[dataz == zlevel,], y = datay[dataz == zlevel])
}
# calling in this environment iterating over single parameter zlevel
worker <- function(zlevel) {
fitmodel(zlevel,datax, datay, dataz)
}
return(worker)
}
今すぐクラスターを作成し、ラッパー関数を実行します。
parallelcluster <- parallel::makeCluster(parallel::detectCores())
models <- parallel::parLapply(parallelcluster,zlevels,
wrapper(datax, datay, dataz))
完了したら、必ずクラスタを停止してください。
parallel::stopCluster(parallelcluster)
parallel
パッケージは全体が含まapply()
が付い家族、 par
。
乱数生成
並列化の大きな問題は、RNGをシードとして使用することです。数値による乱数は、セッションの開始または最新のset.seed()
いずれかからの操作の数によって反復されます。並列処理は同じ関数から発生するため、同一のシードを使用することができ、同じ結果が生じる可能性があります。コールは、さまざまなコアでシリアルに実行され、利点を提供しません。
一連のシードを生成して各並列プロセスに送信する必要があります。これはいくつかのパッケージ( parallel
、 snow
など)で自動的に行われますが、他のパッケージでは明示的に対処する必要があります。
s <- seed
for (i in 1:numofcores) {
s <- nextRNGStream(s)
# send s to worker i as .Random.seed
}
種子を再現性のために設定することもできます。
clusterSetRNGStream(cl = parallelcluster, iseed)
mcparallelDo
mcparallelDo
パッケージを使用すると、UNIX系(LinuxやMacOSXなど)のオペレーティングシステムでRコードを非同期的に評価することができます。パッケージの根底にある考え方は、コーディングではなく、探索的データ分析のニーズに合わせています。非同期をコーディングするには、 future
パッケージを考慮してください。
例
データを作成する
data(ToothGrowth)
フォーク上で分析を実行するためにmcparallelDoをトリガする
mcparallelDo({glm(len ~ supp * dose, data=ToothGrowth)},"interactionPredictorModel")
他のこと、例えば
binaryPredictorModel <- glm(len ~ supp, data=ToothGrowth)
gaussianPredictorModel <- glm(len ~ dose, data=ToothGrowth)
mcparallelDoの結果はtargetEnvironmentなどで返されます(例:.GlobalEnv)。メッセージが完了すると(デフォルトでは)
summary(interactionPredictorModel)
その他の例
# Example of not returning a value until we return to the top level
for (i in 1:10) {
if (i == 1) {
mcparallelDo({2+2}, targetValue = "output")
}
if (exists("output")) print(i)
}
# Example of getting a value without returning to the top level
for (i in 1:10) {
if (i == 1) {
mcparallelDo({2+2}, targetValue = "output")
}
mcparallelDoCheck()
if (exists("output")) print(i)
}