在 R doParallel foreach 循环中运行 ovun.sample
Posted
技术标签:
【中文标题】在 R doParallel foreach 循环中运行 ovun.sample【英文标题】:Run ovun.sample in R doParallel foreach loop 【发布时间】:2016-05-09 01:54:39 【问题描述】:我只是无法在并行 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 上运行。
【问题讨论】:
【参考方案1】: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
【讨论】:
是的,这需要 var global。谢谢!【参考方案2】:foreach
循环在寻找my_data
的位置具有不同的环境上下文。尝试将data=my_data
替换为data=get("my_data", sys.frame(1))
。
另一种方法是在foreach
之前设置数据变量,并在foreach
调用中使用.export=my_data
选项确保数据在执行前推送到每个内核。
【讨论】:
感谢您的建议,但data=get("my_data", sys.frame(1))
也不起作用。我也试过 .export=c("my_data"),也没有用。但这有效:result <- foreach(i=1:2,.combine=rbind, .packages=c("SDR", "ROSE") ) %dopar% my_data = iris[iris$Species != "setosa",] sum(iris$Species == "virginica") print(result)
我只是不知道为什么不适用于函数 ovun.sample。
要使.export=my_data
工作,必须在主代码中的foreach
循环之前定义my_data
。这真的应该工作。它必须与执行环境有关。 ?ovun.sample
将data
选项描述为If not specified, the variables are taken from “environment(formula).
。这向我表明,这可能是公式中的.
和my_data
之间的冲突。如果您完全放弃 data=my_data
选项会发生什么?【参考方案3】:
在 foreach 循环中设置my_data
时,尝试使用my_data <<- ...
这会将赋值的结果放到全局环境中
【讨论】:
以上是关于在 R doParallel foreach 循环中运行 ovun.sample的主要内容,如果未能解决你的问题,请参考以下文章
在 R doParallel foreach 循环中运行 ovun.sample
使用 foreach 函数和 doParallel 库在 R 中嵌套 for 循环
在 R 中将 fread 与 foreach 和 doParallel 一起使用