二項分佈是概率統計中非常基礎、非常實用的一種分佈,可以說它在我們的生活中無所不在。它說明了這樣一種現象:在給定的試驗次數中,某一結果會發生多少次。
比如:
這個月有多少天會刮北風?
今年有多少天會下雨?
經過一個路口100次,有多少次會是綠燈?
一年之中會有多少次出門就見狗?
一、伯努利分佈
伯努利分佈是二項分佈的基礎,它只有兩種狀態,比如拋硬幣的時候,結果只有正面和反面兩種情況,且兩種情況的概率之和為1。也就是說,當我們給定正面朝上的概率的時候,這個分佈的一切就都確定了。
我們以0和1來標識這兩種可能的結果,那麼其概率函數為:
那麼其期望值為:
其方差為:
二、排列組合
1. 排列
從n個對象中有序地挑選出r個對象,我們稱之為排列,我們用以下公式統計其可能產生的排列數:
2. 組合
考慮另一種情況,仍然是從n個對象中抽取r個對象,但是這次我們不考慮其順序,這種過程我們稱之為組合。我們用以下公式統計其可能產生的組合數:
可以看出,這是n選r的排列數除以r的排列數。上述公式又被稱作二項係數,通常用“n選r”表示。
3. Python計算
那麼接下來我們用Python來寫一個函數,用來計算不同參數下的排列與組合的數量。在排列組合的計算中,我們可能會輸入兩個參數:總樣本量n、需要抽取的樣本數k。
那麼我們就定義如下函數:
<code>from
functoolsimport
reducedef
PC
(n, k)
:""" 計算並返回排列組合數 """
if
n <=0
or
k0
or
n < k: print('Wrong Input!'
)return
None
if
k ==0
:return
1
,1
series_asc = list(range(1
, n+1
)) series_desc = sorted(series_asc, reverse=True
) permutation = reduce(lambda
x, y: x*y, series_desc[:k]) perm2 = reduce(lambda
x, y: x*y, series_asc[:k]) combination = int(permutation / perm2)return
permutation, combination/<code>
隨手測試幾個:
<code>for
n inrange
(1
,5
):for
k inrange
(1
,3
):'-'
*10
)
結果是正確的:
<code>----------
1
1
(1,
1
)
----------
1
2
Wrong
Input!
None
----------
2
1
(2,
2
)
----------
2
2
(2,
1
)
----------
3
1
(3,
3
)
----------
3
2
(6,
3
)
----------
4
1
(4,
4
)
----------
4
2
(12,
6
)
/<code>
三、二項分佈
回顧伯努利分佈的情況:一次實驗只有可能有兩種結果,分別用0和1來表示,其中結果1發生的概率為p。那麼在n次獨立實驗中,不考慮順序的情況下,結果1出現k次的概率是多少?
首先,因為n次實驗相互獨立,所以根據乘法定律,任何一種結果1出現k次的場景發生的概率均為:
然後,我們需要考慮結果為1的次數剛好為k的情況有多少種。很明顯,這就是一個伯努利試驗的組合問題,n次實驗中有k次結果為1的情況共有“n選k”種,兩者相乘就是該事件發生的概率。因此:
Python計算
那麼我們來用Python實現一個計算二項分佈概率的小工具,在這裡,我們的輸入參數包含總試驗次數n、正樣本發生的次數k以及正樣本發生的概率p:
<code>def
binominal_prob
(n, k, p)
:""" 計算並返回二項分佈中某結果發生的概率 """
p_base = p ** k * (1
-p) ** (n-k) combination = PC(n, k)[1
] p_result = p_base * combinationreturn
p_result/<code>
那麼接下來,我們利用我們剛剛寫好的小工具,來看一下在10次試驗中,不同的概率對應的二項分佈是什麼樣的。
<code>probs
= [binominal_prob(10
, i,0.5
) for i in range(11
)]/<code>
我們將結果畫出來看看:
<code>%matplotlibinline
import
numpyas
npimport
matplotlib.pyplotas
pltimport
seabornas
sns sns.set
() probs = [round(i/10
,1
)for
iin
range(1
,10
)] n =20
plt.figure(figsize=(16
,6
))for
pin
probs: dist_probs = [binominal_prob(n, i, p)for
iin
range(n+1
)] plt.plot(range(n+1
), dist_probs, label='p={0}'
.format(p)) plt.legend() plt.title('Binominal Distributions of Different P value'
) plt.savefig('binominal.jpg'
) plt.show()/<code>
或者我們使用交互式的繪圖庫plotly來嘗試同樣的事情:
<code>import
plotly.graph_objects as go
probs
=[round(i/10,1) for i in range(1, 10)]
n
=20
fig
=go.Figure()
for
p in probs:
dist_probs
=[binominal_prob(n, i, p) for i in range(n+1)]
fig.add_trace(go.Scatter(
x
=list(range(n+1)),
y
=dist_probs,
name
='p={0}'.format(p)
))
fig.show()
/<code>
可以看到,plotly實現的效果更加靚麗,且額外支持了動態交互,在這裡我就選擇把p=0.8這條線隱藏了起來。
四、一個利用極大似然估計求二項分佈概率參數的例子
我們現在想象一種情況,有一枚分佈不太均勻的硬幣,每次拋向空中後,落地為正面的概率為p,任意兩次實驗之間相互獨立。現在我們做了4次實驗,其中有三次正面朝上,那麼請問p的值為多少?
我們之前曾經提到過極大似然估計,在這裡我們用同樣的思路去估計p的取值。極大似然估計的思想就是尋找一個參數,使得當前結果發生的概率最大,那麼我們先定義出來當前結果發生的概率公式:
對其求導並使導數為0,有:
可得,當p=0.75時,P(X=3)=0.422達到最大(另一個解p=0顯然不可能,因為硬幣朝上已經發生了,並不是“不可能事件”;另外考慮不同區間導數的取值也可以得到答案)。
關鍵字: 二項分佈 ---------- plt