【发布时间】:2018-05-15 19:35:02
【问题描述】:
考虑对 data.frame 的标准分组操作:
library(plyr)
library(doMC)
library(MASS) # for example
nc <- 12
registerDoMC(nc)
d <- data.frame(x = c("data", "more data"), g = c("group1", "group2"))
y <- "some global object"
res <- ddply(d, .(g), function(d_group) {
# slow, complicated operations on d_group
}, .parallel = FALSE)
只需编写.parallel = TRUE 即可充分利用多核设置。这是我最喜欢的 plyr 功能之一。
但是随着 plyr 被弃用(我认为)并基本上被 dplyr、purrr 等取代,并行处理的解决方案变得更加冗长:
library(dplyr)
library(multidplyr)
library(parallel)
library(MASS) # for example
nc <- 12
d <- tibble(x = c("data", "more data"), g = c("group1", "group2"))
y <- "some global object"
cl <- create_cluster(nc)
set_default_cluster(cl)
cluster_library(cl, packages = c("MASS"))
cluster_copy(cl, obj = y)
d_parts <- d %>% partition(g, cluster = cl)
res <- d_parts %>% collect() %>% ungroup()
rm(d_parts)
rm(cl)
考虑到循环内需要的每个包和对象都需要自己的cluster_* 命令将其复制到节点上,您可以想象这个示例需要多长时间。非并行化的 plyr 到 dplyr 的转换只是一个简单的 dplyr::group_by 构造,不幸的是没有简洁的方法可以对其进行并行处理。所以,我的问题是:
- 这实际上是将我的代码从 plyr 转换为 dplyr 的首选方式吗?
- 在 plyr 的幕后发生了什么样的魔力,使得开启并行处理变得如此容易?是否有理由将此功能特别难以添加到 dplyr 中,而这就是它尚不存在的原因?
- 我的两个示例在代码执行方式方面是否存在根本不同?
【问题讨论】:
-
关于您的第三个问题:我会说是的。您的
plyr示例使用doMC,即multicore的后端foreach,即:forking。您的multidplyr示例使用默认为parallel::makePSOCKcluster的create_cluster,即:Parallel SOCket Cluster。 -
关于您的第二个问题:如果您只调用
partition()而没有提前设置集群,就会发生同样的魔法:plyr依赖于先前注册的foreach后端 (@987654336 @),没有集群的multidplyr::partition()隐式依赖create_cluster(),但如果一个已经注册的后端可能会检测到另一个后端(不过,我还没有检查,请参阅print(multidplyr:::cluster_exists)))。multidplyr小插图的第一个示例说明了这种无需预先设置即可简单调用partition()的功能。 -
关于您的第一个问题:据我所知,从文档和我自己的实验来看,
multidplyr不允许像plyr那样分叉,只有PSOCK。
标签: r dplyr plyr tidyverse multidplyr