[英]Efficient way to sample from different probability vectors
我正在尋找一種更有效的方法來從整數列表1:n中抽樣,多次,其中概率向量(也是長度n)每次都不同。 對於n = 10的20次試驗,我知道可以這樣做:
probs <- matrix(runif(200), nrow = 20)
answers <- numeric(20)
for(i in 1:20) answers[i] <- sample(10,1,prob=probs[i,])
但是,每次調用樣本10次只是為了得到一個數字,所以它可能不是最快的方式。 速度會有所幫助,因為代碼會這么做很多次。
非常感謝!
盧克
編輯:非常感謝Roman,他對基准測試的想法幫助我找到了一個很好的解決方案。 我現在把它轉到了答案。
只是為了好玩,我嘗試了兩個版本。 你在做這個抽樣的規模是多少? 我認為所有這些都非常快,並且或多或少相當(我沒有為您的解決方案創建probs)。 很想看到別人對此有所了解。
library(rbenchmark)
benchmark(replications = 1000,
luke = for(i in 1:20) answers[i] <- sample(10,1,prob=probs[i,]),
roman = apply(probs, MARGIN = 1, FUN = function(x) sample(10, 1, prob = x)),
roman2 = replicate(20, sample(10, 1, prob = runif(10))))
test replications elapsed relative user.self sys.self user.child sys.child
1 luke 1000 0.41 1.000 0.42 0 NA NA
2 roman 1000 0.47 1.146 0.46 0 NA NA
3 roman2 1000 0.47 1.146 0.44 0 NA NA
這是我找到的另一種方法。 它速度很快,但沒有像使用for循環多次調用樣本那么快。 我最初認為它非常好,但我錯誤地使用了基准()。
luke2 = function(probs) { # takes a matrix of probability vectors, each in its own row
probs <- probs/rowSums(probs)
probs <- t(apply(probs,1,cumsum))
answer <- rowSums(probs - runif(nrow(probs)) < 0) + 1
return(answer) }
以下是它的工作原理:將概率描述為從0到1的數字線上排列的各種長度的線。大概率的數字線路將占據數字線路的大部分。 然后,您可以通過在數字線上選擇一個隨機點來選擇結果 - 大概率將更有可能被選中。 這種方法的優點是你可以滾動一次runif()調用所需的所有隨機數,而不是像函數luke,roman和roman2那樣反復調用樣本。 但是,看起來額外的數據處理速度會降低速度並且成本會抵消這一優勢。
library(rbenchmark)
probs <- matrix(runif(2000), ncol = 10)
answers <- numeric(200)
benchmark(replications = 1000,
luke = for(i in 1:20) answers[i] <- sample(10,1,prob=probs[i,]),
luke2 = luke2(probs),
roman = apply(probs, MARGIN = 1, FUN = function(x) sample(10, 1, prob = x)),
roman2 = replicate(20, sample(10, 1, prob = runif(10))))
roman = apply(probs, MARGIN = 1, FUN = function(x) sample(10, 1, prob = x)),
roman2 = replicate(20, sample(10, 1, prob = runif(10))))
test replications elapsed relative user.self sys.self user.child sys.child
1 luke 1000 0.171 1.000 0.166 0.005 0 0
2 luke2 1000 0.529 3.094 0.518 0.012 0 0
3 roman 1000 1.564 9.146 1.513 0.052 0 0
4 roman2 1000 0.225 1.316 0.213 0.012 0 0
出於某種原因,當您添加更多行時,apply()會非常糟糕。 我不明白為什么,因為我認為它是for()的包裝器,因此roman()應該與luke()類似地執行。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.