4

data.frame大きなものと小さなものをマージして、計算を並列化しようとしています。以下のコードは完璧に機能し、マシンのすべてのコアを最大化します。

len <- 2000000
set.seed(666)
dat = paste(sample(letters, len, rep = T), sample(0:9, len, rep = T), sample(letters, len, rep = T), sep = '') # create a vector of strings that are 3-long
head(dat)
set.seed(777)
num <- sample(0:9, len, replace = T)
bigDF <-  data.frame(dat = dat, num = num)
smallDF <- data.frame(num = 0:9, caps = toupper(letters[1:10]))
startP <- 1
chunk <- 10000
nodes <- detectCores()
cl <- makeCluster(nodes)
registerDoParallel(cl)
mergedList <- foreach(i = 0:(len/chunk - 1)) %dopar% {
    tmpDF = bigDF[(startP + i * chunk):(startP - 1 + (i + 1) * chunk), ]
    merge(tmpDF, smallDF, by = 'num', all.x = T)
}
stopCluster(cl)

vectordatを 5 の長さの文字列を含むように変更すると、並列処理が機能しなくなり、エラーや警告は表示されませんが、計算に寄与するコアは 1 つだけです。

len <- 2000000
set.seed(666)
dat = paste(sample(letters, len, rep = T), sample(0:9, len, rep = T), sample(letters, len, rep = T), sample(letters, len, rep = T), sample(letters, len, rep = T), sample(letters, len, rep = T), sep = '') # create a vector of strings that are 6-long
head(dat)
set.seed(777)
num <- sample(0:9, len, replace = T)
bigDF <-  data.frame(dat = dat, num = num)
smallDF <- data.frame(num = 0:9, caps = toupper(letters[1:10]))
startP <- 1
chunk <- 10000
nodes <- detectCores()
cl <- makeCluster(nodes)
registerDoParallel(cl)
mergedList <- foreach(i = 0:(len/chunk - 1)) %dopar% {
    tmpDF = bigDF[(startP + i * chunk):(startP - 1 + (i + 1) * chunk), ]
    merge(tmpDF, smallDF, by = 'num', all.x = T)
}
stopCluster(cl)

この不一致の理由と、それを回避するにはどうすればよいでしょうか? dat特定の例では、整数にインデックスを付ける場合、コードは機能します。しかし、索引付けがすべての場合の答えになるわけではありません。ストリングの長さが、使用されるコアの数に関係するのはなぜですか?

4

2 に答える 2

4

違いは、最初のケースでは「bigDF」の最初の列が 6,760 レベルの因子であるのに対し、2 番目のケースでは 1,983,234 レベルであるということです。膨大な数のレベルがあると、多くのパフォーマンスの問題が発生する可能性があります。で「bigDF」を作成したところstringsAsFactors=FALSE、パフォーマンスが大幅に向上しました。

bigDF <- data.frame(dat=dat, num=num, stringsAsFactors=FALSE)

また、itertools パッケージの「isplitRows」関数を使用して、すべての「bigDF」を各ワーカーに送信しないようにしました。

library(itertools)
mergedList <- foreach(splitDF=isplitRows(bigDF, chunkSize=chunk)) %dopar% {
    merge(splitDF, smallDF, by = 'num', all.x = T)
}

R 3.1.1 を実行している私の 6 コア Linux マシンでは、2 番目の例は約 332 秒で実行されました。を使っstringsAsFactors=FALSEたところ、50秒ほどで走りました。isplitRows も使用すると、時間は 5.5 秒に短縮され、2 番目の例よりも約 60 倍速くなりました。

于 2014-09-26T21:19:06.097 に答える
2

まだ答えはありませんが、コードを実行して%do%も並列化しないように使用すると、名前を除いて2つのケースで同じ(成功した)結果が得られdatます。%dopar%短い名前を で実行し、長い名前を で実行しても同じです%do%

これは、サポートしているパッケージの 1 つの微妙なバグのように見え始めているため、このパッケージについて開発者に連絡することをお勧めします。

9 月 29 日更新: 同じセットアップであると思われるものを実行しましたが、ClusterMap を使用しています。

dffunc <-function(i=i,bigDF=bigDF,smallDF=smallDF,startP=startP,chunk=chunk) {
tmpDF <- bigDF[(startP + i * chunk):(startP - 1 + (i + 1) * chunk), ]
    merge(tmpDF, smallDF, by = 'num', all.x = T)
    }


clusmerge<- clusterMap(cl,  function(i) {dffunc(i=i)}, 0:(len/chunk-1),MoreArgs=list(bigDF=bigDF,smallDF=smallDF,startP=startP,chunk=chunk) )

datこの場合、名前文字列の長さに関係なく、すべてのノードを稼働させます。パッケージ内%dopar%または他の場所に何らかのバグがあるのではないかと疑っています。foreach

補足として、実行しないことをお勧めしますか

nodes <- detectCores()
cl <- makeCluster(nodes)

マシン全体がハングアップする可能性があるためです。より良いcl <- makeCluster(nodes-1) :-)

于 2014-09-26T17:41:37.337 に答える