EM算法与高斯混合模型(GMM)系统梳理

一、核心前置概念

在学习EM和GMM前,需先明确以下基础概念,是理解后续内容的关键:

概念定义与作用
隐变量(Latent Variable)无法直接观测但影响可观测变量的变量,是EM算法的核心解决对象(如GMM中样本所属的高斯成分)
最大似然估计(MLE)给定观测数据,求解使似然函数最大的模型参数,适用于无隐变量的场景
高斯分布(正态分布)单变量:N(xμ,σ2)=12πσe−(x−μ)22σ2\mathcal{N}(x\mu, \sigma^2) = \frac{1}{\sqrt{2\pi}\sigma}e^{-\frac{(x-\mu)^2}{2\sigma^2}}N(,σ2)=2πσ1e2σ2(xμ)2;多变量:N(xμ,Σ)=1(2π)d/2Σ1/2e−12(x−μ)TΣ−1(x−μ)\mathcal{N}(\mathbf{x}\boldsymbol{\mu}, \boldsymbol{\Sigma}) = \frac{1}{(2\pi)^{d/2}\boldsymbol{\Sigma}^{1/2}}e^{-\frac{1}{2}(\mathbf{x}-\boldsymbol{\mu})^T\boldsymbol{\Sigma}^{-1}(\mathbf{x}-\boldsymbol{\mu})}N(xμ,Σ)=(2π)d/2Σ1/21e21(xμ)TΣ1(xμ)ddd为特征维度)

二、EM算法(期望最大化算法)

1. 算法定义

EM(Expectation-Maximization)是针对含隐变量的概率模型的参数估计迭代算法,核心是通过交替执行“期望步(E步)”和“最大化步(M步)”,逼近含隐变量模型的最大似然解(MLE)。

2. 核心思想

含隐变量的对数似然函数log⁡p(X∣Θ)\log p(X|\Theta)logp(X∣Θ)XXX为观测数据,Θ\ThetaΘ为模型参数)难以直接最大化,EM通过构造证据下界(ELBO) 替代原目标,交替优化下界以逼近最优解,保证每轮迭代后似然值非递减。

3. 通用迭代步骤

步骤操作
初始化设定模型参数初始值Θ(0)\Theta^{(0)}Θ(0)(如随机初始化),设定收敛阈值ϵ\epsilonϵ
E步计算隐变量的后验概率,构造对数似然关于隐变量的期望(Q函数):
Q(ΘΘ(t))=EZX,Θ(t)[log⁡p(X,ZΘ)]Q(\Theta\Theta^{(t)}) = \mathbb{E}_{ZX,\Theta^{(t)}}[\log p(X,Z\Theta)]Q(ΘΘ(t))=EZX,Θ(t)[logp(X,ZΘ)]
M步最大化Q函数,更新参数:Θ(t+1)=arg⁡max⁡ΘQ(ΘΘ(t)\Theta^{(t+1)} = \arg\max_{\Theta} Q(\Theta\Theta^{(t)}Θ(t+1)=argmaxΘQ(ΘΘ(t)
收敛判断∣Θ(t+1)−Θ(t)∣<ϵ|\Theta^{(t+1)} - \Theta^{(t)}| < \epsilonΘ(t+1)Θ(t)<ϵ或似然值变化<ϵ\epsilonϵ,停止迭代;否则回到E步

4. 收敛性

EM算法保证每轮迭代后对数似然值非递减,最终收敛到局部最优解(而非全局最优,初始值会影响结果)。

三、高斯混合模型(GMM)

1. 模型定义

GMM是由KKK个高斯分布(称为“成分”)加权组合而成的概率模型,用于建模多峰、非高斯的复杂数据分布,公式如下:

(1)单变量GMM

p(x)=∑k=1KπkN(x∣μk,σk2)p(x) = \sum_{k=1}^K \pi_k \mathcal{N}(x|\mu_k, \sigma_k^2)p(x)=k=1KπkN(xμk,σk2)

(2)多变量GMM

p(x)=∑k=1KπkN(x∣μk,Σk)p(\mathbf{x}) = \sum_{k=1}^K \pi_k \mathcal{N}(\mathbf{x}|\boldsymbol{\mu}_k, \boldsymbol{\Sigma}_k)p(x)=k=1KπkN(xμk,Σk)

其中核心约束与参数说明:

  • πk\pi_kπk:混合系数(第kkk个成分的权重),满足∑k=1Kπk=1\sum_{k=1}^K \pi_k = 1k=1Kπk=1πk≥0\pi_k \geq 0πk0
  • μk\boldsymbol{\mu}_kμk:第kkk个成分的ddd维均值向量;
  • Σk\boldsymbol{\Sigma}_kΣk:第kkk个成分的d×dd\times dd×d协方差矩阵(正定);
  • 模型总参数:Θ={π1,...,πK,μ1,...,μK,Σ1,...,ΣK}\Theta = \{\pi_1,...,\pi_K, \boldsymbol{\mu}_1,...,\boldsymbol{\mu}_K, \boldsymbol{\Sigma}_1,...,\boldsymbol{\Sigma}_K\}Θ={π1,...,πK,μ1,...,μK,Σ1,...,ΣK}

2. 用EM算法求解GMM(核心步骤)

GMM的参数估计是EM算法的经典应用,核心是将“样本所属的高斯成分”作为隐变量znkz_{nk}znkznk=1z_{nk}=1znk=1表示样本nnn属于第kkk个成分,∑kznk=1\sum_k z_{nk}=1kznk=1)。

(1)E步:计算“责任(Responsibility)”

责任γnk\gamma_{nk}γnk表示给定当前参数和样本xnx_nxn时,样本nnn属于第kkk个成分的后验概率:
γnk=p(znk=1∣xn,Θ(t))=πk(t)N(xn∣μk(t),Σk(t))∑j=1Kπj(t)N(xn∣μj(t),Σj(t))\gamma_{nk} = p(z_{nk}=1|x_n, \Theta^{(t)}) = \frac{\pi_k^{(t)} \mathcal{N}(x_n|\boldsymbol{\mu}_k^{(t)}, \boldsymbol{\Sigma}_k^{(t)})}{\sum_{j=1}^K \pi_j^{(t)} \mathcal{N}(x_n|\boldsymbol{\mu}_j^{(t)}, \boldsymbol{\Sigma}_j^{(t)})}γnk=p(znk=1∣xn,Θ(t))=j=1Kπj(t)N(xnμj(t),Σj(t))πk(t)N(xnμk(t),Σk(t))

(2)M步:更新模型参数

基于E步的责任,最大化Q函数,得到参数更新公式:

参数类型更新公式
混合系数πk(t+1)=1N∑n=1Nγnk\pi_k^{(t+1)} = \frac{1}{N} \sum_{n=1}^N \gamma_{nk}πk(t+1)=N1n=1NγnkNNN为样本总数)
均值μk(t+1)=∑n=1Nγnkxn∑n=1Nγnk\boldsymbol{\mu}_k^{(t+1)} = \frac{\sum_{n=1}^N \gamma_{nk} \mathbf{x}_n}{\sum_{n=1}^N \gamma_{nk}}μk(t+1)=n=1Nγnkn=1Nγnkxn
协方差Σk(t+1)=∑n=1Nγnk(xn−μk(t+1))(xn−μk(t+1))T∑n=1Nγnk\boldsymbol{\Sigma}_k^{(t+1)} = \frac{\sum_{n=1}^N \gamma_{nk} (\mathbf{x}_n - \boldsymbol{\mu}_k^{(t+1)})(\mathbf{x}_n - \boldsymbol{\mu}_k^{(t+1)})^T}{\sum_{n=1}^N \gamma_{nk}}Σk(t+1)=n=1Nγnkn=1Nγnk(xnμk(t+1))(xnμk(t+1))T
(3)收敛条件

当参数变化的L2范数小于阈值(如10−610^{-6}106),或对数似然值log⁡p(X∣Θ)\log p(X|\Theta)logp(X∣Θ)的变化小于阈值时,停止迭代。

3. GMM vs K-Means(关键对比)

GMM常与K-Means(硬聚类)对比,核心差异如下:

维度GMM(高斯混合模型)K-Means(K均值聚类)
聚类类型软聚类(输出样本属于每个成分的概率)硬聚类(输出样本唯一所属类别)
模型假设数据服从高斯混合分布,考虑均值+协方差数据簇为球形,仅考虑均值(距离)
求解方法EM算法迭代重分配(距离最小化)
输出结果概率分布+聚类标签仅聚类标签
鲁棒性对异常值更敏感(协方差易受影响)对异常值敏感(距离易受影响)

四、Python实现语法与案例

1. 核心API语法(sklearn)

sklearn提供GaussianMixture类实现GMM,核心参数与方法如下:

类别内容
导入from sklearn.mixture import GaussianMixture
初始化gmm = GaussianMixture(n_components=K, # 高斯成分数<br> covariance_type='full', # 协方差类型:full/ diag/ spherical/ tied<br> max_iter=100, # 最大迭代次数<br> tol=1e-6, # 收敛阈值<br> random_state=42)
训练gmm.fit(X) # X为形状(n_samples, n_features)的数组
预测聚类标签labels = gmm.predict(X) # 硬聚类标签(概率最大的成分)
预测概率probs = gmm.predict_proba(X) # 形状(n_samples, K),每个样本属于各成分的概率
模型参数gmm.weights_ # 混合系数π
gmm.means_ # 均值μ
gmm.covariances_ # 协方差Σ

2. 完整案例:GMM拟合二维模拟数据

步骤1:生成模拟数据
import numpy as np
import matplotlib.pyplot as plt
from sklearn.mixture import GaussianMixture
from scipy.stats import multivariate_normal

# 1. 生成二维高斯混合数据
np.random.seed(42)
# 定义3个高斯成分的参数
K = 3
n_samples = 500
# 成分1:均值[0,0],协方差[[1,0.5],[0.5,1]],样本数200
mean1 = [0, 0]
cov1 = [[1, 0.5], [0.5, 1]]
data1 = np.random.multivariate_normal(mean1, cov1, 200)
# 成分2:均值[5,5],协方差[[1,-0.5],[-0.5,1]],样本数150
mean2 = [5, 5]
cov2 = [[1, -0.5], [-0.5, 1]]
data2 = np.random.multivariate_normal(mean2, cov2, 150)
# 成分3:均值[0,8],协方差[[1,0],[0,1]],样本数150
mean3 = [0, 8]
cov3 = [[1, 0], [0, 1]]
data3 = np.random.multivariate_normal(mean3, cov3, 150)
# 合并数据
X = np.vstack([data1, data2, data3])
y_true = np.hstack([np.zeros(200), np.ones(150), np.ones(150)*2])  # 真实标签

# 可视化原始数据
plt.figure(figsize=(8, 6))
plt.scatter(X[:,0], X[:,1], c=y_true, cmap='viridis', alpha=0.6)
plt.title('原始模拟数据(3个高斯成分)')
plt.xlabel('特征1')
plt.ylabel('特征2')
plt.show()
步骤2:sklearn实现GMM
# 2. 用sklearn拟合GMM
gmm = GaussianMixture(
    n_components=3,  # 3个成分
    covariance_type='full',  # 全协方差矩阵
    max_iter=200,
    tol=1e-6,
    random_state=42
)
gmm.fit(X)

# 输出模型参数
print("=== GMM模型参数 ===")
print(f"混合系数(π):{gmm.weights_}")
print(f"均值(μ):\n{gmm.means_}")
print(f"协方差(Σ):\n{gmm.covariances_}")

# 预测聚类标签和概率
labels_pred = gmm.predict(X)
probs_pred = gmm.predict_proba(X)

# 可视化拟合结果
plt.figure(figsize=(8, 6))
# 绘制样本
plt.scatter(X[:,0], X[:,1], c=labels_pred, cmap='viridis', alpha=0.6)
# 绘制每个高斯成分的等高线
x_min, x_max = X[:,0].min()-1, X[:,0].max()+1
y_min, y_max = X[:,1].min()-1, X[:,1].max()+1
xx, yy = np.meshgrid(np.linspace(x_min, x_max, 100), np.linspace(y_min, y_max, 100))
zz = np.zeros_like(xx)
for k in range(K):
    # 计算每个网格点的概率密度
    rv = multivariate_normal(gmm.means_[k], gmm.covariances_[k])
    zz += gmm.weights_[k] * rv.pdf(np.dstack((xx, yy)))
# 绘制等高线
plt.contour(xx, yy, zz, levels=5, colors='black', alpha=0.5)
plt.title('GMM拟合结果(sklearn)')
plt.xlabel('特征1')
plt.ylabel('特征2')
plt.show()
步骤3:手动实现EM算法拟合GMM(核心逻辑)
def gmm_em(X, K, max_iter=200, tol=1e-6):
    """
    手动实现EM算法拟合GMM
    参数:
        X: 数据,形状(n_samples, n_features)
        K: 高斯成分数
        max_iter: 最大迭代次数
        tol: 收敛阈值
    返回:
        pi: 混合系数,形状(K,)
        mu: 均值,形状(K, n_features)
        sigma: 协方差,形状(K, n_features, n_features)
        gamma: 责任,形状(n_samples, K)
    """
    n_samples, n_features = X.shape
    
    # 1. 初始化参数
    # 混合系数:均匀初始化
    pi = np.ones(K) / K
    # 均值:随机选择K个样本作为初始均值
    idx = np.random.choice(n_samples, K, replace=False)
    mu = X[idx]
    # 协方差:初始化为单位矩阵
    sigma = np.array([np.eye(n_features) for _ in range(K)])
    
    # 初始化对数似然
    log_likelihood = []
    
    for _ in range(max_iter):
        # 2. E步:计算责任gamma
        gamma = np.zeros((n_samples, K))
        for k in range(K):
            # 计算每个样本在第k个成分的概率密度
            gamma[:, k] = pi[k] * multivariate_normal.pdf(X, mean=mu[k], cov=sigma[k])
        # 归一化得到后验概率
        gamma = gamma / gamma.sum(axis=1, keepdims=True)
        
        # 计算当前对数似然
        ll = np.sum(np.log(np.sum([pi[k] * multivariate_normal.pdf(X, mu[k], sigma[k]) for k in range(K)], axis=0)))
        log_likelihood.append(ll)
        
        # 3. M步:更新参数
        # 更新混合系数
        pi_new = gamma.sum(axis=0) / n_samples
        # 更新均值
        mu_new = np.zeros_like(mu)
        for k in range(K):
            mu_new[k] = (gamma[:, k].reshape(-1,1) * X).sum(axis=0) / gamma[:, k].sum()
        # 更新协方差
        sigma_new = np.zeros_like(sigma)
        for k in range(K):
            diff = X - mu_new[k]
            sigma_new[k] = (gamma[:, k].reshape(-1,1,1) * np.einsum('ni,nj->nij', diff, diff)).sum(axis=0) / gamma[:, k].sum()
        
        # 4. 收敛判断
        if np.linalg.norm(pi_new - pi) < tol and \
           np.linalg.norm(mu_new - mu) < tol and \
           np.linalg.norm(sigma_new - sigma) < tol:
            break
        
        # 更新参数
        pi, mu, sigma = pi_new, mu_new, sigma_new
    
    return pi, mu, sigma, gamma

# 调用手动实现的EM-GMM
pi_manual, mu_manual, sigma_manual, gamma_manual = gmm_em(X, K=3, max_iter=200, tol=1e-6)

# 输出手动拟合的参数
print("\n=== 手动EM-GMM模型参数 ===")
print(f"混合系数(π):{pi_manual}")
print(f"均值(μ):\n{mu_manual}")
print(f"协方差(Σ):\n{sigma_manual}")

# 可视化手动拟合结果
labels_manual = np.argmax(gamma_manual, axis=1)
plt.figure(figsize=(8, 6))
plt.scatter(X[:,0], X[:,1], c=labels_manual, cmap='viridis', alpha=0.6)
# 绘制等高线
x_min, x_max = X[:,0].min()-1, X[:,0].max()+1
y_min, y_max = X[:,1].min()-1, X[:,1].max()+1
xx, yy = np.meshgrid(np.linspace(x_min, x_max, 100), np.linspace(y_min, y_max, 100))
zz = np.zeros_like(xx)
for k in range(K):
    rv = multivariate_normal(mu_manual[k], sigma_manual[k])
    zz += pi_manual[k] * rv.pdf(np.dstack((xx, yy)))
plt.contour(xx, yy, zz, levels=5, colors='black', alpha=0.5)
plt.title('手动EM算法拟合GMM结果')
plt.xlabel('特征1')
plt.ylabel('特征2')
plt.show()

3. 案例结果说明

  • 模拟数据由3个二维高斯成分组成,sklearn和手动实现的EM-GMM均能较好拟合出3个成分的参数;
  • 手动实现的参数与sklearn结果略有差异(初始值不同),但聚类效果一致;
  • 等高线清晰展示了每个高斯成分的分布范围,混合系数反映了各成分的样本占比。

五、关键注意事项

  1. 成分数K的选择:需通过信息准则(如AIC、BIC)确定,sklearn的GaussianMixture支持aic()bic()方法;
  2. 初始值敏感:EM易陷入局部最优,可多次随机初始化取似然值最大的结果;
  3. 协方差类型covariance_type参数(full/diag/spherical/tied)需根据数据特性选择(如球形协方差等价于K-Means的球形假设);
  4. 数据预处理:GMM对数据尺度敏感,建议先标准化(StandardScaler)。

六、总结

EM算法是处理含隐变量模型参数估计的通用框架,GMM是EM算法的经典应用,核心是通过“责任”的交替计算与参数更新拟合多峰分布。相比K-Means,GMM能输出概率分布,更贴合真实数据的统计特性,是机器学习中聚类、密度估计、生成模型的重要工具。

更多推荐