机器学习-EM算法:从硬币实验到隐变量模型的参数估计
1. 从抛硬币实验理解EM算法想象你面前有两个外观完全相同的硬币A和B但它们的重量分布略有不同——硬币A正面朝上的概率是0.6硬币B是0.3这些真实概率你并不知道。现在有人用这两枚硬币进行了多轮抛掷实验每轮随机选择一枚硬币抛5次但故意不告诉你每轮用的是哪枚硬币。你拿到的只是类似这样的记录[1,0,1,1,0], [0,0,1,0,1], [1,1,1,0,1],...这就是典型的含隐变量的参数估计问题——你能看到每次抛掷的结果观测变量但不知道每次实验用的是哪枚硬币隐变量。这时候传统的最大似然估计就束手无策了而EM算法却能优雅地解决。我第一次遇到这个问题时尝试直接用最大似然估计结果发现似然函数里出现了和的对数log of sum的形式求导后方程根本解不开。后来才明白正是隐变量的存在使得问题变得复杂。EM算法的精妙之处在于它不直接求解这个难题而是通过交替执行两个步骤来逼近最优解E步Expectation基于当前参数猜测隐变量的分布M步Maximization基于隐变量分布更新参数估计这就好比你在玩一个猜硬币-调参数的游戏先随便假设硬币A和B的正面概率比如都是0.5然后根据这个假设计算每组数据来自A/B的概率E步再用这个概率重新估计两枚硬币的参数M步。反复进行这个过程参数就会越来越接近真实值。2. EM算法的数学原理2.1 最大似然估计的困境假设我们有一组独立同分布的观测数据X{x₁,...,xₙ}其概率密度函数p(x|θ)由参数θ决定。传统最大似然估计通过最大化似然函数L(θ)∏p(xᵢ|θ)来求解θ。但当存在隐变量Z时似然函数变为L(θ)∏∑p(xᵢ,zⱼ|θ)这个和的对数形式使得求导极其困难。好比你要调配一杯鸡尾酒但不知道每种原料的具体比例隐变量直接通过最终口感观测数据反推配方参数几乎不可能。2.2 Jensen不等式带来的突破EM算法的核心技巧是引入一个关于隐变量的分布q(z)通过Jensen不等式构造似然函数的下界log p(X|θ) ≥ ∑∑q(z)log[p(x,z|θ)/q(z)]这个下界称为ELBOEvidence Lower Bound。EM算法就是通过交替优化这个下界来间接优化似然函数E步固定θ令q(z)p(z|x,θ)使下界紧贴似然函数M步固定q(z)优化θ最大化下界这个过程就像爬山时遇到峭壁无法直接攀登转而走之字形路线横向移动找更好的起点E步然后向上爬升M步如此反复直到山顶。2.3 收敛性证明为什么这样交替优化一定能收敛可以证明每次迭代后似然函数都不减小L(θ⁽ᵗ⁺¹⁾) ≥ L(θ⁽ᵗ⁾)这是因为E步使下界等于当前似然值M步使下界增大新的E步在新的θ下重新使下界等于似然值因此似然函数单调递增最终会收敛到局部最大值。这就像你每次调整配方都让鸡尾酒更好喝最终必然能找到最佳口味。3. EM算法的实现细节3.1 硬币实验的Python实现让我们用Python实现开头的硬币实验。假设真实参数为θ_A0.6θ_B0.3生成模拟数据import numpy as np # 真实参数 true_theta {A:0.6, B:0.3} # 生成数据100轮实验每轮随机选硬币抛10次 np.random.seed(42) observations [] for _ in range(100): coin np.random.choice([A,B]) prob true_theta[coin] results np.random.binomial(1, prob, size10) observations.append(results)EM算法的核心代码如下def em_single(init_theta, observations): 单次EM迭代 # E步计算隐变量分布 counts {A:{H:0,T:0}, B:{H:0,T:0}} theta_A, theta_B init_theta for obs in observations: n len(obs) heads sum(obs) tails n - heads # 计算来自A/B的概率二项分布 prob_A (theta_A**heads)*((1-theta_A)**tails) prob_B (theta_B**heads)*((1-theta_B)**tails) # 归一化得到权重 weight_A prob_A / (prob_A prob_B) weight_B prob_B / (prob_A prob_B) # 加权计数 counts[A][H] weight_A * heads counts[A][T] weight_A * tails counts[B][H] weight_B * heads counts[B][T] weight_B * tails # M步更新参数 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]3.2 完整迭代过程运行完整的EM算法def em(observations, init_theta, tol1e-6, max_iter100): theta init_theta history [theta] for i in range(max_iter): new_theta em_single(theta, observations) history.append(new_theta) # 检查收敛条件 if np.sum(np.abs(np.array(new_theta)-np.array(theta))) tol: break theta new_theta return theta, history # 初始猜测两枚硬币都是公平的 init_theta [0.5, 0.5] final_theta, history em(observations, init_theta)在我的实验中经过约15次迭代后参数收敛到[0.593, 0.307]非常接近真实值[0.6,0.3]。下图展示了参数的收敛过程迭代次数θ_Aθ_B00.5000.50050.5720.325100.5890.310150.5930.3074. EM算法的应用与变种4.1 高斯混合模型(GMM)EM算法最著名的应用就是高斯混合模型。假设数据由K个高斯分布混合生成但每个数据点来自哪个分布未知。这时E步计算每个数据点属于各高斯分布的概率M步用加权数据重新估计每个高斯分布的均值和方差这就像给数据点染色——根据当前模型给每个点分配属于各个成分的颜色深浅再用这些颜色重新调整各个成分的形状。4.2 隐马尔可夫模型(HMM)在语音识别等领域HMM用EM算法这时称为Baum-Welch算法来估计状态转移概率观测发射概率通过反复调整这些概率使得模型最能解释观测到的语音序列。4.3 变分EM当E步中后验分布p(z|x,θ)难以计算时可以用变分推断近似。这就像用简单的几何形状如长方体去近似复杂物体如雕塑的体积。5. 实践中的注意事项5.1 初始值选择EM算法对初始值敏感不同初始值可能导致收敛到不同的局部最优。实践中可以尝试多个随机初始值使用k-means等简单方法先聚类根据领域知识选择合理初值我在一个客户分群项目中就吃过亏——由于初始值选得不好模型收敛到一个毫无业务意义的解。后来改用k-means中心作为初始值效果立竿见影。5.2 过拟合问题当隐变量较多时EM算法容易过拟合。解决方法包括使用贝叶斯方法引入先验采用正则化技术交叉验证选择模型复杂度5.3 收敛判断除了参数变化小于阈值外还可以监控似然函数的变化设置最大迭代次数防止无限循环当验证集性能下降时提前停止有一次我忘记设置最大迭代次数结果算法在已经收敛的情况下又空转了上千次白白浪费计算资源。