機器學習 - GMM參數估計的EM算法

博客內容源於《統計機器學習》一書的閱讀筆記。Python的源碼實現來源於互聯網(作者不詳)。

看理論之前先來【舉個例子】
對於一個未知參數的模型,我們觀測他的輸出,得到下圖這樣的直方圖:

混合高斯模型

我們先假設它是由兩個高斯分佈混合疊加而成的,那麼我們該怎麼去得到這兩個高斯分佈的參數呢?
EM算法!!

1. 高斯混合模型

假設觀測數據 y1y2...yN 是由高斯混合模型生成的。

P(y|θ)=k=1Kαkθ(y|θk)

其中,θ={α1α2...αkθ1θ2...θk} 。表示的是高斯模型的參數,EM算法也正是要用來估計高斯混合模型的這個參數。

2. 算法步驟

2.1 寫出完全對數似然函數(弄清楚隱變量)

還是以上面的例子來說,對於我們的觀測數據 yii=1,2,...,N 來說,該數據肯定是由分模型的數據疊加得到的。那麼我們設想 yi 是這樣產生的:
1> 首先依概率 αk 選擇第 k 個高斯模型 ϕ(y|θk)
2> 然後依第 k 個分模型的概率分佈 ϕ(y|θk) 生成觀測數據。
這時候觀測數據是已知的,反應觀測數據yj 來自第k 個分模型的數據是未知的,k=12...K , 以隱變量 γjk 來表示。

這裏寫圖片描述

可以得到完全似然函數:
這裏寫圖片描述

2.2 EM算法的E步:確定Q函數

Q(θ,θ(i))=E[logP(y,γ|θ)|y,θ(i)]

這裏寫圖片描述

EγjkNj=1Eγjk 替換,得到Q函數。Eγjk 表示分模型k 對觀測數據yj 的響應度。

這裏寫圖片描述

2.2 EM算法的M步:迭代計算

迭代M步就是求函數Q(θ,θ(i))θ 的極大值,即求新一輪迭代的模型參數:

θ(i+1)=argmaxθQ(θ,θ(i))

每一次迭代中參數計算公式表示可得到:
這裏寫圖片描述

最終迭代計算到參數沒有明顯的變化時爲止。

實例代碼:

import math
import copy
import numpy as np
import matplotlib.pyplot as plt

isdebug = False

# 指定k個高斯分佈參數,這裏k=2。2個高斯分佈具有相同均方差Sigma,均值分別爲Mu1,Mu2。
def ini_data(Sigma,Mu1,Mu2,k,N):
    global X
    global Mu
    global Expectations
    X = np.zeros((1,N))
    Mu = np.random.random(2)
    Expectations = np.zeros((N,k))
    for i in xrange(0,N):
        if np.random.random(1) > 0.5:
            X[0,i] = np.random.normal()*Sigma + Mu1
        else:
            X[0,i] = np.random.normal()*Sigma + Mu2
    if isdebug:
        print "***********"
        print u"初始觀測數據X:"
        print X

# EM算法:步驟1,計算E[zij]
def e_step(Sigma,k,N):
    global Expectations
    global Mu
    global X
    for i in xrange(0,N):
        Denom = 0
        for j in xrange(0,k):
            Denom += math.exp((-1/(2*(float(Sigma**2))))*(float(X[0,i]-Mu[j]))**2)
        for j in xrange(0,k):
            Numer = math.exp((-1/(2*(float(Sigma**2))))*(float(X[0,i]-Mu[j]))**2)
            Expectations[i,j] = Numer / Denom
    if isdebug:
        print "***********"
        print u"隱藏變量E(Z):"
        print Expectations

# EM算法:步驟2,求最大化E[zij]的參數Mu
def m_step(k,N):
    global Expectations
    global X
    for j in xrange(0,k):
        Numer = 0
        Denom = 0
        for i in xrange(0,N):
            Numer += Expectations[i,j]*X[0,i]
            Denom +=Expectations[i,j]
        Mu[j] = Numer / Denom 

# 算法迭代iter_num次,或達到精度Epsilon停止迭代
def run(Sigma,Mu1,Mu2,k,N,iter_num,Epsilon):
    ini_data(Sigma,Mu1,Mu2,k,N)
    print u"初始<u1,u2>:", Mu
    for i in range(iter_num):
        Old_Mu = copy.deepcopy(Mu)
        e_step(Sigma,k,N)
        m_step(k,N)
        print i,Mu
        if sum(abs(Mu-Old_Mu)) < Epsilon:
            break

if __name__ == '__main__':
   run(6,40,20,2,1000,1000,0.0001)
   plt.hist(X[0,:],50)
   plt.show()
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章