作为机器学习的十大算法之一,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文件
每次迭代过程的公式是:
最后我们使用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算法还是有很好的准确度