Foreach循环找不到对象

mar*_*ist 3 parallel-processing foreach eval r

我正在尝试将foreach与并行后端一起使用以加快计算速度(如果这很重要,可以对{AUCRF}随机森林进行交叉验证以进行特征选择)。在这样做的过程中,我需要获取向量的子集。向量的名称可以更改,但可以作为字符向量访问。我使用eval(parse())构造(好主意?)来获取向量的子集。

例:

library(parallel)
library(foreach)
library(stats)

#create cluster
clu <- makeCluster(detectCores() - 1)
registerDoParallel(clu, cores = detectCores() - 1)

bar<-c("a","b","c","d")
rab<-c(2,3)
bar.name<-"bar"

#expected output in this example is a list containing ten times
bar[rab]
#or
eval(parse(text=paste(bar.name,"[rab]",sep="")))

foo<-foreach(m = 1:10, .packages = c("stats")) %dopar% {
  sink("foreach.txt")
      print(bar.name)
      print(parse(text=paste(bar.name,"[rab]",sep="")))
      print(eval(parse(text=paste(bar.name,"[rab]",sep=""))))
  foo.temp<-eval(parse(text=paste(bar.name,"[rab]",sep="")))
  return(foo.temp)
}
sink()
stopCluster(clu)
Run Code Online (Sandbox Code Playgroud)

但是我得到以下错误:

Error in { : task 1 failed - "Object 'bar' not found"
Run Code Online (Sandbox Code Playgroud)

我以为每个工作人员都会得到一个包含所有对象的工作区副本。知道我在做什么错吗?

MrF*_*ick 5

这听起来像是一个糟糕的设计。几乎从未使用过eval(parse())

要获取变量,get()则更安全一些,例如get(bar.name)[rab]。但是您仍然在这里遇到环境问题。既然你没有变量barrab在的身体dopar,他们不出口到那里的环境foreach中运行代码。您可以通过显式分配.exportforeach参数来解决此问题,以确保导出了这些变量。在这里,我更改为使用get,只需要显式导出,bar因为rab它现在包含在函数框中。

foo<-foreach(m = 1:10, .export=c("bar"), .packages = c("stats")) %dopar% {
  get(bar.name)[rab]
}
Run Code Online (Sandbox Code Playgroud)

一个更好的主意不是指定变量名,而是指定命名列表的元素。例如

baz <- list(bar=letters[1:4], bob=letters[5:7])
Run Code Online (Sandbox Code Playgroud)

那你可以做

baz.name <- "bar"
rab <- c(2,4)

foo<-foreach(m = 1:10, .packages = c("stats")) %dopar% {
  baz[[baz.name]][rab]
}
Run Code Online (Sandbox Code Playgroud)

而且由于dopar可以看到变量baz,,baz.name因此rab您无需导出任何内容。