种子设置:为什么输入不变后输出不同

Seed setting: why is the output different after no change in input

设置种子可确保可重复性,这在模拟建模中很重要。考虑一个简单模型 f(),其中包含两个感兴趣的变量 y1y2。这些变量的输出由随机过程 (rbinom()) 和参数 x1x2 决定。感兴趣的两个变量的输出相互独立。

现在假设我们要比较相应参数发生变化后变量输出的变化与发生变化之前的场景(即敏感性分析)。如果没有更改所有其他参数并且设置了相同的种子,那么不受影响的变量的输出不应该保持与默认模拟中的相同,因为这个变量独立于其他变量吗?

简而言之,尽管设置了常量种子,为什么仅在 x1 发生变化后由参数 x2 确定的变量 y2 的以下输出发生变化?可以忽略 y2 的输出而只关注 y1,但在更大的模拟中,每个变量都是总成本的成本组成部分,在测试更改单个参数后模型的整体灵敏度。

#~ parameters and model

x1 <- 0.0
x2 <- 0.5
n  <- 10
ts <- 5

f <- function(){
  out <- data.frame(step = rep(0, n),
                    space = 1:n,
                    id = 1:n,
                    y1 = rep(1, n),
                    y2 = rep(0, n))
  
  l.out <- vector(mode = "list", length = n)
  
  for(i in 1:ts){
    out$step <- i
    out$y1[out$y1 == 0] <- 1
    out$id[out$y2 == 1]  <- seq_along(which(out$y2 == 1)) + n
    out$y2[out$y2 == 1] <- 0
    
    out$y1 <- rbinom(nrow(out), 1, 1-x1)
    out$y2 <- rbinom(nrow(out), 1, x2)
    
    n  <- max(out$id)
    l.out[[i]] <- out
  }
do.call(rbind, l.out)
}

#~ Simulation 1 (default)
set.seed(1)
run1 <- f()
set.seed(1)
run2 <- f()
run1 == run2 #~ all observations true as expected

#~ Simulation 2
#~ change in x1 parameter affecting only variable y1
x1 <- 0.25
set.seed(1)
run3 <- f()
set.seed(1)
run4 <- f()
run3 == run4 #~ all observations true as expected

#~ compare variables after change in x1 has occured
run1$y1 == run3$y1  #~ observations differ as expected
run1$y2 == run3$y2  #~ observations differ - why?

好问题。此行为的原因是当您在 rbinom 中设置 p = 0p = 1 时,底层 C 函数意识到它不需要使用随机数生成器进行采样。种子仅在调用随机数生成器时发生变化,因此如果 p 是任何严格 介于 0 和 1 之间的数字,种子将发生变化,但如果 p是 0 或 1 它不会。你可以看到这是 source code.

在正常情况下,当 p 大于零或小于一时,您的设置应该可以正常工作:

set.seed(1)
x1 <- rbinom(5, 1, 0.4)
y1 <- rbinom(5, 1, 0.5)

set.seed(1)
x2 <- rbinom(5, 1, 0.1)
y2 <- rbinom(5, 1, 0.5)

all(y1 == y2)
#> [1] TRUE

但是如果你把p设置为1或者0,结果就会不同:

set.seed(1)
x1 <- rbinom(5, 1, 0.4)
y1 <- rbinom(5, 1, 0.5)

set.seed(1)
x2 <- rbinom(5, 1, 1)
y2 <- rbinom(5, 1, 0.5)

all(y1 == y2)
#> [1] FALSE

为了证明这是正确的,如果我们第一次将 p 设置为 1,第二次将 p 设置为 0,我们应该得到 y1 == y2

set.seed(1)
x1 <- rbinom(5, 1, 0)
y1 <- rbinom(5, 1, 0.5)

set.seed(1)
x2 <- rbinom(5, 1, 1)
y2 <- rbinom(5, 1, 0.5)

all(y1 == y2)
#> [1] TRUE