一段 R 代码会影响 foreach 输出中的随机数吗?

2024-05-18

我使用运行模拟foreach and doParallel并与随机数(名为random在代码中)。

简而言之:我模拟一个足球联赛,随机生成所有比赛的获胜者以及相应的结果。在dt_base没有比赛进行,在dt_ex1 and dt_ex24场比赛的结果已经已知。所有未知的结果都应该被模拟。

In the 联赛模拟代码在这篇文章的底部,我设置了 1000 个模拟,分为 100 个块(forloop 用于将数据发送到 PostgreSQL 并减少我使用的完整代码中的 RAM 使用量)。我希望所有的随机数都不同(甚至不坚持可重现的结果)。

1.当运行给定的代码时,应该达到所有不同随机数的目标。

> # ====== Distinct Random Numbers ======
> length(unique(out$random))                              # expectation: 22000
[1] 22000
> length(unique(out$random[out$part == "base"]))          # expectation: 10000
[1] 10000
> length(unique(out$random[out$part == "dt_ex1"]))        # expectation: 6000
[1] 6000
> length(unique(out$random[out$part == "dt_ex2"]))        # expectation: 6000
[1] 6000

2. 现在请取消注释分配最终分数的代码段 *[tmp_sim] = 3(应该是第 60,61,67,68 行!!!在他们身上)并再次运行它。

> # ====== Distinct Random Numbers ======
> length(unique(out$random))                              # expectation: 22000
[1] 10360
> length(unique(out$random[out$part == "base"]))          # expectation: 10000
[1] 10000
> length(unique(out$random[out$part == "dt_ex1"]))        # expectation: 6000
[1] 180
> length(unique(out$random[out$part == "dt_ex2"]))        # expectation: 6000
[1] 180

那就是事情变得混乱并且对我来说没有意义的时候。random inside iter对于dt_ex1 and dt_ex2当向这些数据框中添加几个数字时。

您是否也经历过同样的效果?知道发生了什么事吗?

我尝试了 R 版本 3.5.3 和 3.6.3。也尝试过doRNG包裹。总是同样的问题。

联赛模拟代码

# League Simulation
rm(list = ls())
set.seed(666)
cat("\014")
library(sqldf)
library(plyr)
library(dplyr)

# ====== User Functions ======
comb4 = function(x, ...) { #function for combining foreach output
  Map(rbind, x, ...)
}

# ====== Data Preparation ======
dt_base = data.frame(id = 1:10,
                  part = rep("base",10),
                  random = NA)

dt_ex1 = data.frame(id = 1:10,
                         part = rep("dt_ex1",10),
                         HG = c(1,3,6,NA,NA,2,NA,NA,NA,NA),  # Home Goals
                         AG = c(1,3,6,NA,NA,2,NA,NA,NA,NA),  # Away Goals
                         random = NA)

dt_ex2 = data.frame(id = 1:10,
                            part = rep("dt_ex2",10),
                         HG = c(1,3,6,NA,NA,2,NA,NA,NA,NA),  # Home Goals
                         AG = c(1,3,6,NA,NA,2,NA,NA,NA,NA),  # Away Goals
                         random = NA)

# ====== Set Parallel Computing ======
library(foreach)
library(doParallel)

cl = makeCluster(3, outfile = "")
registerDoParallel(cl)

# ====== SIMULATION ======
nsim = 1000                # number of simulations
iterChunk = 100            # split nsim into this many chunks
out = data.frame()    # prepare output DF
for(iter in 1:ceiling(nsim/iterChunk)){
  strt = Sys.time()
  
  out_iter = 
    foreach(i = 1:iterChunk, .combine = comb4, .multicombine = TRUE, .maxcombine = 100000, .inorder = FALSE, .verbose = FALSE,
            .packages = c("plyr", "dplyr", "sqldf")) %dopar% {
              
              ## PART 1
              # simulation number
              id_sim = iterChunk * (iter - 1) + i
              
              # First random numbers set
              dt_base[,"random"] = runif(nrow(dt_base))
              
              
              ## PART 2
              tmp_sim = is.na(dt_ex1$HG) # no results yet
              dt_ex1$random[tmp_sim] = runif(sum(tmp_sim))
              # dt_ex1$HG[tmp_sim] = 3   # !!!
              # dt_ex1$AG[tmp_sim] = 3   # !!!
              
              
              ## PART 3
              tmp_sim = is.na(dt_ex2$HG) # no results yet
              dt_ex2$random[tmp_sim] = runif(sum(tmp_sim))
              # dt_ex2$HG[tmp_sim] = 3   # !!!
              # dt_ex2$AG[tmp_sim] = 3   # !!!
              
              
              # ---- Save Results
              zapasy = rbind.data.frame(dt_base[,c("id","part","random")],
                                        dt_ex1[,c("id","part","random")]
                                        ,dt_ex2[,c("id","part","random")]
              )
              zapasy$id_sim = id_sim
              zapasy$iter = iter
              zapasy$i = i
              
              out_i = list(zapasy = zapasy)
              
              print(Sys.time())
              return(out_i)
            }#i;sim_forcycle
  
  out = rbind.data.frame(out,subset(out_iter$zapasy, !is.na(random)))
  
  fnsh = Sys.time()
  cat(" [",iter,"] ",fnsh - strt, sep = "")
  
}#iter


# ====== Distinct Random Numbers ======
length(unique(out$random))                              # expectation: 22000
length(unique(out$random[out$part == "base"]))          # expectation: 10000
length(unique(out$random[out$part == "dt_ex1"]))        # expectation: 6000
length(unique(out$random[out$part == "dt_ex2"]))        # expectation: 6000


# ====== Stop Parallel Computing ======
stopCluster(cl)


R 使用的随机生成器(包括set.seed and runif) 是全局的并且适用于整个应用程序。

看来您的问题正在发生,因为生成器的访问在并行进程之间共享,但这些进程之间不同步(即,它不是“线程安全”),因此每个进程都有自己的生成器状态视图(因此因此,由于这种不同步的访问,不同的进程可以绘制完全相同的随机数)。相反,您应该为每个并行进程(在本例中为每个模拟)提供其自己的随机生成器,该生成器不在进程之间共享,并且每个进程的种子 https://peteroupc.github.io/random.html#Seeding_Multiple_Processes(或模拟)相应地。

多线程是其中之一许多问题需要考虑 https://peteroupc.github.io/random.html#Ensuring_Reproducibility当您关心可重复的“随机”数字时。


事实证明,根本问题更多是由数据框在进程之间共享,而不是 R 的全局 RNG。看到这个问题使用 R 进行多线程计算:如何获得所有不同的随机数? https://stackoverflow.com/questions/62758637/multithread-computation-with-r-how-to-get-all-different-random-numbers .

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

一段 R 代码会影响 foreach 输出中的随机数吗? 的相关文章

随机推荐