Mul*_*one 0 parallel-processing r divide-and-conquer dataframe
众所周知,R不是运行大型分析的最有效平台.如果我有一个包含三个参数的大型数据框:
GROUP X Y
A 1 2
A 2 2
A 2 3
...
B 1 1
B 2 3
B 1 4
...
millions of rows
Run Code Online (Sandbox Code Playgroud)
我想在每个组上运行计算(例如,在X,Y上计算Pearson的r)并将结果存储在一个新的数据框中,我可以这样做:
df = loadDataFrameFrom( someFile )
results = data.frame()
for ( g in unique( df$GROUP)) ){
gdf <- subset( df, df$GROUP == g )
partialRes <- slowStuff( gdf$X,gdf$Y )
results = rbind( results, data.frame( GROUP = g, RES = partialRes ) )
}
// results contains all the results here.
useResults(results)
Run Code Online (Sandbox Code Playgroud)
显而易见的问题是,即使在强大的多核机器上,这也非常慢.
我的问题是:是否可以并行化这种计算,例如为每个组或一组组创建一个单独的线程?是否有一个干净的R模式来解决这个简单的除法和问题?
谢谢,Mulone
首先,R不一定慢.它的速度在很大程度上取决于正确使用它,就像任何语言一样.有一些东西可以加快你的代码而不会改变太多:results在你开始之前预先分配你的data.frame; 使用列表和矩阵或向量构造而不是data.frame; 切换使用data.table; 列表还在继续,但The R Inferno是一个很好的起点.
另外,看看这里.它提供了有关如何利用多核机器的良好总结.
Hadley Wickam用他的plyr包裹简洁地解决了"干净的R模式" ,特别是ddply:
library(plyr)
library(doMC)
registerDoMC()
ddply(df, .(GROUP), your.function, .parallel=TRUE)
Run Code Online (Sandbox Code Playgroud)
但是,它不一定快.您可以使用以下内容:
library(parallel)
mclapply(unique(df$GRUOP), function(x, df) ...)
Run Code Online (Sandbox Code Playgroud)
或者最后,您可以使用该foreach包:
foreach(g = unique(df$Group), ...) %dopar$ {
your.analysis
}
Run Code Online (Sandbox Code Playgroud)
备份我的评论:1000万行,26组.在单核3.3Ghz CPU上完成<3秒.仅使用基础R.不需要并行化.
> set.seed(21)
> x <- data.frame(GROUP=sample(LETTERS,1e7,TRUE),X=runif(1e7),Y=runif(1e7))
> system.time( y <- do.call(rbind, lapply(split(x,x$GROUP),
+ function(d) data.frame(GROUP=d$GROUP[1],cor=cor(d$X,d$Y)))) )
user system elapsed
2.37 0.56 2.94
> y
GROUP cor
A A 2.311493e-03
B B -1.020239e-03
C C -1.735044e-03
D D 1.355110e-03
E E -8.027199e-04
F F 8.234086e-04
G G 2.337217e-04
H H -5.861781e-04
I I 7.799191e-04
J J 1.063772e-04
K K 7.174137e-04
L L 4.151059e-04
M M 4.440694e-04
N N 2.568411e-03
O O -3.827366e-04
P P -1.239380e-03
Q Q -1.057020e-03
R R 1.079676e-03
S S -1.819232e-03
T T -3.577533e-04
U U -1.084114e-03
V V 6.686503e-05
W W -1.631912e-03
X X 8.668508e-04
Y Y -6.460281e-04
Z Z 1.614978e-03
Run Code Online (Sandbox Code Playgroud)
顺便说一句,并行化只有在你的slowStuff功能成为瓶颈时才有用.你rbind在循环中的使用可能是瓶颈,除非你做类似的事情slowStuff.