我正在尝试将大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)
合并,并将计算并行化。下面的代码非常完美,最大化了我机器的所有内核:
dat
一旦我将向量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)
更改为包含5长的字符串,并行性就会中断,虽然没有错误或警告,但只有1个核心有助于计算:
dat
为什么会出现这种不一致,以及如何解决这个问题呢?在特定示例中,如果将{{1}}索引为整数,则代码可以正常工作。但索引并不是所有情况下的答案。为什么字符串的长度与使用的内核数量有关?
答案 0 :(得分:3)
我认为不同之处在于,在第一种情况下,“bigDF”的第一列是6,760级的因子,而在第二种情况下,它有1,983,234级。具有大量级别可能会导致许多性能问题。当我使用stringsAsFactors=FALSE
创建“bigDF”时,性能要好得多。
bigDF <- data.frame(dat=dat, num=num, stringsAsFactors=FALSE)
我还使用了itertools包中的“isplitRows”函数,以避免向每个worker发送所有“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机器上,你的第二个例子在大约332秒内运行。当我使用stringsAsFactors=FALSE
时,它会在大约50秒内运行。当我也使用isplitRows时,时间下降到5.5秒,比第二个例子快约60倍。
答案 1 :(得分:1)
还没有回答,但是:
如果我运行您的代码但使用%do%
以便不进行并行化,那么除了dat
名称之外,我会得到两个案例相同(成功)的结果。如果我使用%dopar%
运行短名称,使用%do%
运行长名称,则相同。
这开始看起来像其中一个支持包中的一个微妙的错误,所以你可能想要ping这个开发人员。
更新29Sept:我运行了我认为相同的设置但使用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)
:-)