用 Python 進行貝葉斯模型建模(1)
(點擊
上方藍字
,快速關注我們)
編譯:伯樂在線 - JLee
如有好文章投稿,請點擊 → 這裡了解詳情
本系列:
《
第 0 節:導論
》
《第 1 節:估計模型參數》
第1節:估計模型參數
在這一節,我們將討論貝葉斯方法是如何思考數據的,我們怎樣通過 MCMC 技術估計模型參數。
from
IPython
.
display
import
Image
import
matplotlib
.
pyplot
as
plt
import
numpy
as
np
import
pandas
as
pd
import
pymc3
as
pm
import
scipy
import
scipy
.
stats
as
stats
import
scipy
.
optimize
as
opt
import
statsmodels
.
api
as
sm
%
matplotlib
inline
plt
.
style
.
use
(
"bmh"
)
colors
=
[
"#348ABD"
,
"#A60628"
,
"#7A68A6"
,
"#467821"
,
"#D55E00"
,
"#CC79A7"
,
"#56B4E9"
,
"#009E73"
,
"#F0E442"
,
"#0072B2"
]
messages
=
pd
.
read_csv
(
"data/hangout_chat_data.csv"
)
貝葉斯方法如何思考數據?
當我開始學習如何運用貝葉斯方法的時候,我發現理解貝葉斯方法如何思考數據是很有用的。設想下述的場景:
一個好奇的男孩每天觀察從他家門前經過的汽車的數量。他每天努力地記錄汽車的總數。一個星期過去後,他的筆記本上記錄著下面的數字:12,33,20,29,20,30,18
從貝葉斯方法的角度看,這個數據是由隨機過程產生的。但是,既然數據被觀測,它便固定了並且不會改變。這個隨機過程有些模型參數被固定了。然而,貝葉斯方法用概率分布來表示這些模型參數的不確定性。
由於這個男孩調查的是計數(非負整數),一個通常的做法是用泊松分布對數據(如隨機過程)建模。泊松分布只有一個參數 μ,它既是數據的平均數,也是方差。下面是三個不同 μ 值的泊松分布。
代碼:
fig
=
plt
.
figure
(
figsize
=
(
11
,
3
))
ax
=
fig
.
add_subplot
(
111
)
x_lim
=
60
mu
=
[
5
,
20
,
40
]
for
i
in
np
.
arange
(
x_lim
)
:
plt
.
bar
(
i
,
stats
.
poisson
.
pmf
(
mu
[
0
],
i
),
color
=
colors
[
3
])
plt
.
bar
(
i
,
stats
.
poisson
.
pmf
(
mu
[
1
],
i
),
color
=
colors
[
4
])
plt
.
bar
(
i
,
stats
.
poisson
.
pmf
(
mu
[
2
],
i
),
color
=
colors
[
5
])
_
=
ax
.
set_xlim
(
0
,
x_lim
)
_
=
ax
.
set_ylim
(
0
,
0.2
)
_
=
ax
.
set_ylabel
(
"Probability mass"
)
_
=
ax
.
set_title
(
"Poisson distribution"
)
_
=
plt
.
legend
([
"$mu$ = %s"
%
mu
[
0
],
"$mu$ = %s"
%
mu
[
1
],
"$mu$ = %s"
%
mu
[
2
]])
在上一節中,我們引入我的 hangout 聊天數據集。特別地,我對我的回復時間(response_time)感興趣。鑒於 response_time 是計數數據,我們可以用泊松分布對其建模,並估計參數 μ 。我們將用頻率論方法和貝葉斯方法兩種方法來估計。
fig
=
plt
.
figure
(
figsize
=
(
11
,
3
))
_
=
plt
.
title
(
"Frequency of messages by response time"
)
_
=
plt
.
xlabel
(
"Response time (seconds)"
)
_
=
plt
.
ylabel
(
"Number of messages"
)
_
=
plt
.
hist
(
messages
[
"time_delay_seconds"
].
values
,
range
=
[
0
,
60
],
bins
=
60
,
histtype
=
"stepfilled"
)
頻率論方法估計μ
在進入貝葉斯方法之前,讓我們先看一下頻率論方法估計泊松分布參數。我們將使用優化技術使似然函數最大。
下面的函數poisson_logprob()返回在給定泊松分布模型和參數值的條件下,觀測數據總體的可能性。用方法opt.minimize_scalar找到在觀測數據基礎上參數值 μ 的最可信值(最大似然)。該方法的機理是,這個優化技術會自動迭代可能的mu值直到找到可能性最大的值。
y_obs
=
messages
[
"time_delay_seconds"
].
values
def
poisson_logprob
(
mu
,
sign
=-
1
)
:
return
np
.
sum
(
sign
*
stats
.
poisson
.
logpmf
(
y_obs
,
mu
=
mu
))
freq_results
=
opt
.
minimize_scalar
(
poisson_logprob
)
%
time
(
"The estimated value of mu is: %s"
%
freq_results
[
"x"
])
The estimated value of mu is: 18.0413533867
CPU times: user 63 μs, sys: 1e+03 ns, total: 64 μs
Wall time: 67.9 μs
所以,μ 的估計值是18.0413533867。優化技術沒有對不確定度進行評估,它只返回一個點,效率很高。
下圖描述的是我們優化的函數。對於每個μ值,圖線顯示給定數據和模型在μ處的似然度。優化器以登山模式工作——從曲線上隨機一點開始,不停向上攀登直到達到最高點。
x
=
np
.
linspace
(
1
,
60
)
y_min
=
np
.
min
([
poisson_logprob
(
i
,
sign
=
1
)
for
i
in
x
])
y_max
=
np
.
max
([
poisson_logprob
(
i
,
sign
=
1
)
for
i
in
x
])
fig
=
plt
.
figure
(
figsize
=
(
6
,
4
))
_
=
plt
.
plot
(
x
,
[
poisson_logprob
(
i
,
sign
=
1
)
for
i
in
x
])
_
=
plt
.
fill_between
(
x
,
[
poisson_logprob
(
i
,
sign
=
1
)
for
i
in
x
],
y_min
,
color
=
colors
[
0
],
alpha
=
0.3
)
_
=
plt
.
title
(
"Optimization of $mu$"
)
_
=
plt
.
xlabel
(
"$mu$"
)
_
=
plt
.
ylabel
(
"Log probability of $mu$ given data"
)
_
=
plt
.
vlines
(
freq_results
[
"x"
],
y_max
,
y_min
,
colors
=
"red"
,
linestyles
=
"dashed"
)
_
=
plt
.
scatter
(
freq_results
[
"x"
],
y_max
,
s
=
110
,
c
=
"red"
,
zorder
=
3
)
_
=
plt
.
ylim
(
ymin
=
y_min
,
ymax
=
0
)
_
=
plt
.
xlim
(
xmin
=
1
,
xmax
=
60
)
上述優化方法估計泊松分布的參數值為 18 .我們知道,對任意一個泊松分布,參數 μ 代表的是均值和方差。下圖描述了這個分布。
fig
=
plt
.
figure
(
figsize
=
(
11
,
3
))
ax
=
fig
.
add_subplot
(
111
)
x_lim
=
60
mu
=
np
.
int
(
freq_results
[
"x"
])
for
i
in
np
.
arange
(
x_lim
)
:
plt
.
bar
(
i
,
stats
.
poisson
.
pmf
(
mu
,
i
),
color
=
colors
[
3
])
_
=
ax
.
set_xlim
(
0
,
x_lim
)
_
=
ax
.
set_ylim
(
0
,
0.1
)
_
=
ax
.
set_xlabel
(
"Response time in seconds"
)
_
=
ax
.
set_ylabel
(
"Probability mass"
)
_
=
ax
.
set_title
(
"Estimated Poisson distribution for Hangout chat response time"
)
_
=
plt
.
legend
([
"$lambda$ = %s"
%
mu
])
上述泊松分布模型和 μ 的估計表明,觀測小於10 或大於 30 的可能性很小,絕大多數的概率分布在 10 和 30 之間。但是,這不能反映我們觀測到的介於 0 到 60 之間的數據。
貝葉斯方法估計 μ
如果你之前遇到過貝葉斯理論,下面的公式會看起來很熟悉。我從沒認同過這個框架直到我讀了John K. Kruschke的書「貝葉斯數據分析」,從他優美簡潔的貝葉斯圖表模型視角認識這個公式。
代碼:
Image("graphics/Poisson-dag.png", width=320)
上述模式可以解讀如下(從下到上):
對每一個對話(i)觀測計數數據(y)
數據由一個隨機過程產生,我們認為可以用泊松分布模擬
泊松分布只有一個參數,介於 0 到 60 之間
由於我們沒有任何依據對μ在這個範圍內進行預估,就用均勻分布對 μ 建模
神奇的方法MCMC
下面的動畫很好的演示了馬爾科夫鏈蒙特卡羅方法(MCMC)的過程。MCMC採樣器從先驗分布中選取參數值,計算從這些參數值決定的某個分布中得到觀測數據的可能性。
這個計算可以作為MCMC採樣器的導引。從參數的先驗分布中選取值,然後計算給定數據條件下這些參數值可能性——導引採樣器到更高概率的區域。
與上面討論的頻率論優化技術在概念上有相似之處,MCMC採樣器向可能性最高的區域運動。但是,貝葉斯方法不關心尋找絕對最大值,而是遍歷和收集概率最高區域附近的樣本。所有收集到的樣本都可認為是一個可信的參數。
Image(url="graphics/mcmc-animate.gif")
with
pm
.
Model
()
as
model
:
mu
=
pm
.
Uniform
(
"mu"
,
lower
=
0
,
upper
=
60
)
likelihood
=
pm
.
Poisson
(
"likelihood"
,
mu
=
mu
,
observed
=
messages
[
"time_delay_seconds"
].
values
)
start
=
pm
.
find_MAP
()
step
=
pm
.
Metropolis
()
trace
=
pm
.
sample
(
200000
,
step
,
start
=
start
,
progressbar
=
True
)
Applied
interval
-
transform to mu
and
added transformed mu_interval to
model
.
[
-----------------
100
%-----------------
]
200000
of
200000
complete
in
48.3
sec
上面的代碼通過遍歷 μ 的後驗分布的高概率區域,收集了 200,000 個 μ 的可信樣本。下圖(左)顯示這些值的分布,平均值與頻率論的估值(紅線)幾乎一樣。但是,我們同時也得到了不確定度,μ 值介於 17 到 19 之間都是可信的。我們稍後會看到這個不確定度很有價值。
_ = pm.traceplot(trace, varnames=["mu"], lines={"mu": freq_results["x"]})
丟棄早期樣本(壞點)
你可能疑惑上面 MCMC 代碼中pm.find.MAP()的作用。MAP 代表最大後驗估計,它幫助 MCMC 採樣器尋找合適的採樣起始點。理想情況下,模型從高概率區域開始,但有時不是這樣。因此,樣本集中的早期樣本(壞點)經常被丟棄。
fig
=
plt
.
figure
(
figsize
=
(
11
,
3
))
plt
.
subplot
(
121
)
_
=
plt
.
title
(
"Burnin trace"
)
_
=
plt
.
ylim
(
ymin
=
16.5
,
ymax
=
19.5
)
_
=
plt
.
plot
(
trace
.
get_values
(
"mu"
)[
:
1000
])
fig
=
plt
.
subplot
(
122
)
_
=
plt
.
title
(
"Full trace"
)
_
=
plt
.
ylim
(
ymin
=
16.5
,
ymax
=
19.5
)
_
=
plt
.
plot
(
trace
.
get_values
(
"mu"
))
模型的收斂性
樣本軌跡
由於上面模型對 μ 的估計不能表明估計的效果很好,可以採用一些檢驗手段。首先,觀察樣本輸出,樣本的軌跡應該輕微上下浮動,就像一條毛蟲。如果你看到軌跡上下跳躍或滯留在某點,這就是模型不收斂的標誌,通過 MCMC 採樣器得到的估計沒有意義。
自相關圖
也可采另一種測試,自相關測試(見下圖),這是評估MCMC採樣鏈中樣本前後相關關係的一種方法。相關性弱的樣本比相關性強的樣本能夠給參數估計提供更多的信息。
直觀上看,自相關圖應該快速衰減到0附近,然後在 0 附近上下波動。如果你的自相關圖沒有衰減,通常這是弱融合的標誌,你需要重新審查你的模型選擇(如似然度)和抽樣方法(如Metropolis)
_ = pm.autocorrplot(trace[:2000], varnames=["mu"])
看完本文有收穫?請轉
發分享給更多人
關注「P
ython開發者」,提升Python技能
※為什麼Python開發越來越火?
※原來Python能做這樣的簡歷
※這些提高Python開發效率的小方法你知道嗎?
※Python經典練手項目——從萌新到大神的成長之路
※打造自己的Python編碼環境
TAG:Python |
※利用Chan-Vese模型和Sobel運算對重疊葉片進行圖像分割
※使用 VS Code 進行 Python 編程
※一文讀懂如何用LSA、PSLA、LDA和lda2vec進行主題建模
※使用pdb進行Python調試(下篇)
※用Python進行機器學習
※S.Moro和T.Lunger進行Pik Pobeda峰冬季首攀
※諾基亞9真旗艦 有資格與三星S10和iPhone X Plus進行PK嗎?
※英格蘭教會或使用Apple Pay/Google Pay進行募捐
※使用pdb進行Python調試
※用Prophet快速進行時間序列預測(附Prophet和R代碼)
※2018 UOD舉行Epic Games創始人Tim Sweeney進行主題演講
※Python利用OpenCV來進行圖片的位移和縮放
※Angewandte Chemie 突破!會動的納米馬達讓CRISPR-Cas-9鑽進癌細胞心窩進行基因編輯!
※德國 Fostla為Mercedes-AMG GT S 進行改裝強化 馬力達 613ps!
※三星將停止對Galaxy Note 5和S6 Edge +進行系統更新
※使用Pandas&NumPy進行數據清洗的6大常用方法
※Android銀行木馬——Red Alert 2.0偽裝成合法程序進行傳播
※CVE-2018-8412:通過MS Office for Mac的Legacy Package進行提權
※微軟Azure現在支持Nvidia的GPU Cloud進行深度學習模型的訓練和推理
※Google試圖僱用Vitalik Buterin進行秘密加密項目