R语言用doParallel替代apply时函数内重命名data.frame列名报错如何解决
问题原因
你遇到的报错是PSOCK类型集群的典型问题:通过parallel::makeCluster默认创建的是PSOCK集群,每个工作子进程都是独立的全新R会话,不会自动继承主进程全局环境里定义的df2对象,所以函数内部调用df2时会提示对象不存在。
你之前去掉重命名逻辑的函数能够运行属于巧合,大概率是测试过程中已经意外把df2同步到了子进程,在干净的R环境中,只要没做变量同步,不管有没有重命名逻辑都会触发对象不存在的报错。
方案1:通过foreach的.export参数导出依赖对象
不需要修改原有函数逻辑,只需在foreach语句中添加.export参数,指定要同步到所有子进程的全局变量名即可:
library(doParallel) dat1 <- df1 ncores1 <- detectCores()-5 # 加个保护逻辑,避免检测到的核心数太少导致ncores1为负 ncores1 <- max(1, ncores1) c1 <- parallel::makeCluster(ncores1) registerDoParallel(c1) v1 <- foreach(i = 1:nrow(dat1), .export = "df2") %dopar% { my.function1(dat1[i,1], dat1[i,2], dat1[i,3], dat1[i,4], dat1[i,5]) } v1 stopCluster(c1)
方案2:将df2改为函数入参(更规范的写法)
避免函数依赖全局变量,把df2作为参数传入函数,代码可维护性更强,也不需要额外配置变量导出规则:
- 先修改自定义函数:
my.function1 <- function(aa, bb, cc, dd, ee, df) { colnames(df) <- c('qqq', 'www', 'eee', 'rrr', 'ttt') return(list(new.df=df)) }
- 并行调用时传入
df2即可:
library(doParallel) dat1 <- df1 ncores1 <- detectCores()-5 ncores1 <- max(1, ncores1) c1 <- parallel::makeCluster(ncores1) registerDoParallel(c1) v1 <- foreach(i = 1:nrow(dat1)) %dopar% { my.function1(dat1[i,1], dat1[i,2], dat1[i,3], dat1[i,4], dat1[i,5], df2) } v1 stopCluster(c1)
内容的提问来源于stack exchange,提问作者Mark Miller
相关产品推荐
相关产品推荐

