在R doParallel foreach循环中运行ovun.sample

时间:2016-01-31 17:00:44

标签: r doparallel

我无法在平行的foreach中使用ovun.sample。

以下是最小的工作示例。

library(doParallel)
library(ROSE) # ovun.sample

if(!getDoParRegistered()){
  registerDoParallel(cores=detectCores())
}

foreach(i=1:2,.combine=rbind, .packages=c("ROSE")) %dopar% {
  my_data = iris[iris$Species != "setosa",]
  under_data <- ovun.sample(Species ~ ., data=my_data, N=40, seed = 1)$data
}
print(r)

我收到错误:

Error in { : task 1 failed - "object 'my_data' not found"

任何想法我错过了什么。或者可能是另一个类似于ROSE的上/下采样包与doParallel一起使用?在Windows上运行。

3 个答案:

答案 0 :(得分:0)

... // in buildFormGroup() removePhoneLink.id = "btnRemove"+this.targetId; ... // called after attaching the form group to the dom this.bindEventHandlers = function() { document.getElementById("btnRemove"+this.targetId).onclick = function(e) { this.removePhone(); }.bind(this); } 循环在查找foreach的位置具有不同的环境上下文。尝试将my_data替换为data=my_data

另一种方法是在data=get("my_data", sys.frame(1))之前设置数据变量,并使用foreach调用中的.export=my_data选项,以确保在执行之前将数据推送到每个核心。

答案 1 :(得分:0)

ovun.sample的问题在于,不幸的是,它假设变量在全局范围内,试图执行代码: https://github.com/cran/ROSE/blob/master/R/data_balancing_funcs.R#L26

以下代码有助于直观地说明ovun.sample不起作用的原因:

my.ovun.sample <- function(dataset) {
  my_data <- dataset
  ovun.sample(cls ~ ., data = my_data, method="both", N=200, seed=1)$data
}

my.ovun.sample(dataset=hacide.train)

它将产生:

  

adj.formula(公式,数据)出错:找不到对象“ my_data”

因此,如果我们调试问题,则在ovun.sample source code中执行第24行时:

sys.nframe()
# [1] 2

这意味着R当前在environment #2中。

然后我们调试当前范围内可用的变量:

ls(sys.frame(2))
# [1] "Call"      "Call1"     "data"      "formula"   "m"         "method"    "N"         "na.action" "p"         "seed"     
# [11] "subset"   

然后,我们继续调试父作用域(将是my.ovun.sample函数)中的内容:

ls(sys.frame(1))
# [1] "dataset" "my_data"

最后在全局范围内:

ls(sys.frame(0))
# [1] "hacide.test"    "hacide.train"   "my.ovun.sample"

现在,当执行以下行时:

res <- eval(Call1)

该代码将引发错误,因为my_data在该环境中不可用。如果将代码更改为:

my.ovun.sample <- function(dataset) {
  my_data <- dataset
  ovun.sample(cls ~ ., data = get("my_data", sys.frame(1)), method="both", N=200, seed=1)$data
}

现在,在使用foreach时,data=get("my_data", sys.frame(1))的问题在于并行环境不会总是为1。要解决此问题,我们需要使用更通用的方式来发送当前帧。这是似乎有效的代码:

library(doParallel)
library(ROSE) # ovun.sample
data(hacide)

if (!getDoParRegistered()) {
  registerDoParallel(cores=detectCores())
}

my_results = foreach(i=1:2, .combine=rbind, .packages=c("ROSE")) %dopar% {
  my_data <- hacide.train
  my_data$i <- i

  # this sends the current_frame to global environment
  curr_frame <<- sys.nframe()

  ovun.sample(cls ~ ., data = get("my_data", sys.frame(curr_frame)), method="both", N=200, seed=1)$data
}

registerDoSEQ()

print(head(my_results))
#  cls          x1         x2 i
# 1   0  0.56444509 -0.7198744 1
# 2   0  0.73493507  0.4791222 1
# 3   0 -0.39307673  0.8098423 1
# 4   0 -0.39934508 -0.2746103 1
# 5   0 -0.06157228 -1.2983649 1
# 6   0  0.20251246 -0.6173485 1

print(tail(my_results))
#    cls        x1        x2 i
# 395   1 -2.789707 -1.497824 2
# 396   1 -2.149788 -1.708764 2
# 397   1 -0.741708 -1.973571 2
# 398   1 -2.149788 -1.708764 2
# 399   1 -1.427158 -1.415405 2
# 400   1 -2.037152 -1.127303 2

print(table(my_results$cls))
#   0   1 
# 196 204

print(table(my_results$i))
#  1   2 
# 200 200

答案 2 :(得分:0)

在foreach循环中设置my_data时,请尝试使用my_data <<- ...

这会将分配结果放入全局环境