Chase cung cấp một câu trả lời tuyệt vời và đề cập đến vấn đề của việc lặp đi lặp lại while()
. Một trong những vấn đề với việc chạy trốn while()
là nếu bạn thực hiện một lần thử này tại một thời điểm và phải mất rất nhiều, giả sử t, các thử nghiệm để tìm một kết quả phù hợp với số mục tiêu là 1
s, bạn phải chịu chi phí t cuộc gọi đến chức năng chính, rbinom()
trong trường hợp này.
Có một lối thoát, tuy nhiên, vì rbinom()
, giống như tất cả trong số này (giả) máy phát điện số ngẫu nhiên trong R, được vectorised, chúng ta có thể tạo ra m thử nghiệm tại một thời điểm và kiểm tra những m thử nghiệm cho phù hợp theo yêu cầu của 5 1
s. Nếu không tìm thấy chúng tôi, chúng tôi sẽ liên tục vẽ m bản dùng thử cho đến khi chúng tôi tìm thấy bản dùng thử phù hợp. Ý tưởng này được thực hiện trong hàm foo()
bên dưới. Đối số chunkSize
là m, số lần thử để vẽ tại một thời điểm. Tôi cũng đã tận dụng cơ hội này để cho phép hàm tìm kiếm nhiều hơn một thử nghiệm duy nhất; đối số n
kiểm soát số lượng thử nghiệm phù hợp để trả lại.
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
}
Nó hoạt động như thế này:
> 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
Lưu ý rằng tôi thả kích thước trống trong trường hợp n == 1
. Hãy chú ý đoạn mã if
cuối cùng nếu bạn không muốn tính năng này.
Bạn cần cân bằng kích thước chunkSize
với gánh nặng tính toán khi kiểm tra nhiều lần thử nghiệm tại một thời điểm.Nếu yêu cầu (ở đây 5 1
s) là rất khó xảy ra, sau đó tăng chunkSize
để bạn phải thực hiện các cuộc gọi ít hơn đến rbinom()
. Nếu có yêu cầu, có ít thử nghiệm vẽ điểm và lớn chunkSize
tại một thời điểm nếu bạn chỉ muốn một hoặc hai khi bạn phải đánh giá mỗi lần rút thăm thử.
"Tổng số tiền của vectơ phải luôn là một". Ý bạn là "... nên luôn luôn là năm"? – Chase
Bạn nói đúng! Tôi sửa nó rồi. Cảm ơn bạn. – Laura