Chase提供了一个很好的答案,并提到了while()迭代的问题。run-away while()的一个问题是,如果您一次只做一个试验,并且需要很多次,比如t次才能找到符合目标数字1的数量,则会产生t次对主函数rbinom()的调用开销。
然而,有一种方法可以解决这个问题,因为像R中所有这些(伪)随机数生成器一样,rbinom()也是向量化的,我们可以一次生成m个试验,并检查这些m个试验是否符合5个1的要求。如果没有找到,则反复绘制m个试验,直到找到符合要求的试验。这个想法在下面的函数foo()中实现。chunkSize参数是m,表示一次绘制的试验数量。我还利用这个机会允许函数查找不止一个符合条件的试验;n参数控制返回多少个符合条件的试验。
foo <- function(probs, target, n = 1, chunkSize = 100) {
len <- length(probs)
out <- matrix(ncol = len, nrow = 0)
trial <- matrix(rbinom(len * chunkSize, 1, probs),
ncol = len, byrow = TRUE)
rs <- rowSums(trial)
ok <- which(rs == 5L)
found <- length(ok)
if(found > 0)
out <- rbind(out,
trial[ok, , drop = FALSE][seq_len(min(n,found)), ,
drop = FALSE])
while(found < n) {
trial <- matrix(rbinom(len * chunkSize, 1, probs),
ncol = len, byrow = TRUE)
rs <- rowSums(trial)
ok <- which(rs == 5L)
New <- length(ok)
if(New > 0) {
found <- found + New
out <- rbind(out, trial[ok, , drop = FALSE][seq_len(min(n, New)), ,
drop = FALSE])
}
}
if(n == 1L)
out <- drop(out)
out
}
它的工作原理如下:
> set.seed(1)
> foo(probs, target = 5)
[1] 1 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0
[31] 0
> foo(probs, target = 5, n = 2)
[,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10] [,11]
[1,] 0 0 0 0 0 0 0 0 0 0 0
[2,] 0 0 0 0 0 0 0 0 0 0 1
[,12] [,13] [,14] [,15] [,16] [,17] [,18] [,19] [,20] [,21]
[1,] 0 0 0 1 1 0 0 0 0 0
[2,] 0 1 0 0 1 0 0 0 0 0
[,22] [,23] [,24] [,25] [,26] [,27] [,28] [,29] [,30] [,31]
[1,] 1 0 1 0 0 0 1 0 0 0
[2,] 1 0 1 0 0 0 0 0 0 0
请注意,当
n == 1
时,我会删除空维度。如果您不需要此功能,请将最后一个
if
代码块注释掉。
您需要平衡
chunkSize
的大小和同时检查那么多次数的计算负担。如果要求(这里是 5 个
1
)非常不可能发生,则增加
chunkSize
,以便减少对
rbinom()
的调用次数。如果该要求很可能被满足,则每次绘制试验和大量的
chunkSize
是没有意义的,因为您必须评估每次试验的绘制。