使用mclapply控制种子

9
想象一下,我们正在进行多个处理过程,我想在程序开始时设置一个总体种子,如下所示:
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相同,这不是我想要的...


你可以使用 clusterSetupRNG... https://dev59.com/62sy5IYBdhLWcg3wtwa9 - user20650
谢谢,但是(doRNG)库的示例似乎已经过时且不再可用,而clusterSetupRNG也不完全符合我的要求,除非你能向我展示其他方面。 - user1320502
似乎已经略有改变...请查看doRNG参考手册的第三页。 或使用snow - user20650
实际上?'%dorng%'的帮助页面给出了一个例子。 - user20650
1个回答

10

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 的两次调用将返回相同的结果。这是因为主进程中的随机数生成器状态通过调用 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)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接