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

时间:2012-05-04 15:59:43

标签: r parallel-processing dataframe divide-and-conquer

众所周知,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

我希望在每个组上运行计算(例如,在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)

显而易见的问题是,即使在强大的多核机器上,这也非常慢。

我的问题是:是否有可能将此计算并行化,例如为每个组或一组组创建一个单独的线程? 是否有一个干净的R模式来解决这个简单的除法和问题?

谢谢, Mulone

3 个答案:

答案 0 :(得分:6)

首先,R不一定慢。它的速度在很大程度上取决于正确使用它,就像任何语言一样。有一些方法可以在不改变的情况下加快代码速度:在开始之前预先分配results data.frame;使用列表和矩阵或向量构造而不是data.frame;切换到使用data.table;列表继续,但The R Inferno是一个很好的起点。

另外,看看here。它提供了有关如何利用多核机器的良好总结。

Hadley Wickam用他的plyr包裹,特别是ddply简洁地解决了“干净的R模式”:

library(plyr)
library(doMC)
registerDoMC()
ddply(df, .(GROUP), your.function, .parallel=TRUE)

然而,它并不一定快。你可以使用类似的东西:

library(parallel)
mclapply(unique(df$GRUOP), function(x, df)  ...)

或者最后,您可以使用foreach包:

foreach(g = unique(df$Group), ...) %dopar$ {
   your.analysis
}

答案 1 :(得分:5)

备份我的评论:1000万行,26组。完成于&lt;单核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

顺便说一下,只有当slowStuff函数成为瓶颈时,并行化才有用。您在循环中使用rbind可能是瓶颈,除非您在slowStuff中执行类似操作。

答案 2 :(得分:2)

我认为你的缓慢部分是由于你在R中的非R编程。以下将给出每组的相关性(我使用mtcars数据集并将其除以cyl group)并且非常快速地执行:

by(mtcars, mtcars$cyl, cor)