EM算法与高斯混合分布

作为机器学习的十大算法之一,EM算法可谓是风头出尽,尤其是EM算法在聚类等方面的优越表现,让EM算法备受瞩目,这个星期对EM算法进行了一番了解,说实话EM算法光从教科书上的那些公式说导我觉得很难理解,在七月算法的一节关于EM算法的公开课上慢慢的对EM算法有了算是入门的了解,今天就来说说EM算法与其典型的应用:高斯混合分布

 

首先简略介绍一个高斯混合分布:

 

在一个随机分布里面,可能存在着很多的分布类型,我们假设每个类的分布都符合高斯混合模型,那么一个随机值集合里面就会有多个高斯分布,举个简单的例子,在一群男女生中,我们统计每个人的身高数据,因为男女生的身高存在差异,我们显然不能讲两者的身高都做一样的处理,那么对于这个身高数据而言,男生的身高符合一个高斯分布,女生的身高符合一个高斯分布,这就是一个数据集里面的两个高斯分布,高斯分布的数学描述是:


                       

其中phi表示一个高斯分布,alpha表示该高斯分布占的比例

 

回到男女身高问题本身,现在的问题是如何求解男女身高的均值和方差(标准差)

 

当然我们可以使用极大似然估计来求解,但这只是理论上可行,实际并不可行

因此我们需要使用一种新的办法来求解,当然,这里自然指的是:EM算法

 

EM算法该如何理解,这是一个问题,七月算法的公开课讲的非常给力,这里给出链接地址 http://www.julyedu.com/video/play/?id=79&course=18

 

这里我不准备对EM进行理论推导,对于上述的男女身高问题这里仅给出一个结论,然后我们使用python将这个问题解决,当然,具体的推导过程见附件的pdf文件

 

每次迭代过程的公式是:


EM算法与高斯混合分布_第1张图片
 

最后我们使用python代码来实现以下男女身高问题的求解过程,我给出了一个男生占50人女生占70人的数据集,其中男生均值为175,标准差为2,女生均值是160,方标准差为2,并加以0~1的随机噪声,然后通过代码求解EM算法运算的准确性

 

# -*- coding: cp936 -*-
"""
EM算法与混合高斯分布
author:luchi
date:2015/12/6

description:假如有一堆人,包括男的和女的,现在不知道
其比例只能统计身高信息,现在要求男的和女的的身高的均值
方差已经在人群中占得比例,使用EM算法的混合高斯模型可以
解决
"""
from numpy import *
from random import *
import math

#计算高斯值
def calcGauss(x,mu,sigma):
    return exp(-1*(x-mu)**2/2/(sigma**2))/sigma/sqrt(2*math.pi)
    
#计算均值
def averageHeight(height,gamma,n):
    sumHeight=0.0
    for i in range(len(height)):
        sumHeight+=height[i]*gamma[i]
    return float(sumHeight)/n
#计算标准差
def varianceHeight(height,gamma,mu,n):
    sumVariance=0.0
    for i in range(len(height)):
        sumVariance+=gamma[i]*(height[i]-mu)**2
    return sqrt(float(sumVariance)/n)

#终止条件gp,bp,gmu,gsigma,bmu,bsigma
def isEqual(cur,now):
    cur=mat(cur).T
    now=mat(now).T
    temp=cur-now
    if temp.T*temp<0.001:
        return True
    return False
    
#计算的主要函数,height为人群的身高分布
def calcEM(height):
    N=len(height)
    gp=0.5  #女孩的初始比例
    bp=0.5  #男孩的初始比例
    gmu,gsigma=min(height),1  #初始值的女孩身高均值和标准差
    bmu,bsigma=max(height),1  #初始值的男孩身高均值和标准差
    
    ggamma=range(N)  #计算女孩在迭代过程中的gamma值
    bgamma=range(N)  #计算女孩在迭代过程中的gamma值
    
    cur=[gp,bp,gmu,gsigma,bmu,bsigma] #初始的方差矩阵
    now=[]
    
    times=0  #迭代次数
    while times<100:
        i=0
        for x in height:
           ggamma[i]= gp*calcGauss(x,gmu,gsigma)
           bgamma[i]= bp*calcGauss(x,bmu,bsigma)
           s= ggamma[i]+bgamma[i]
           ggamma[i]/=s
           bgamma[i]/=s
           i+=1
        
        gn=sum(ggamma)  #计算比例
        gp=float(gn)/float(N)
        bn=sum(bgamma)
        bp=float(bn)/float(N)
        gmu=averageHeight(height,ggamma,gn)
        gsigma=varianceHeight(height,ggamma,gmu,gn)
        bmu=averageHeight(height,bgamma,bn)
        bsigma=varianceHeight(height,bgamma,bmu,bn)

        now=[gp,bp,gmu,gsigma,bmu,bsigma]
        if isEqual(cur,now):
            break
        cur=now

        print "迭代次数是:\t",times
        print "女孩的身高平均值和标准差是:\t",gmu,gsigma
        print "男孩的身高平均值和标准差是:\t",bmu,bsigma
        print "男孩女孩的比例是:\t",bn,gn,bn+gn
        times+=1
    return now

def test():
    #产生随机测试集
    height=[]
    #产生男生的身高数据
    for i in range(50):
        height.append(gauss(175,2)+5*random()*pow(-1,i))
    for i in range(70):
        height.append(gauss(160,2)+5*random()*pow(-1,i))
    
    calcEM(height)

if __name__=='__main__':
    test()
    
        




        

  计算结果如下:

 

 

迭代次数是:	2
女孩的身高平均值和标准差是:	160.368555386 3.56047601722
男孩的身高平均值和标准差是:	174.782518706 3.52040845881
男孩女孩的比例是:	52.5771905209 67.4228094791 120.0

 

 需要说明的是,EM算法对初值很敏感,而且EM算法是局部最优解,而不是全局最优解,但是在选定的初值偏差不是太大的情况下,EM算法还是有很好的准确度

你可能感兴趣的:(EM算法与高斯混合分布)