R中的并行计算,用于通过循环保存数据
Posted
技术标签:
【中文标题】R中的并行计算,用于通过循环保存数据【英文标题】:Parallel computation in R for saving data over loops 【发布时间】:2020-04-08 17:45:06 【问题描述】:我在以下简单代码上应用并行以在多个循环中使用 Openxlsx 保存输出的努力失败了。
任何人都可以帮助将此代码转换为并行模式。此代码基于实际大小的数据(超过 5000 万次观察,需要 13 小时才能运行)。减少 2 小时对我来说是一项艰巨的工作。
library(dplyr)
library(readxl)
library(openxlsx)
library(foreach)
library(doParallel)
rawdata <- readxl::read_xlsx("~/Desktop/Book1.xlsx")
TYPE1 <- rawdata %>% filter(TYPE == "A")
TYPE2 <- rawdata %>% filter(TYPE == "B")
Split.TYPE1 <- split(TYPE1, TYPE1$Name)
Split.TYPE2 <- split(TYPE2, TYPE2$Name)
#--------------------------------- Save the TYPE A reports------------------------------------------------------------------------------
###################################(the foreach lines are coded)
for (nm in names(Split.TYPE1))
#foreach(nm=1:names(Split.TYPE1), .combine=cbind) %dopar%
file<-paste0(nm,".xlsx")
d1<-as.data.frame(Split.TYPE1[[nm]])
wb<-createWorkbook(file)
addWorksheet(wb, "test", gridLines = T)
writeData(wb, sheet = "test", x = d1)
saveWorkbook(wb, file, overwrite = TRUE)
# #------------------------------ Save the TYPE B in a folder ----------------------------------
for (dn in names(Split.TYPE2))
dnn <- paste0(dn)
dir.create(dnn)
sub_Split.TYPE2 <- split(Split.TYPE2[[dn]], Split.TYPE2[[dn]]$Surname)
for (fn in names(sub_Split.TYPE2))
file<-file.path(dnn, paste0(fn,".xlsx"))
d1<-as.data.frame(sub_Split.TYPE2[[fn]])
wb<-createWorkbook(file)
addWorksheet(wb, "test", gridLines = T)
writeData(wb, sheet = "test", x = d1)
saveWorkbook(wb, file, overwrite = TRUE)
数据:
Name Surname TYPE
John Greer A
David bear A
Rose beer B
Tara tea B
Sam Mac B
Alan Glass B
Brad Newman A
Kristen Goodman A
Jessica Goodwin A
Heather Poker B
【问题讨论】:
标准for
循环不会在R
中并行运行。试试foreach
包中的foreach
函数。
不确定如何为我的代码中的第二个嵌套循环应用 Foreach。嵌套的 Foreach 代码通常紧跟在每个代码之后。我在嵌套循环的第一层有一些事情要做。
【参考方案1】:
因为我没有你的数据,所以我做了一些小的虚拟样本。
我使用的包:
library(tidyverse)
library(openxlsx)
library(foreach)
library(doParallel)
这部分来自你,并没有改变任何东西。
TYPE1 <- rawdata %>% filter(TYPE == "A")
TYPE2 <- rawdata %>% filter(TYPE == "B")
Split.TYPE1 <- split(TYPE1, TYPE1$Name)
Split.TYPE2 <- split(TYPE2, TYPE2$Name)
定义并行后端。我在这里使用 6 个核心。
cl <- makeCluster(6)
registerDoParallel(cl)
这是您的第一个循环。不要忘记添加.packages = "openxlsx"
。这可以确保包裹也被发送给工人。我稍微更改了代码,因为nm in names(Split.TYPE1)
不适用于 foreach。也许有更简单的解决方案,但我不知道。
foreach(nm = 1:length(Split.TYPE1), .combine = cbind, .packages = "openxlsx") %dopar%
file <- paste0(names(Split.TYPE1)[nm], ".xlsx")
d1 <- as.data.frame(Split.TYPE1[[names(Split.TYPE1)[nm]]])
wb <- createWorkbook(file)
addWorksheet(wb, "test", gridLines = TRUE)
writeData(wb, sheet = "test", x = d1)
saveWorkbook(wb, file, overwrite = TRUE)
第二个循环。我过去只使用过一次,它对我来说效果很好。这就是创建嵌套 foreach 循环的方法。更多信息here。
foreach(dn = 1:length(Split.TYPE2)) %:%
foreach(fn = 1:length(unique(Split.TYPE2[[names(Split.TYPE2)[dn]]]$Surname)), .packages = "openxlsx") %dopar%
dnn <- paste0(names(Split.TYPE2)[dn])
dir.create(dnn)
sub_Split.TYPE2 <- split(Split.TYPE2[[names(Split.TYPE2)[dn]]], Split.TYPE2[[names(Split.TYPE2)[dn]]]$Surname)
file <- file.path(dnn, paste0(names(sub_Split.TYPE2)[fn],".xlsx"))
d1 <- as.data.frame(sub_Split.TYPE2[[fn]])
wb <- createWorkbook(file)
addWorksheet(wb, "test", gridLines = T)
writeData(wb, sheet = "test", x = d1)
saveWorkbook(wb, file, overwrite = TRUE)
并停止并行后端。
stopCluster(cl)
使用您的数据,我得到以下嵌套循环的文件夹/文件结构:
- Alan
- Glass.xlsx
- Heather
- Poker.xlsx
- Rose
- beer.xlsx
- Sam
- Mac.xlsx
- Tara
- tea.xlsx
【讨论】:
感谢您的努力,但是,我在运行您的示例的第二个循环中遇到了一个错误,因为“ 中的错误:任务 1 失败 -”参数意味着不同的行数:10、0” ” 。此外,第二个循环不应该保存每个文件夹中的所有工作表。由于它在原始代码中编码,因此它仅将具有相同姓氏的 split.Type2 文件保存在相关文件夹中。所以我认为你误解了第二个嵌套循环的工作方式。这就是为什么我还不能申请foreach。无论如何都要欣赏它。 您在运行我的示例时遇到了错误?我只是在我的电脑上运行它,没有任何错误。我在 Ubuntu 18.04.3 LTS 系统上使用 R 3.6.2、doParallel 1.0.15、foreach 1.4.7、openxlsx 4.1.4、tidyverse 1.3.0。 我得到的结果与普通 for 循环与 foreach 循环完全相同。我会再试一次。 如果我错了,请纠正我。这在您的嵌套循环中是否正确:(fn in names(Split.TYPE2))
,这不应该是(fn in names(sub_Split.TYPE2))
吗?我对嵌套的 foreach 循环进行了一些调整。这不是一个好的解决方案。使用嵌套的 foreach 循环,您需要事先准备好迭代器。
感谢您的宝贵时间。在嵌套循环中:第一个循环遍历 split.TYPE2,并根据定义的条件将它们中的每一个拆分为 sub_split.TYPE2,并为每个循环创建一个文件夹。然后内部循环遍历 sup_split.TYPE2 并将相关输出写入相关文件夹中。这有意义吗?以上是关于R中的并行计算,用于通过循环保存数据的主要内容,如果未能解决你的问题,请参考以下文章