EM算法的python實現(xiàn)的方法步驟
前言:前一篇文章大概說了EM算法的整個理解以及一些相關(guān)的公式神馬的,那些數(shù)學(xué)公式啥的看完真的是忘完了,那就來用代碼記憶記憶吧!接下來將會對python版本的EM算法進行一些分析。
EM的python實現(xiàn)和解析
引入問題(雙硬幣問題)
假設(shè)有兩枚硬幣A、B,以相同的概率隨機選擇一個硬幣,進行如下的拋硬幣實驗:共做5次實驗,每次實驗獨立的拋十次,結(jié)果如圖中a所示,例如某次實驗產(chǎn)生了H、T、T、T、H、H、T、H、T、H,H代表正面朝上。
假設(shè)試驗數(shù)據(jù)記錄員可能是實習(xí)生,業(yè)務(wù)不一定熟悉,造成a和b兩種情況
a表示實習(xí)生記錄了詳細的試驗數(shù)據(jù),我們可以觀測到試驗數(shù)據(jù)中每次選擇的是A還是B
b表示實習(xí)生忘了記錄每次試驗選擇的是A還是B,我們無法觀測實驗數(shù)據(jù)中選擇的硬幣是哪個
問在兩種情況下分別如何估計兩個硬幣正面出現(xiàn)的概率?
以上的針對于b實習(xí)生的問題其實和三硬幣問題類似,只是這里把三硬幣中第一個拋硬幣的選擇換成了實習(xí)生的選擇。
對于已知是A硬幣還是B硬幣拋出的結(jié)果的時候,可以直接采用概率的求法來進行求解。對于含有隱變量的情況,也就是不知道到底是A硬幣拋出的結(jié)果還是B硬幣拋出的結(jié)果的時候,就需要采用EM算法進行求解了。如下圖:
其中的EM算法的第一步就是初始化的過程,然后根據(jù)這個參數(shù)得出應(yīng)該產(chǎn)生的結(jié)果。
構(gòu)建觀測數(shù)據(jù)集
針對這個問題,首先采集數(shù)據(jù),用1表示H(正面),0表示T(反面):
#硬幣投擲結(jié)果 observations = numpy.array([[1,0,0,0,1,1,0,1,0,1], [1,1,1,1,0,1,1,1,0,1], [1,0,1,1,1,1,1,0,1,1], [1,0,1,0,0,0,1,1,0,0], [0,1,1,1,0,1,1,1,0,1]])
第一步:參數(shù)的初始化
參數(shù)賦初值
第一個迭代的E步
拋硬幣是一個二項分布,可以用scipy中的binom來計算。對于第一行數(shù)據(jù),正反面各有5次,所以:
#二項分布求解公式 contribution_A = scipy.stats.binom.pmf(num_heads,len_observation,theta_A) contribution_B = scipy.stats.binom.pmf(num_heads,len_observation,theta_B)
將兩個概率正規(guī)化,得到數(shù)據(jù)來自硬幣A,B的概率:
weight_A = contribution_A / (contribution_A + contribution_B) weight_B = contribution_B / (contribution_A + contribution_B)
這個值類似于三硬幣模型中的μ,只不過多了一個下標,代表是第幾行數(shù)據(jù)(數(shù)據(jù)集由5行構(gòu)成)。同理,可以算出剩下的4行數(shù)據(jù)的μ。
有了μ,就可以估計數(shù)據(jù)中AB分別產(chǎn)生正反面的次數(shù)了。μ代表數(shù)據(jù)來自硬幣A的概率的估計,將它乘上正面的總數(shù),得到正面來自硬幣A的總數(shù),同理有反面,同理有B的正反面。
#更新在當前參數(shù)下A,B硬幣產(chǎn)生的正反面次數(shù) counts['A']['H'] += weight_A * num_heads counts['A']['T'] += weight_A * num_tails counts['B']['H'] += weight_B * num_heads counts['B']['T'] += weight_B * num_tails
第一個迭代的M步
當前模型參數(shù)下,AB分別產(chǎn)生正反面的次數(shù)估計出來了,就可以計算新的模型參數(shù)了:
new_theta_A = counts['A']['H']/(counts['A']['H'] + counts['A']['T']) new_theta_B = counts['B']['H']/(counts['B']['H'] + counts['B']['T'])
于是就可以整理一下,給出EM算法單個迭代的代碼:
def em_single(priors,observations): """ EM算法的單次迭代 Arguments ------------ priors:[theta_A,theta_B] observation:[m X n matrix] Returns --------------- new_priors:[new_theta_A,new_theta_B] :param priors: :param observations: :return: """ counts = {'A': {'H': 0, 'T': 0}, 'B': {'H': 0, 'T': 0}} theta_A = priors[0] theta_B = priors[1] #E step for observation in observations: len_observation = len(observation) num_heads = observation.sum() num_tails = len_observation-num_heads #二項分布求解公式 contribution_A = scipy.stats.binom.pmf(num_heads,len_observation,theta_A) contribution_B = scipy.stats.binom.pmf(num_heads,len_observation,theta_B) weight_A = contribution_A / (contribution_A + contribution_B) weight_B = contribution_B / (contribution_A + contribution_B) #更新在當前參數(shù)下A,B硬幣產(chǎn)生的正反面次數(shù) counts['A']['H'] += weight_A * num_heads counts['A']['T'] += weight_A * num_tails counts['B']['H'] += weight_B * num_heads counts['B']['T'] += weight_B * num_tails # M step new_theta_A = counts['A']['H'] / (counts['A']['H'] + counts['A']['T']) new_theta_B = counts['B']['H'] / (counts['B']['H'] + counts['B']['T']) return [new_theta_A,new_theta_B]
EM算法主循環(huán)
給定循環(huán)的兩個終止條件:模型參數(shù)變化小于閾值;循環(huán)達到最大次數(shù),就可以寫出EM算法的主循環(huán)了
def em(observations,prior,tol = 1e-6,iterations=10000): """ EM算法 :param observations :觀測數(shù)據(jù) :param prior:模型初值 :param tol:迭代結(jié)束閾值 :param iterations:最大迭代次數(shù) :return:局部最優(yōu)的模型參數(shù) """ iteration = 0; while iteration < iterations: new_prior = em_single(prior,observations) delta_change = numpy.abs(prior[0]-new_prior[0]) if delta_change < tol: break else: prior = new_prior iteration +=1 return [new_prior,iteration]
調(diào)用
給定數(shù)據(jù)集和初值,就可以調(diào)用EM算法了:
print em(observations,[0.6,0.5])
得到
[[0.72225028549925996, 0.55543808993848298], 36]
我們可以改變初值,試驗初值對EM算法的影響。
print em(observations,[0.5,0.6])
結(jié)果:
[[0.55543727869042425, 0.72225099139214621], 37]
看來EM算法還是很健壯的。如果把初值設(shè)為相等會怎樣?
print em(observations,[0.3,0.3])
輸出:[[0.64000000000000001, 0.64000000000000001], 1]
顯然,兩個值相加不為1的時候就會破壞這個EM函數(shù)。
換一下初值:
print em(observations,[0.99999,0.00001])
輸出:[[0.72225606292866507, 0.55543145006184214], 33]
EM算法對于參數(shù)的改變還是有一定的健壯性的。
以上是根據(jù)前人寫的博客進行學(xué)習(xí)的~可以自己動手實現(xiàn)以下,對于python練習(xí)還是有作用的。希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
基于OpenCV python3實現(xiàn)證件照換背景的方法
這篇文章主要介紹了基于OpenCV python3實現(xiàn)證件照換背景的方法,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-03-03windows+vscode穿越跳板機調(diào)試遠程代碼的圖文教程
本文通過圖文并茂的形式給大家介紹了windows+vscode穿越跳板機調(diào)試遠程代碼,本文給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2022-02-02使用 NumPy 和 Matplotlib 繪制函數(shù)圖
Matplotlib 是 Python 的繪圖庫。 它可與 NumPy 一起使用,提供了一種有效的 MatLab 開源替代方案。 它也可以和圖形工具包一起使用,如 PyQt 和 wxPython2021-09-09Python3+Pycharm+PyQt5環(huán)境搭建步驟圖文詳解
這篇文章主要介紹了Python3+Pycharm+PyQt5環(huán)境搭建步驟圖文詳解,本文給大家介紹的非常詳細,具有一定的參考借鑒價值,需要的朋友可以參考下2019-05-05使用Python實現(xiàn)火車票查詢系統(tǒng)(帶界面)
周末、假期來了,七夕也快到了,又到一年中最一票難求的時候了!本文將用Python制作一個簡單的火車票查詢系統(tǒng),感興趣的可以了解一下2022-07-07Python基于動態(tài)規(guī)劃算法解決01背包問題實例
這篇文章主要介紹了Python基于動態(tài)規(guī)劃算法解決01背包問題,結(jié)合實例形式分析了Python動態(tài)規(guī)劃算法解決01背包問題的原理與具體實現(xiàn)技巧,需要的朋友可以參考下2017-12-12