欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 文旅 > 明星 > EM算法(期望最大算法、Expectation Maximization Algorithm)

EM算法(期望最大算法、Expectation Maximization Algorithm)

2024/10/24 2:19:22 来源:https://blog.csdn.net/m0_52049033/article/details/143194933  浏览:    关键词:EM算法(期望最大算法、Expectation Maximization Algorithm)

在这里插入图片描述

EM算法(期望最大算法、Expectation Maximization Algorithm)

引言

EM算法,全称为期望最大(Expectation Maximization)算法,是一种从不完全数据或有数据丢失的数据集(存在隐含变量)中求解概率模型参数的最大似然估计方法。
我们采用Nature Biotech中EM tutorial中掷硬币的例子来对EM算法进行一个具体化的解释。

我们假设有两枚硬币A与B,他们随机抛掷的结果如图,当我们知道了每次抛的是A还是B就可以直接进行估计。
在这里插入图片描述

那么根据图中的计算,我们可以得到,两枚硬币抛出正面的概率分别为 θ ^ A = 0.80 \hat \theta_A = 0.80 θ^A=0.80, θ ^ B = 0.45 \hat \theta_B = 0.45 θ^B=0.45
但如果此时不知道抛掷的硬币是A还是B,也就是隐藏了图中表格里的Coin ACoin B,将所有结果存到一列表格中。此时相当于添加了隐变量。只能观测到5轮循环,每轮循环10次,共计50次投币。这个时候就无法直接估计A和B的正面概率,因为不知道哪一轮循环是哪个硬币投掷的。最后,图中的表格就变为下面的形式:

CoinStatistics
Unknown5H,5T
Unknown9H,1T
Unknown8H,2T
Unknown4H,6T
Unknown7H,3T

此时我们的目标没有变,仍旧是估计A和B正面的概率。虽然此时我们失去了A和B的标号,但是我们多了一个硬币种类的隐变量,设为Z,Z是一个5维的向量,可以表示为:
Z = ( z 1 , z 2 , z 3 , z 4 , z 5 ) Z=(z_1,z_2,z_3,z_4,z_5) Z=(z1,z2,z3,z4,z5),代表每一轮所使用的硬币。但是,对于Z并不知晓,就无法去估计 θ A \theta_A θA θ B \theta_B θB,那么我们就必须先得出Z,然后才能进一步估计P(A)和P(B),要得出Z又必须先知道 θ A \theta_A θA θ B \theta_B θB,然后采用最大似然去预测,那么就会陷入一个死循环。

为了解决上述问题,我们可以先随机初始化 θ A \theta_A θA θ B \theta_B θB,然后去估计Z,基于估计出来的Z按照最大似然去估计新的 θ A \theta_A θA θ B \theta_B θB,直至最后收敛,这就是EM算法的思想,下图给出了E-step和M-step。
在这里插入图片描述

下面计算引用【机器学习】EM——期望最大(非常详细)

随机初始化 θ A = 0.6 \theta_A = 0.6 θA=0.6 θ B = 0.5 \theta_B = 0.5 θB=0.5,那么第一轮循环中,如果Unknown的硬币是A,得出5H5T的概率就是 0. 6 5 ∗ 0. 4 5 0.6^5*0.4^5 0.650.45;如果是B,概率为 0. 5 5 ∗ 0. 5 5 0.5^5*0.5^5 0.550.55。那么就有,Unknown为硬币A和B的概率分别是
P A = 0. 6 5 ∗ 0. 4 5 0. 6 5 ∗ 0. 4 5 + 0. 5 5 ∗ 0. 5 5 = 0.45 P B = 0. 5 5 ∗ 0. 5 5 0. 6 5 ∗ 0. 4 5 + 0. 5 5 ∗ 0. 5 5 = 0.55 P_A = \frac{0.6^5*0.4^5}{0.6^5*0.4^5+0.5^5*0.5^5} = 0.45\\ P_B = \frac{0.5^5*0.5^5}{0.6^5*0.4^5+0.5^5*0.5^5 } = 0.55 PA=0.650.45+0.550.550.650.45=0.45PB=0.650.45+0.550.550.550.55=0.55

5个轮次我们都依照上面进行计算,可以得到如下情况

Coin ACoin B
0.450.55
0.800.20
0.730.27
0.350.65
0.650.35

这一步对应了E-step

结合硬币A的概率和上面的投掷结果情况,我们可以利用期望求出硬币A和硬币B的贡献。

CoinStatistics
Unknown5H,5T
Unknown9H,1T
Unknown8H,2T
Unknown4H,6T
Unknown7H,3T
Coin ACoin B
0.450.55
0.800.20
0.730.27
0.350.65
0.650.35

以第一轮硬币A为例,计算方式为:
H : 0.45 ∗ 5 = 2.25 T : 0.45 ∗ 5 = 2.25 H:0.45*5 = 2.25 T:0.45*5 = 2.25 H:0.455=2.25T:0.455=2.25
上面的计算代表着,硬币A对于投掷结果是5H5T的贡献情况。于是可以得到下面的贡献分布情况。

Coin ACoin B
2.2H,2.2T2.8H,2.8T
7.2H,0.8T1.8H,0.2T
5.9H,1.5T2.1H,0.5T
1.4H,2.1T2.6H,3.9T
4.5H,1.9T2.5H,1.1T

总计有

21.3H,8.6T11.7H,8.4T

然后使用极大似然来估计 θ A \theta_A θA θ B \theta_B θB
θ A = 21.3 21.3 + 8.6 = 0.71 θ B = 11.7 11.7 + 8.4 = 0.58 \theta_A = \frac{21.3}{21.3+8.6} = 0.71 \\ \theta_B = \frac{11.7}{11.7+8.4} = 0.58 θA=21.3+8.621.3=0.71θB=11.7+8.411.7=0.58
这一步就是M-step,如此反复迭代,可以得到最终的 θ A \theta_A θA θ B \theta_B θB

原理

有一个样本集 { x 1 . . . , x m } \{x_1...,x_m\} {x1...,xm},我们假设样本间互相独立,想要拟合模型 p ( x ; θ ) p(x;\theta) p(x;θ)到数据的参数。想要找到每个样本隐含的类别z,使得p(x,z)最大,那么可以得到下面的极大似然估计:
L ( θ ) = ∑ i = 1 m log ⁡ p ( x i ; θ ) = ∑ i = 1 m l o g ∑ z p ( x i , z ; θ ) . L(\theta) = \sum_{i=1}^m \log p(x_i;\theta)\\ =\sum_{i=1}^m log \sum_z p(x_i,z;\theta). L(θ)=i=1mlogp(xi;θ)=i=1mlogzp(xi,z;θ).

第一步是对极大似然取对数,第二步是对每个样例的每个可能类别z求联合分布概率和。但是直接求一般比较困难,因为有隐藏变量z存在,但是一般确定了z后,求解就容易了。所以我们需要用EM算法来求z。对于参数估计,我们本质上还是想获得一个使似然函数最大化的那个参数θ,现在与极大似然不同的只是似然函数式中多了一个未知的变量z。

事实上,隐变量估计问题也可以通过梯度下降等优化算法,但事实由于求和项将随着隐变量的数目以指数级上升,会给梯度计算带来麻烦;而 EM 算法则可看作一种非梯度优化方法。

对于每个样本,我们使用 Q i ( z ) Q_i(z) Qi(z)表示样本i隐含变量z的某种分布,且 Q i ( z ) Q_i(z) Qi(z)满足: ∑ z Z Q i ( z ) = 1 , Q i ( z ) ≥ 0 \sum_z^Z Q_i(z) = 1,Q_i(z) \geq 0 zZQi(z)=1,Qi(z)0,那么我们的目标最后就变成了找到合适的 θ \theta θ和z使得 L ( θ ) L(\theta) L(θ)最大。

我们将式子做如下变换:
∑ i n log ⁡ p ( x i ; θ ) = ∑ i n log ⁡ ∑ z p ( x i , z ; θ ) = ∑ i n log ⁡ ∑ z Z Q i ( z ) p ( x i , z ; θ ) Q i ( z ) ≥ ∑ i n ∑ z Z Q i ( z ) log ⁡ p ( x i , z ; θ Q i ( z ) \sum_i^n \log p(x_i;\theta) = \sum_i^n \log \sum_z p(x_i,z;\theta)\\ = \sum_i^n \log \sum_z^Z Q_i(z)\frac{p(x_i,z;\theta)}{Q_i(z)}\\ \geq \sum_i^n \sum_z^Z Q_i(z) \log \frac{p(x_i,z;\theta}{Q_i(z)} inlogp(xi;θ)=inlogzp(xi,z;θ)=inlogzZQi(z)Qi(z)p(xi,z;θ)inzZQi(z)logQi(z)p(xi,z;θ

第一步是求和每个样本的所有可能的类别 z 的联合概率密度函数,但是这一步直接求导非常困难,所以将其分母都乘以函数 Q i ( z ) Q_i(z) Qi(z) ,转换到第二步。从第二步到第三步是利用 Jensen 不等式。

Jensen不等式:

  • 如果f是凸函数,X是随机变量,则 E [ f ( X ) ] ≥ f ( E [ X ] ) E[f(X)]\geq f(E[X]) E[f(X)]f(E[X]) ,当f是严格凸函数时,则 E [ f ( X ) ] > f ( E [ X ] ) E[f(X)] \gt f(E[X]) E[f(X)]>f(E[X])
  • 如果f是凹函数,X是随机变量,则 E [ f ( X ) ] ≤ f ( E [ X ] ) E[f(X)] \leq f(E[X]) E[f(X)]f(E[X]) ,当f是严格凹函数时,则 E [ f ( X ) ] < f ( E [ X ] ) E[f(X)] \lt f(E[X]) E[f(X)]<f(E[X])
  • X = E [ X ] X= E[X] X=E[X]时,即为常数时等式成立。
    在这里插入图片描述

我们把第一步中的 log ⁡ \log log函数看成一个整体,由于 log ⁡ ( x ) \log(x) log(x)的二阶导数小于0,所以原函数为凹函数。我们把 Q i ( z ) Q_i(z) Qi(z)看成一个概率 p z p_z pz,把 p ( x i , z ; θ ) Q i ( z ) \frac{p(x_i,z;\theta)}{Q_i(z)} Qi(z)p(xi,z;θ)看成 z的函数 g ( z ) g(z) g(z)。根据期望公式有:
E ( z ) = p z g ( z ) = ∑ z Z Q i ( z ) [ p ( x i , z ; θ ) Q i ( z ) ] E(z) = p_zg(z)= \sum_z^ZQ_i(z)[\frac{p(x_i,z;\theta)}{Q_i(z)}] E(z)=pzg(z)=zZQi(z)[Qi(z)p(xi,z;θ)]

根据Jensen不等式:
f ( ∑ z Z Q i ( z ) [ p ( x i , z ; θ ) Q i ( z ) ] = f ( E [ z ] ) ≥ E [ f ( z ) ] = ∑ z Z Q i ( z ) f ( [ p ( x i , z ; θ ) Q i ( z ) ] ) f(\sum_z^ZQ_i(z)[\frac{p(x_i,z;\theta)}{Q_i(z)}] = f(E[z])\geq E[f(z)]\\ =\sum_z^ZQ_i(z)f([\frac{p(x_i,z;\theta)}{Q_i(z)}]) f(zZQi(z)[Qi(z)p(xi,z;θ)]=f(E[z])E[f(z)]=zZQi(z)f([Qi(z)p(xi,z;θ)])

通过上面我们得到了: L ( θ ) ≥ J ( z , Q ) L(\theta) \geq J(z,Q) L(θ)J(z,Q) 的形式(z 为隐变量),那么我们就可以通过不断最大化 J ( z , Q ) J(z,Q) J(z,Q)的下界来使得 L ( θ ) L(\theta) L(θ)不断提高。

在这里插入图片描述

图片来自 【机器学习】EM——期望最大(非常详细)

或许我们可以直接分别对 θ \theta θ和z求偏导数,然后求得极值点,也就是最大化 L ( θ ) L(\theta) L(θ),但是式子中含有 log ⁡ ∑ z p \log\sum_z p logzp的形式,求导后就会变得非常复杂,因此很难求得我们需要的z和 θ \theta θ

也就是说,EM 算法通过引入隐含变量,使用 MLE(极大似然估计)进行迭代求解参数。通常引入隐含变量后会有两个参数,EM 算法首先会固定其中的第一个参数,然后使用 MLE 计算第二个变量值;接着通过固定第二个变量,再使用 MLE 估测第一个变量值,依次迭代,直至收敛到局部最优解。

最后可以总结一下EM算法的步骤:
第一步,初始化分布参数 θ \theta θ
第二步,重复E-step 和 M-step直到收敛:

  • E-step:根据参数的初始值或上一次迭代的模型参数来计算出的隐性变量的后验概率(条件概率),其实就是隐性变量的期望值。作为隐藏变量的现有估计值:
    Q i ( z j ) = p ( z j ∣ x i ; θ ) Q_i(z_j) = p(z_j|x_i;\theta) Qi(zj)=p(zjxi;θ)
  • M-step:最大化似然函数从而获得新的参数值:
    θ = a g r m a x θ ∑ i ∑ j Q i ( z j ) log ⁡ P ( x i , z j ; θ ) Q i ( z j ) \theta = {agrmax}_\theta \sum_i \sum_j Q_i(z_j)\log \frac{P(x_i,z_j;\theta)}{Q_i(z_j)} θ=agrmaxθijQi(zj)logQi(zj)P(xi,zj;θ)

代码

import numpy as np
from scipy.stats import multivariate_normal  #多元正态分布
from numpy import genfromtxt    #数据处理函数def Estep(X, prior, mu, sigma):N, D = X.shape         #N表示数据的条数,D表示数据的维数K = len(prior)          #计算随机变量prior的长度gama_mat = np.zeros((N,K))       #初始化gama_mat为N行K列个0for i in range(0,N):        #遍历N条数据xi = X[i, :]        #对于每一行数据sum = 0for k in range(0, K):     #对K个prior求概率密度函数p = multivariate_normal.pdf(xi, mu[k,:], sigma[k,:,:])         #计算第k个prior的概率密度psum += prior[k] * p      #求K个prior的总和for k in range(0,K):gama_mat[i, k] = prior[k] * multivariate_normal.pdf(xi, mu[k,:], sigma[k,:,:]) / sum   #求gama_mat概率矩阵return gama_mat   def Mstep(X, gama_mat):        #将Estep得到的gama_mat,作为Mstep的输入参数(N, D) = X.shapeK = np.size(gama_mat, 1)     #返回gama_mat的列数mu = np.zeros((K, D))        #给mu初始化为K行D列个0 sigma = np.zeros((K, D, D))   #给sigma初始化为K个D行D列的矩阵(方阵)prior = np.zeros(K)         #初始化prior为K个0for k in range(0, K):N_k = np.sum(gama_mat, 0)[k]    for i in range(0,N):mu[k] += gama_mat[i, k] * X[i]         mu[k] /= N_k             #得到均值矩阵for i in range(0, N):left = np.reshape((X[i] - mu[k]), (2,1))right = np.reshape((X[i] - mu[k]), (1,2))sigma[k] += gama_mat[i,k] * left * right     #得到sigma矩阵sigma[k] /= N_kprior[k] = N_k/Nreturn mu, sigma, priordef logLike(X, prior, Mu, Sigma):          #对数似然函数K = len(prior)                         N, M = np.shape(X)P = np.zeros([N, K])      # 初始化概率矩阵Pfor k in range(K):for i in range(N):P[i, k] = multivariate_normal.pdf(X[i], Mu[k, :], Sigma[k, :, :])  #P是一个NxK矩阵,其中(i,k)个元素表示第i个数据点在第j个簇中的可能性return np.sum(np.log(P.dot(prior)))     #返回似然函数值def main():# Reading the data fileX = genfromtxt('.\data\TrainingData_GMM.csv', delimiter=',')   #读取数据print('training data shape:', X.shape)    #打印数据的shape(5000,2)N, D = X.shape     #把5000、2分别赋予N,D表示有5000条数据,每条数据有两个特征K = 4       # initializationmu = np.zeros((K, D))      #给mu初始化为K行D列个0sigma = np.zeros((K, D, D))     #给sigma初始化为K个D行D列的矩阵(方阵)#mu[0] = [-0.5, -0.5]#mu[1] = [0.3, 0.3]#mu[2] = [-0.3, 0.3]#mu[3] = [1.3, -1.3]mu[0] = [1, 0]mu[1] = [0, 1]mu[2] = [0, 0]mu[3] = [1, 1]for k in range(0, K):            #K个二维单位矩阵作为sigmasigma[k] = [[1, 0], [0, 1]]prior = np.ones(K) / K        #先验概率为K个1/kiter = 0prevll = -999999ll_evol = []      #定义一个空数组ll_evol用于后面装log likelihood值print('initialization of the params:')print('mu:\n', mu)print('sigma:\n', sigma)print('prior:', prior)# Iterate with E-Step and M-stepwhile (True):W = Estep(X, prior, mu, sigma)   #调用Estepmu, sigma, prior = Mstep(X, W)    #通过Mstep更新初始的参数mu、sigma、priorll_train = logLike(X, prior, mu, sigma)   #调用对数似然函数print('iter:',iter, 'log likelihood:',ll_train)   #返回第几次迭代和对应的似然值ll_evol.append(ll_train)iter = iter + 1if (iter > 150 or abs(ll_train - prevll) < 0.01):   #当迭代次数大于150次或ll_train的值接近-999999时结束操作breakabs(ll_train - prevll)   prevll = ll_train     #更新prevll的值import pickle    #pickle模块能将对象序列化with open('results.pkl', 'wb') as f:     pickle.dump([prior, mu, sigma, ll_evol], f)    #把prior, mu, sigma, ll_evol数据以二进制形式写入results.pkl文件中   if __name__ == '__main__':main()
training data shape: (5000, 2)
initialization of the params:
mu:[[1. 0.][0. 1.][0. 0.][1. 1.]]
sigma:[[[1. 0.][0. 1.]][[1. 0.][0. 1.]][[1. 0.][0. 1.]][[1. 0.][0. 1.]]]
prior: [0.25 0.25 0.25 0.25]
iter: 0 log likelihood: -7758.98161924987
iter: 1 log likelihood: -6842.325796847348
iter: 2 log likelihood: -5877.092929285351
iter: 3 log likelihood: -5368.007026989181
iter: 4 log likelihood: -5158.951024247597
iter: 5 log likelihood: -4711.421034949499
iter: 6 log likelihood: -3814.307460091173
iter: 7 log likelihood: -2974.4639436766956
iter: 8 log likelihood: -2696.7255823784203
iter: 9 log likelihood: -2428.8597242586584
iter: 10 log likelihood: -2182.0334455177353
iter: 11 log likelihood: -2023.8042796345283
iter: 12 log likelihood: -1970.824061153165
iter: 13 log likelihood: -1956.739299533951
iter: 14 log likelihood: -1951.841638776625
iter: 15 log likelihood: -1949.6197599504249
iter: 16 log likelihood: -1948.411570496814
iter: 17 log likelihood: -1947.6739124172018
iter: 18 log likelihood: -1947.1944657348135
iter: 19 log likelihood: -1946.87392793565
iter: 20 log likelihood: -1946.6573830294146
iter: 21 log likelihood: -1946.5107251106433
iter: 22 log likelihood: -1946.4114561101228
iter: 23 log likelihood: -1946.3443661539402
iter: 24 log likelihood: -1946.299098150319
iter: 25 log likelihood: -1946.2685983080376
iter: 26 log likelihood: -1946.248073038022
iter: 27 log likelihood: -1946.2342732733175
iter: 28 log likelihood: -1946.225002083594
import numpy as np
from scipy.stats import multivariate_normal    #导入多元正太分布函数
from numpy import genfromtxt  
import matplotlib.pyplot as pyplot
import pickle 
with open('results.pkl', 'rb') as f:[prior, mu, sigma, ll_evol] = pickle.load(f)   #反序列化对象,将文件中的数据解析为python对象pyplot.plot(ll_evol, 'o')  #画出29个训练数据的ll_evol值
pyplot.show() print('prior:',prior)       #进过训练后的prior
print('mu:', mu)            #进过训练后的mu
print('sigma:', sigma)      #进过训练后的sigmaX = genfromtxt('.\data\TrainingData_GMM.csv', delimiter=',')
print('data shape:', X.shape)sel_num = 500
X_sel = []
sel_idxs = []
while len(sel_idxs) < sel_num:idx = np.random.randint(0, 5000, 1)    #如果len(sel_idxs)小于500,则从0到4999中返回一个随机整数给idxwhile idx in sel_idxs:                     #如果返回的idx在sel_idxs中已有,则继续从0到4999中返回一个随机整数给idxidx = np.random.randint(0, 5000, 1)sel_idxs.append(idx[0])            #把idx放入数组sel_idxs中
X_sel = X[sel_idxs]  def get_label(x, prior, mu, sigma):K = len(prior)p = np.zeros(K)for k in range(0,K):p[k] = prior[k] * multivariate_normal.pdf(x, mu[k,:], sigma[k,:,:])     #求k的概率plabel = np.argmax(p)      #输出最大p对应的索引值(即label)return labellbs = []
for i in range(0, sel_num):lb = get_label(X_sel[i], prior, mu, sigma)      #调用get_label函数传参后,得到相应的分类标签lbs.append(lb)# plot
pyplot.scatter(X_sel[:,0], X_sel[:,1], marker='o', c=lbs)      #做出lbs的散点图
pyplot.show()

在这里插入图片描述

prior: [0.23       0.27274177 0.26683872 0.23041951]
mu: [[ 1.20354296 -1.19685788][ 0.14438214  0.14615911][-0.44133345 -0.45061832][-0.40658589  0.32258308]]
sigma: [[[ 0.02258855 -0.00761021][-0.00761021  0.02361336]][[ 0.00885564  0.00186778][ 0.00186778  0.00880396]][[ 0.07027983  0.0373684 ][ 0.0373684   0.06508573]][[ 0.03447208 -0.01299104][-0.01299104  0.03454537]]]
data shape: (5000, 2)

在这里插入图片描述

参考

【机器学习】EM——期望最大(非常详细)

EM算法详解+通俗例子理解

(EM算法)The EM Algorithm

What is the expectation maximization
algorithm?

Python——EM(期望极大算法)实战(附详细代码与注解)(一)

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com