Dev*_*vin 9 r plyr dplyr tidyverse multidplyr
考虑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)
Run Code Online (Sandbox Code Playgroud)
通过简单地编写.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)
Run Code Online (Sandbox Code Playgroud)
你可以想象这个例子可以考虑在循环中需要的每个包和对象需要多长时间cluster_*才能将它复制到节点上.非并行化的plyr-to-dplyr转换只是一个简单的dplyr::group_by结构,很遗憾没有简洁的方法来实现并行处理.所以,我的问题是:
我认为没有一种真正的“首选”方法可以将 {plyr} 代码转换为 {dplyr}。
在评论中,@Aur\xc3\xa8le 在描述 {plyr} 和 {doMC} 之间的连接方面比我做得更好。发生的一件事是激励措施发生了一些变化。{doMC} 来自 Revolution Analytics(已被 Microsoft 收购)。但 dplyr 的开发者 Hadley 目前在 RStudio 工作。这两家公司在 IDE 领域展开竞争。因此,他们的软件包设计得不能很好地协同工作,这也许是很自然的。我看到 RStudio 强烈支持的唯一并行形式是 {sparklyr},他们使设置变得相对“容易”。但是,我真的不建议使用 Spark 为单台机器进行并行处理。
@Aur\xc3\xa8le 再次很好地解释了执行差异。您的新代码使用 PSOCK 集群,旧代码使用分叉。分叉使用写时复制模式来访问 RAM,因此并行进程可以在分叉后立即访问相同的数据。PSOCK 集群就像生成 R 的新副本 - 它们必须加载库并接收数据的显式副本。
您可以使用类似的模式...
\n\nlibrary(dplyr)\nlibrary(purrr)\nlibrary(future)\nplan(multicore)\noptions(mc.cores = availableCores())\nd <- data.frame(x = 1:8, g = c("group1", "group2", "group3", "group4"))\ny <- "some global object"\n\n\nsplit(d, d$g) %>% \n map(~ future({Sys.sleep(5);mean(.x$x)})) %>% \n map_df(~value(.x))\nRun Code Online (Sandbox Code Playgroud)\n\n...在步骤上采取一些技巧map_df来进行一些并行处理。请注意,在 {purrr} 下 ~ 是匿名函数语法,其中 .x 是已映射的值。
如果你喜欢危险的生活,你也许可以通过在 {purrr} 中使用私有方法来创建类似的版本,而无需使用 {future}
\n\nmcmap <- function(.x, .f, ...) {\n .f <- as_mapper(.f, ...)\n mclapply(.x, function(.x) {\n force(.f)\n .Call(purrr:::map_impl, environment(), ".x", ".f", "list")\n }) %>%\n map(~ .x[[1]])\n}\nRun Code Online (Sandbox Code Playgroud)\n