二項分佈的理論基礎、應用及Python實踐

二項分佈是概率統計中非常基礎、非常實用的一種分佈,可以說它在我們的生活中無所不在。它說明了這樣一種現象:在給定的試驗次數中,某一結果會發生多少次。

比如:

這個月有多少天會刮北風?

今年有多少天會下雨?

經過一個路口100次,有多少次會是綠燈?

一年之中會有多少次出門就見狗?



一、伯努利分佈

伯努利分佈是二項分佈的基礎,它只有兩種狀態,比如拋硬幣的時候,結果只有正面和反面兩種情況,且兩種情況的概率之和為1。也就是說,當我們給定​正面朝上的概率的時候,這個分佈的一切就都確定了。

我們以0和1來標識這兩種可能的結果,那麼其概率函數為:


二項分佈的理論基礎、應用及Python實踐

那麼其期望值為:


二項分佈的理論基礎、應用及Python實踐

其方差為:

二項分佈的理論基礎、應用及Python實踐

二、排列組合

1. 排列

從n個對象中有序地挑選出r個對象,我們稱之為排列,我們用以下公式統計其可能產生的排列數:


二項分佈的理論基礎、應用及Python實踐

2. 組合

考慮另一種情況,仍然是從n個對象中抽取​r個對象,但是這次我們不考慮其順序,這種過程我們稱之為組合。我們用以下公式統計其可能產生的組合數:


二項分佈的理論基礎、應用及Python實踐

可以看出,這是n選r的排列數除以r的排列數。上述公式又被稱作二項係數,通常用“n選r”表示。

3. Python計算

那麼接下來我們用Python來寫一個函數,用來計算不同參數下的排列與組合的數量。在排列組合的計算中,我們可能會輸入兩個參數:總樣本量n、需要抽取的樣本數​k。

那麼我們就定義如下函數:

<code>

from

functools

import

reduce

def

PC

(n, k)

:

""" 計算並返回排列組合數 """

if

n <=

0

or

k

0

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 in

range

(

1

,

5

):

for

k in

range

(

1

,

3

):

print

(

'-'

*

10

)

print

(n, k)

print

(PC(n, k))/<code>

結果是正確的:

<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次的場景發生的概率均為:


二項分佈的理論基礎、應用及Python實踐

然後,我們需要考慮結果為1的次數剛好為k的情況有多少種。很明顯,這就是一個伯努利試驗的組合問題,n次實驗中有k次結果為1的情況共有“n選k”種,兩者相乘就是該事件發生的概率。因此:


二項分佈的理論基礎、應用及Python實踐

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 * combination

return

p_result/<code>

那麼接下來,我們利用我們剛剛寫好的小工具,來看一下在10次試驗中,不同的概率對應的二項分佈是什麼樣的。

<code>

probs

= [binominal_prob(

10

, i,

0.5

) for i in range(

11

)]/<code>

我們將結果畫出來看看:

<code>%matplotlib 

inline

import

numpy

as

np

import

matplotlib.pyplot

as

plt

import

seaborn

as

sns sns.

set

() probs = [round(i/

10

,

1

)

for

i

in

range(

1

,

10

)] n =

20

plt.figure(figsize=(

16

,

6

))

for

p

in

probs: dist_probs = [binominal_prob(n, i, p)

for

i

in

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>


二項分佈的理論基礎、應用及Python實踐


或者我們使用交互式的繪圖庫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>


二項分佈的理論基礎、應用及Python實踐

可以看到,plotly實現的效果更加靚麗,且額外支持了動態交互,在這裡我就選擇把p=0.8這條線隱藏了起來。

四、一個利用極大似然估計求二項分佈概率參數的例子

我們現在想象一種情況,有一枚分佈不太均勻的硬幣,每次拋向空中後,落地為正面的概率為p,任意兩次實驗之間相互獨立。現在我們做了4次實驗,其中有三次正面朝上,那麼請問p的值為多少?

我們之前曾經提到過極大似然估計,在這裡我們用同樣的思路去估計p​的取值。極大似然估計的思想就是尋找一個參數,使得當前結果發生的概率最大,那麼我們先定義出來當前結果發生的概率公式:


二項分佈的理論基礎、應用及Python實踐

對其求導並使導數為0,有:


二項分佈的理論基礎、應用及Python實踐

可得,當p=0.75時,P(X=3)=0.422達到最大(另一個解​p=0顯然不可能,因為硬幣朝上已經發生了,並不是“不可能事件”;另外考慮不同區間導數的取值也可以得到答案)。


分享到:


相關文章: