這裏的另一種方法,我發現。它速度很快,但速度並不像使用for循環多次調用樣本那麼快。我最初認爲它非常好,但我錯誤地使用了benchmark()。
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()的操作。
+1您應該添加隨機卷解答作爲解決方案。這是一個非常酷的方法!你有沒有檢查它是如何可縮放的? –
重要的是要注意R'sample'函數中的'prob'參數*沒有替換*並不與一階包含概率成正比。如果你想保留這個,那麼看看package'sampling' @ CRAN。 –
感謝您的投入。費迪南德,你讓我失去了一點點,但我想在這個例子中,這並不重要,因爲樣本的長度爲1(因此在有和沒有替換的情況下抽樣是相同的)。此外,luke2中的解決方案完全避免了樣本。我將把它列爲解決方案。 – lukeholman