R 使设置随机种子的函数独立

R 使设置随机种子的函数独立,r,random,random-sample,random-seed,R,Random,Random Sample,Random Seed,有时我想编写一个随机化函数,它总是为特定的输入返回相同的输出。我总是通过在函数顶部设置随机种子然后继续来实现这一点。考虑以这种方式定义的两个函数: sample.12 <- function(size) { set.seed(144) sample(1:2, size, replace=TRUE) } rand.prod <- function(x) { set.seed(144) runif(length(x)) * x } 在这种情况下,我可以通过将其中一个函

有时我想编写一个随机化函数,它总是为特定的输入返回相同的输出。我总是通过在函数顶部设置随机种子然后继续来实现这一点。考虑以这种方式定义的两个函数:

sample.12 <- function(size) {
  set.seed(144)
  sample(1:2, size, replace=TRUE)
}
rand.prod <- function(x) {
  set.seed(144)
  runif(length(x)) * x
}

在这种情况下,我可以通过将其中一个函数中的随机种子更改为其他值来解决此问题。例如,在
rand.prod
中使用
set.seed(10000)
可以得到预期的分布:

这种使用不同种子的解决方案被认为是生成独立随机数流的最佳方法。然而,我发现解决方案并不令人满意,因为具有不同种子的流可能相互关联(甚至可能);事实上,根据set.seed,它们甚至可能产生相同的流:

无法保证不同的种子值会以不同的方式为RNG种子,尽管任何例外情况都极为罕见

有没有办法在R中实现一对随机函数:

  • 始终为特定输入返回相同的输出,并且
  • 除了使用不同的随机种子外,还可以加强随机性源之间的独立性

  • 我对此进行了深入研究,它看起来像是
    rlecuyer
    包提供了独立的随机流:

    为L'Ecuyer等人(2002)开发的具有多个独立流的随机数生成器的C实现提供接口。该软件包的主要目的是使该随机数生成器能够在并行R应用中使用

    第一步是独立流的全局初始化:

    library(rlecuyer)
    .lec.CreateStream(c("stream.12", "stream.prod"))
    
    然后需要修改每个函数,将相应的流重置为其开始状态(
    .lec.restartstream
    ),将R随机数生成器设置为相应的流(
    .lec.CurrentStream
    ),然后将R随机数生成器设置回调用函数之前的状态(
    .lec.CurrentStreamEnd

    在我们的示例中,流似乎也独立运行:

    x <- sample.12(10000)
    hist(rand.prod(x))
    
    然后,我们可以将脚本开头的流初始化更改为:

    library(rlecuyer)
    .lec.CreateStream(c("stream.12", "stream.prod"))
    .lec.SetSeed("stream.12", c(3161578179, 1307260052, 2724279262, 1101690876, 1009565594, 836476762))
    .lec.SetSeed("stream.prod", c(596094074, 2279636413, 3050913596, 1739649456, 2368706608, 3058697049))
    

    现在对
    sample.12
    rand.prod
    的调用将匹配对脚本的调用。

    这是一个很好的发现。为了完整性起见,
    rlecuyer
    使用了
    MRG32k3a
    (第1.1章),因此它也可能有其局限性(就像Mersenne Twister那样)。但在99%的情况下应该不会有太大问题。
    all.equal(rand.prod(sample.12(10000)), rand.prod(sample.12(10000)))
    # [1] TRUE
    
    x <- sample.12(10000)
    hist(rand.prod(x))
    
    .lec.GetState("stream.12")
    # [1] 3161578179 1307260052 2724279262 1101690876 1009565594  836476762
    .lec.GetState("stream.prod")
    # [1]  596094074 2279636413 3050913596 1739649456 2368706608 3058697049
    
    library(rlecuyer)
    .lec.CreateStream(c("stream.12", "stream.prod"))
    .lec.SetSeed("stream.12", c(3161578179, 1307260052, 2724279262, 1101690876, 1009565594, 836476762))
    .lec.SetSeed("stream.prod", c(596094074, 2279636413, 3050913596, 1739649456, 2368706608, 3058697049))