[英]Enumerate all possible combined probabilities of a series of Bernoulli trials with different probabilities
假設我有一系列獨立伯努利試驗成功的 n 概率,p1 到 pn,使得 p1 != p2 != ... != pn。 給每個試驗一個唯一的名稱。
p <- c(0.5, 0.12, 0.7, 0.8, .02)
a <- c("A","B","C","D","E")
我通過搜索堆棧交換(例如, here和here )知道我可以使用泊松二項分布函數找到 cdf、pmf 等。
我感興趣的是成功和失敗的每種可能組合的確切概率。 (例如,如果我畫了一個概率樹,我想知道每個分支末尾的概率。)
all <- prod(p)
all
[1] 0.000672
o1 <- (0.5 * (1-0.12) * 0.7 * 0.8 * .02)
o1
[1] 0.004928
o2 <- (0.5 * 0.12 * (1-0.7) * 0.8 * .02)
o2
[1] 0.000288
...對於所有 2^5 種可能的成功/失敗組合。
在 R 中解決這個問題的有效方法是什么?
在我的實際數據集的情況下,試驗次數是 19,所以我們談論的是概率樹上的 2^19 條總路徑。
使此計算快速的關鍵是在對數概率空間中進行,以便樹的每個分支的乘積是一個總和,可以作為矩陣乘法的內部總和進行計算。 以這種方式,可以以矢量化方式一起計算所有分支。
首先,我們構造一個所有分支的枚舉。 為此,我們使用R.utils
包中的intToBin
函數:
library(R.utils)
enum.branches <- unlist(strsplit(intToBin(seq_len(2^n)-1),split=""))
其中n
是伯努利變量的數量。 對於您的示例, n=5
:
matrix(enum.branches, nrow=n)
## [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10] [,11] [,12] [,13] [,14] [,15] [,16] [,17]
##[1,] "0" "0" "0" "0" "0" "0" "0" "0" "0" "0" "0" "0" "0" "0" "0" "0" "1"
##[2,] "0" "0" "0" "0" "0" "0" "0" "0" "1" "1" "1" "1" "1" "1" "1" "1" "0"
##[3,] "0" "0" "0" "0" "1" "1" "1" "1" "0" "0" "0" "0" "1" "1" "1" "1" "0"
##[4,] "0" "0" "1" "1" "0" "0" "1" "1" "0" "0" "1" "1" "0" "0" "1" "1" "0"
##[5,] "0" "1" "0" "1" "0" "1" "0" "1" "0" "1" "0" "1" "0" "1" "0" "1" "0"
## [,18] [,19] [,20] [,21] [,22] [,23] [,24] [,25] [,26] [,27] [,28] [,29] [,30] [,31] [,32]
##[1,] "1" "1" "1" "1" "1" "1" "1" "1" "1" "1" "1" "1" "1" "1" "1"
##[2,] "0" "0" "0" "0" "0" "0" "0" "1" "1" "1" "1" "1" "1" "1" "1"
##[3,] "0" "0" "0" "1" "1" "1" "1" "0" "0" "0" "0" "1" "1" "1" "1"
##[4,] "0" "1" "1" "0" "0" "1" "1" "0" "0" "1" "1" "0" "0" "1" "1"
##[5,] "1" "0" "1" "0" "1" "0" "1" "0" "1" "0" "1" "0" "1" "0" "1"
結果是一個矩陣,其中每一列都是概率樹分支的結果。
現在,使用該構造相同尺寸的對數概率的矩陣enum.branches
其中值是log(p)
如果enum.branches=="1"
和log(1-p)
否則。 對於您的數據, p <- c(0.5, 0.12, 0.7, 0.8, .02)
,這是:
logp <- matrix(ifelse(enum.branches == "1", rep(log(p), 2^n), rep(log(1-p), 2^n)), nrow=n)
然后,對對數概率求和並取指數以得到概率的乘積:
result <- exp(rep(1,n) %*% logp)
## [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10]
##[1,] 0.025872 0.000528 0.103488 0.002112 0.060368 0.001232 0.241472 0.004928 0.003528 7.2e-05
[,11] [,12] [,13] [,14] [,15] [,16] [,17] [,18] [,19] [,20]
##[1,] 0.014112 0.000288 0.008232 0.000168 0.032928 0.000672 0.025872 0.000528 0.103488 0.002112
[,21] [,22] [,23] [,24] [,25] [,26] [,27] [,28] [,29] [,30]
##[1,] 0.060368 0.001232 0.241472 0.004928 0.003528 7.2e-05 0.014112 0.000288 0.008232 0.000168
[,31] [,32]
##[1,] 0.032928 0.000672
result
將與enum.branches
中分支的enum.branches
順序相同。
我們可以將計算封裝成一個函數:
enum.prob.product <- function(n, p) {
enum.branches <- unlist(strsplit(intToBin(seq_len(2^n)-1),split=""))
exp(rep(1,n) %*% matrix(ifelse(enum.branches == "1", rep(log(p), 2^n), rep(log(1-p), 2^n)), nrow=n))
}
用19
獨立的伯努利變量計時:
n <- 19
p <- runif(n)
system.time(enum.prob.product(n,p))
## user system elapsed
## 24.064 1.470 26.082
這是在我的 2 GHz MacBook(大約 2009 年)上。 應該注意的是,計算本身是相當快的; 它是概率樹的分支的枚舉(我猜是其中的unlist
)占用了大部分時間。 來自社區的關於另一種方法的任何建議將不勝感激。
只需在基礎 R 中試試這個:
p <- c(0.5, 0.12, 0.7, 0.8, .02)
a <- c("A","B","C","D","E")
n <- length(p)
apply(expand.grid(replicate(n,list(0:1)))[n:1], 1,
function(x) prod(p[which(x==1)])*prod(1-p[which(x==0)]))
#[1] 0.025872 0.000528 0.103488 0.002112 0.060368 0.001232 0.241472 0.004928 0.003528 0.000072 0.014112 0.000288 0.008232 0.000168 0.032928 0.000672 0.025872
#[18] 0.000528 0.103488 0.002112 0.060368 0.001232 0.241472 0.004928 0.003528 0.000072 0.014112 0.000288 0.008232 0.000168 0.032928 0.000672
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.