在R中的数据帧上划分et impera

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

Jus*_*tin 6

首先,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)


Jos*_*ich 5

备份我的评论: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.