用 mclapply 控制种子

controlling seeds with mclapply

假设我们正在做一些我想在程序开始时设置一个整体种子的过程:例如

mylist <- list( as.list(rep(NA,3)), as.list(rep(NA,3)) )
foo <- function(x){  for(i in 1:length(x)){ 
                       x[[i]] <- sample(100,1)
                         }
                      return(x) 
                     } 

# start block
set.seed(1)
l1 <- lapply(mylist, foo)
l2 <- lapply(mylist, foo)
# end

当然在一个块内 l1l2 是不同的,但是如果我 运行 上面的块再次 l1 将与以前相同并且 l2 将与以前相同。

假设 foo 非常耗时,所以我想使用 mclapply 而不是 lapply,所以我这样做:

library(parallel)

# start block
set.seed(1)
mclapply(mylist , foo,  mc.cores = 3)
mclapply(mylist , foo,  mc.cores = 3)
# end

如果我再次运行这个块,下次我会得到不同的结果。如何产生与使用 lapply 但使用 mclappy 设置一个整体种子相同的行为。我查看了 mclapply 文档,但我不确定,因为使用:

set.seed(1)
l1 <-  mclapply(mylist , foo,  mc.cores = 3, mc.set.seed=FALSE)
l2 <-  mclapply(mylist , foo,  mc.cores = 3, mc.set.seed=FALSE)

结果l1l2一样,这不是我想要的...

parallel 软件包特别支持 "L'Ecuyer-CMRG" 随机数生成器,它与 parallel 同时引入。您可以使用以下方式阅读该支持的文档:

library(parallel)
?mc.reset.stream

要使用它,您首先需要启用"L'Ecuyer-CMRG":

RNGkind("L'Ecuyer-CMRG")

完成后,代码如下:

set.seed(1)
mclapply(mylist, foo, mc.cores=3)
mclapply(mylist, foo, mc.cores=3)

将是可重现的,但是对 mclapply 的两次调用将 return 产生相同的结果。这是因为调用 mclapply.

不会改变主进程中随机数生成器的状态

我使用以下函数跳过 mclapply 工作人员使用的随机数流:

skip.streams <- function(n) {
  x <- .Random.seed
  for (i in seq_len(n))
    x <- nextRNGStream(x)
  assign('.Random.seed', x, pos=.GlobalEnv)
}

您可以使用此函数来获得我认为您想要的行为:

set.seed(1)
mclapply(mylist, foo, mc.cores=3)
skip.streams(3)
mclapply(mylist, foo, mc.cores=3)
skip.streams(3)