45

我发现了我认为在R使用种子rbinom()时会出现的不稳定行为(但我希望有一个简单的解释) prob=0.5。总体思路:对我来说,如果我设置种子,运行rbinom()一次(即执行一个随机过程),不管prob设置什么值,随机种子应该改变一个增量。然后,如果我再次将种子设置为相同的值,并运行另一个随机过程(例如rbinom()再次,但可能使用不同的值prob),种子应该再次更改为与之前的单个随机过程相同的值.

我发现R只要我使用rbinom()any就可以做到这一点prob!=0.5。这是一个例子:

.Random.seed比较0.5 以外的两个概率的种子向量 , :

set.seed(234908)
x <- rbinom(n=1,size=60,prob=0.4)
temp1 <- .Random.seed

set.seed(234908)
x <- rbinom(n=1,size=60,prob=0.3)
temp2 <- .Random.seed

any(temp1!=temp2)
> [1] FALSE

.Random.seed比较prob=0.5 与 prob!=0.5 的种子向量 ,

set.seed(234908)
x <- rbinom(n=1,size=60,prob=0.5)
temp1 <- .Random.seed

set.seed(234908)
x <- rbinom(n=1,size=60,prob=0.3)
temp2 <- .Random.seed
any(temp1!=temp2)
> [1] TRUE

temp1==temp2
> [1]  TRUE FALSE  TRUE  TRUE  TRUE  TRUE  TRUE
> [8]  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE
...

prob=0.5对于集合 {0.1, 0.2, ..., 0.9} 中的所有其他概率,我发现了这一点。同样,如果我比较prob{0.1, 0.2, ..., 0.9} 中除 0.5 以外的任何值,则.Random.seed向量始终是逐个元素相等的。这些事实也适用于奇数或偶数sizerbinom()

为了让它更奇怪(我很抱歉这有点令人费解 - 它与我的函数编写方式有关),当我使用保存为向量中元素的概率时,如果 0.5 是第一个元素,我会遇到同样的问题,但不是第二。这是此案例的示例:

第一种情况:0.5是向量中引用的第一个概率

set.seed(234908)
MNAR <- c(0.5,0.3)
x <- rbinom(n=1,size=60,prob=MNAR[1])
y <- rbinom(n=1,size=50,prob=MNAR[2])
temp1 <- .Random.seed

set.seed(234908)
MNAR <- c(0.1,0.3)
x <- rbinom(n=1,size=60,prob=MNAR[1])
y <- rbinom(n=1,size=50,prob=MNAR[2])
temp2 <- .Random.seed

any(temp1!=temp2)
> [1] TRUE

any(temp1!=temp2)
> [1]  TRUE FALSE  TRUE  TRUE  TRUE  TRUE  TRUE
> [8]  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE

第二种情况:0.5是向量中引用的第二个概率

set.seed(234908)
MNAR <- c(0.3,0.5)
x <- rbinom(n=1,size=60,prob=MNAR[1])
y <- rbinom(n=1,size=50,prob=MNAR[2])
temp1 <- .Random.seed

set.seed(234908)
MNAR <- c(0.1,0.3)
x <- rbinom(n=1,size=60,prob=MNAR[1])
y <- rbinom(n=1,size=50,prob=MNAR[2])
temp2 <- .Random.seed

any(temp1!=temp2)
> [1] FALSE

再一次,我发现尽管使用了proband的值,但size这种模式仍然成立。谁能给我解释一下这个谜?这引起了相当大的问题,因为应该相同的结果会出现不同的结果,因为由于某种原因,种子的使用/计算方式不同,prob=0.5但在其他情况下没有。

4

2 回答 2

40

所以让我们把我们的评论变成一个答案。感谢 Ben Bolker 通过代码链接使我们走上正轨:https ://svn.r-project.org/R/trunk/src/nmath/rbinom.c以及跟踪unif_rand()调用位置的建议.

快速扫描一下,代码似乎分为两部分,由注释分隔:

/*-------------------------- np = n*p >= 30 : ------------------- */

/*---------------------- np = n*p < 30 : ------------------------- */

在其中的每一个中,调用的数量unif_rand都不相同(两个对一个。)

因此,对于给定的size( n),您的随机种子可能最终处于不同的状态,具体取决于prob( p) 的值:是否size * prob >= 30

考虑到这一点,您通过示例获得的所有结果现在应该是有意义的:

# these end up in the same state
rbinom(n=1,size=60,prob=0.4) # => np <  30
rbinom(n=1,size=60,prob=0.3) # => np <  30

# these don't
rbinom(n=1,size=60,prob=0.5) # => np >= 30
rbinom(n=1,size=60,prob=0.3) # => np <  30

# these don't
{rbinom(n=1,size=60,prob=0.5)  # np >= 30
 rbinom(n=1,size=50,prob=0.3)} # np <  30
{rbinom(n=1,size=60,prob=0.1)  # np <  30
 rbinom(n=1,size=50,prob=0.3)} # np <  30

# these do
{rbinom(n=1,size=60,prob=0.3)  # np <  30
 rbinom(n=1,size=50,prob=0.5)} # np <  30
{rbinom(n=1,size=60,prob=0.1)  # np <  30
 rbinom(n=1,size=50,prob=0.3)} # np <  30
于 2013-09-20T04:08:49.117 回答
15

我将在这个问题上采取相反的立场,并声称期望是不合适的,并且没有得到文档的支持。.Random.seed该文档没有就调用可以预期哪些副作用(特别是在 上) rbinom,或者这些副作用在各种情况下可能相同或可能不同做出任何声明。

rbinom具有三个参数:nsizeprob。您的期望是,对于调用之前的随机种子集,在调用给定值和and的任何值(或者可能是and的任何有限值)rbinom之后.Random.seed将是相同的。您当然意识到不同的值会有所不同。不保证或暗示。rbinomnsizeprobsizeprobnrbinom

在不知道函数内部的情况下,这是无法知道的;正如另一个答案所示,该算法基于 和 的乘积而有所size不同prob。内部结构可能会发生变化,因此这些具体细节可能会发生变化。

至少,在这种情况下,每次调用都具有相同的,.Random.seed,结果将是相同的。我可以构建一个甚至不正确的病理函数:rbinom nsize prob

seedtweak <- function() {
  if(floor(as.POSIXlt(Sys.time())$sec * 10) %% 2) {
    runif(1)
  }
  invisible(NULL)
}

基本上,这个函数看一个时间的十分之一是奇数还是偶数来决定是否抽取一个随机数。运行这个函数,.Random.seed可能会也可能不会改变:

rs <- replicate(10, {
  set.seed(123) 
  seedtweak()
  .Random.seed
})
all(apply(rs, 1, function(x) Reduce(`==`, x)))

您可以(应该?)希望的最好结果是所有输入/参数相同(包括种子)的给定代码集将始终给出相同的结果。当只有大多数(或只有部分)参数相同时,期望相同的结果是不现实的,除非所有调用的函数都做出这些保证。

于 2013-09-20T16:16:08.850 回答