当我坐在这里等待我的R脚本运行时,我想知道...是否有任何方法可以在R中并行操作rbind?
因为我处理大量数据时,常常需要等待这个调用的完成。
do.call("rbind", LIST)
当我坐在这里等待我的R脚本运行时,我想知道...是否有任何方法可以在R中并行操作rbind?
因为我处理大量数据时,常常需要等待这个调用的完成。
do.call("rbind", LIST)
到目前为止,我还没有找到一种并行处理的方法。不过,针对我的数据集(其中有一个包含大约1500个数据框和总共450万行的列表),下面的代码片段似乎有所帮助:
while(length(lst) > 1) {
idxlst <- seq(from=1, to=length(lst), by=2)
lst <- lapply(idxlst, function(i) {
if(i==length(lst)) { return(lst[[i]]) }
return(rbind(lst[[i]], lst[[i+1]]))
})
}
其中lst是列表。这种方法似乎比使用do.call(rbind, lst)
甚至比使用plyr
包中的rbind.fill
函数快大约4倍。在每次迭代中,此代码都会将数据帧减半。
编辑:
library(data.table)
system.time(dt <- rbindlist(pieces))
utilisateur système écoulé
0.12 0.00 0.13
tables()
NAME NROW MB COLS KEY
[1,] dt 1,000 8 X1,X2,X3,X4,X5,X6,X7,X8,...
Total: 8MB
闪电般快速...
我怀疑你想通过并行化来更快地实现这个功能:除了你可能需要自己编写代码(线程一首先将项目1和2组合,而线程二将项目3和4组合等等,等它们完成后,结果就像“重新绑定”一样 - 我不认为没有非C方式可以改进这个问题),这还将涉及在线程之间复制大量数据,这通常是导致速度变慢的原因。
在 C 语言中,您可以在线程之间共享对象,因此您可以让所有线程在同一内存中写入。祝您好运 :-)
最后,顺带一提:rbinding 数据框(data.frame)的速度很慢。如果您事先知道所有数据框的结构完全相同,并且它不包含纯字符列,则可以使用我的问题的这个答案中的技巧。如果您的数据框包含字符列,我认为最好单独处理这些列(do.call(c, lapply(LIST, "[[", "myCharColName"))
),然后进行其余部分的操作,之后再将它们重新组合。
以下是一种解决方案,它自然地扩展到rbind.fill,merge和其他数据框列表函数:
但是像我所有的答案/问题一样,请进行验证 :)
require(snowfall)
require(rbenchmark)
rbinder <- function(..., cores=NULL){
if(is.null(cores)){
do.call("rbind", ...)
}else{
sequ <- as.integer(seq(1, length(...), length.out=cores+1))
listOLists <- paste(paste("list", seq(cores), sep=""), " = ...[", c(1, sequ[2:cores]+1), ":", sequ[2:(cores+1)], "]", sep="", collapse=", ")
dfs <- eval(parse(text=paste("list(", listOLists, ")")))
suppressMessages(sfInit(parallel=TRUE, cores))
dfs <- sfLapply(dfs, function(x) do.call("rbind", x))
suppressMessages(sfStop())
do.call("rbind", dfs)
}
}
pieces <- lapply(seq(1000), function(.) data.frame(matrix(runif(1000), ncol=1000)))
benchmark(do.call("rbind", pieces), rbinder(pieces), rbinder(pieces, cores=4), replications = 10)
#test replications elapsed relative user.self sys.self user.child sys.child
#With intel i5 3570k
#1 do.call("rbind", pieces) 10 116.70 6.505 115.79 0.10 NA NA
#3 rbinder(pieces, cores = 4) 10 17.94 1.000 1.67 2.12 NA NA
#2 rbinder(pieces) 10 116.03 6.468 115.50 0.05 NA NA
rbindlist
或其他基于列表的技术。我只是使用R的标准rbind
来进行简单的概念验证。 - Xachriel这是对 @Dominik 回答的进一步扩展。
我们可以使用 parallel 包中的 mclapply 来进一步提高速度。此外,rbind.fill 比 rbind 做得更好,因此以下是改进后的代码。 注意:这仅适用于 mac/linux。mclapply 不支持 Windows。 编辑:如果您想查看进度,请取消注释 print(i) 行,并确保从终端而非 RStudio 运行。从并行进程打印到 RStudio 会有点搞乱 RStudio。
library(parallel)
rbind.fill.parallel <- function(list){
while(length(list) > 1) {
idxlst <- seq(from=1, to=length(list), by=2)
list <- mclapply(idxlst, function(i) {
#print(i) #uncomment this if you want to see progress
if(i==length(list)) { return(list[[i]]) }
return(rbind.fill(list[[i]], list[[i+1]]))
})
}
}
看起来已经有很多人回答了,但如果有人遇到这个问题,这里是一个针对非data.table/data.frame-esque对象的并行rbind版本:
rbind.parallel <- function(list,ncore)
{
library(parallel)
do.call.rbind<-function(x){do.call(rbind,x)}
cl<-makeCluster(ncore)
list.split<-split(list,rep(1:ncore,length(list)+1)[1:length(list)])
list.join<-parLapply(cl,list.split,do.call.rbind)
stopCluster(cl)
list.out<-do.call(rbind,list.join)
return(list.out)
}
这在 sf 类型的对象上非常有效。例如,如果您使用 lapply(.,st_read)
从目录中读取一组 shapefile 的列表,则明显不能使用 rbind.fill 及其变体来连接所有要素。
rbind
快得多。也许你会在这里看到一些性能提升。如果您添加一些代表性数据样本,人们也可以提供其他解决方案,并进行基准测试以测量时间。 - ChaseLIST
中包含什么类型的对象(矩阵,数据框等)? - Joshua Ulrich