Чейз дает отличный ответ и упоминает проблему повторения while()
.Одна из проблем, связанных с побегом while()
, заключается в том, что если вы делаете это одно испытание за раз, и потребуется много, скажем t , испытаний, чтобы найти то, которое соответствует целевому числу 1
s, вы получаете накладные расходы на t вызовов основной функции, в данном случае rbinom()
.
Однако есть выход, потому что rbinom()
, как и всеэти (псевдо) генераторы случайных чисел в R векторизованы, мы можем генерировать 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) ## return object
## draw chunkSize trials
trial <- matrix(rbinom(len * chunkSize, 1, probs),
ncol = len, byrow = TRUE)
rs <- rowSums(trial) ## How manys `1`s
ok <- which(rs == 5L) ## which meet the `target`
found <- length(ok) ## how many meet the target
if(found > 0) ## if we found some, add them to out
out <- rbind(out,
trial[ok, , drop = FALSE][seq_len(min(n,found)), ,
drop = FALSE])
## if we haven't found enough, repeat the whole thing until we do
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) ## comment this, and
out <- drop(out) ## this if you don't want dimension dropping
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
за один раз, если вы хотите только одно или два, так как вы должны оценивать каждую пробную игру.