1

並列 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"

私が見逃したアイデア。それとも、doParallel で動作する ROSE に似た別のオーバー/アンダー サンプリング パッケージでしょうか。Windows 上で実行されます。

4

3 に答える 3

2

問題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(formula, data) のエラー: オブジェクト 'my_data' が見つかりません

したがって、問題をデバッグすると、ovun.sample ソース コードの 24 行目が実行されます。

sys.nframe()
# [1] 2

これは、R が現在環境 #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
于 2019-08-11T22:54:58.623 に答える
0

foreachループは、どこで を探すかについて、異なる環境コンテキストを持っていますmy_data。に置き換えdata=my_dataてみてくださいdata=get("my_data", sys.frame(1))

もう 1 つの方法は、データ変数を の前に設定し、呼び出しでオプションforeachを使用して、データが実行前に各コアに確実にプッシュされるようにすることです。.export=my_dataforeach

于 2016-01-31T18:39:32.603 に答える