MCM520 ← 资料站首页 高斯混合模型 GMM · 深度手册 打开交互阅读器 →

高斯混合模型 GMM · 深度手册

分类:聚类分类 | 难度:★★☆ 进阶 | 编号:gmm


📊 数据视角:它到底有多常用?

本资料站收录 343 篇 优秀范文,GMM 共出现约 20 次,排名靠前。其中:

  • 美赛(MCM/ICM):15 次,主要用于概率建模和聚类;
  • 国赛(CUMCM):3 次;
  • 电工杯 / 泰迪杯:约 2 次。

关键词覆盖:"GMM"、"高斯混合模型"、"EM算法"、"概率聚类"、"期望最大化" 等。

一句话:GMM 是 K-Means 的概率升级版——不是把点硬分配到某个簇,而是说"这个点有 70% 概率属于簇 1,25% 概率属于簇 2,5% 属于簇 3",用 EM 算法迭代求解。


一、这是什么(一句话用途)

软聚类 / 概率密度估计 / 生成模型(客户分群、异常检测、语音识别)


二、核心思想

高斯混合模型(Gaussian Mixture Model, GMM)假设数据由 K 个高斯分布混合生成:

p(x)=∑k=1KπkN(x∣μk,Σk)p(x) = \sum_{k=1}^{K} \pi_k \mathcal{N}(x \mid \mu_k, \Sigma_k)

其中 πk\pi_k 是第 k 个分量的混合系数(∑πk=1\sum \pi_k = 1),N(x∣μk,Σk)\mathcal{N}(x \mid \mu_k, \Sigma_k) 是高斯分布。

与 K-Means 的区别:

  • K-Means:硬分配——每个点属于且仅属于一个簇
  • GMM:软分配——每个点以一定概率属于每个簇
  • K-Means:簇是球形等大小的
  • GMM:簇可以是椭圆、不同大小、不同方向(通过协方差矩阵)

三、数学原理与推导

3.1 模型定义

GMM 的参数:θ={πk,μk,Σk}k=1K\theta = \{\pi_k, \mu_k, \Sigma_k\}_{k=1}^{K}

似然函数:
L(θ)=∏i=1N∑k=1KπkN(xi∣μk,Σk)L(\theta) = \prod_{i=1}^{N} \sum_{k=1}^{K} \pi_k \mathcal{N}(x_i \mid \mu_k, \Sigma_k)

3.2 EM 算法(Expectation-Maximization)

E步(期望):计算每个点属于每个簇的后验概率(责任度)
γik=πkN(xi∣μk,Σk)∑j=1KπjN(xi∣μj,Σj)\gamma_{ik} = \frac{\pi_k \mathcal{N}(x_i \mid \mu_k, \Sigma_k)}{\sum_{j=1}^{K} \pi_j \mathcal{N}(x_i \mid \mu_j, \Sigma_j)}

M步(最大化):更新参数
πknew=NkN,Nk=∑i=1Nγik\pi_k^{new} = \frac{N_k}{N}, \quad N_k = \sum_{i=1}^{N} \gamma_{ik}
μknew=1Nk∑i=1Nγikxi\mu_k^{new} = \frac{1}{N_k} \sum_{i=1}^{N} \gamma_{ik} x_i
Σknew=1Nk∑i=1Nγik(xi−μknew)(xi−μknew)T\Sigma_k^{new} = \frac{1}{N_k} \sum_{i=1}^{N} \gamma_{ik} (x_i - \mu_k^{new})(x_i - \mu_k^{new})^T

迭代 E-M 直到收敛。

3.3 BIC/AIC 选 K

BIC=−2ln⁡(L)+dln⁡(N)\text{BIC} = -2\ln(L) + d\ln(N)
AIC=−2ln⁡(L)+2d\text{AIC} = -2\ln(L) + 2d
其中 dd 为参数个数。选 BIC/AIC 最小的 K。


四、建模 / 求解步骤

  1. 数据标准化
  2. 选择 K 值(BIC/AIC 或肘部法)
  3. 初始化参数(K-Means 结果初始化)
  4. EM 迭代至收敛
  5. 评估:对数似然、BIC、聚类效果

五、Python 实现示例

5.1 从零手写 GMM(对角协方差)

import numpy as np

class GMM:
    def __init__(self, K=3, max_iter=100, tol=1e-6):
        self.K = K
        self.max_iter = max_iter
        self.tol = tol
    
    def _gaussian(self, X, mu, cov):
        """计算高斯概率密度"""
        diff = X - mu
        inv_cov = np.linalg.inv(cov)
        det = np.linalg.det(cov)
        exponent = -0.5 * np.sum(diff @ inv_cov * diff, axis=1)
        return (1.0 / np.sqrt((2*np.pi)**X.shape[1] * det)) * np.exp(exponent)
    
    def fit(self, X):
        N, D = X.shape
        # 用 K-Means 初始化
        rng = np.random.default_rng(42)
        idx = rng.choice(N, self.K, replace=False)
        self.mu = X[idx].copy()
        self.pi = np.ones(self.K) / self.K
        self.cov = np.array([np.cov(X.T) for _ in range(self.K)])
        
        log_likelihood_prev = -np.inf
        
        for iteration in range(self.max_iter):
            # E-step
            responsibilities = np.zeros((N, self.K))
            for k in range(self.K):
                responsibilities[:, k] = self.pi[k] * self._gaussian(X, self.mu[k], self.cov[k])
            responsibilities /= responsibilities.sum(axis=1, keepdims=True)
            
            # M-step
            N_k = responsibilities.sum(axis=0)
            self.pi = N_k / N
            for k in range(self.K):
                diff = X - self.mu[k]
                weighted_diff = responsibilities[:, k:k+1] * diff
                self.mu[k] = (responsibilities[:, k] @ X) / N_k[k]
                self.cov[k] = (weighted_diff.T @ diff) / N_k[k]
            
            # 检查收敛
            log_likelihood = np.sum(np.log(responsibilities @ np.array([self._gaussian(X, self.mu[k], self.cov[k]) for k in range(self.K)]).T + 1e-300)))
            if abs(log_likelihood - log_likelihood_prev) < self.tol:
                print(f'收敛于迭代 {iteration+1}')
                break
            log_likelihood_prev = log_likelihood
        
        self.responsibilities_ = responsibilities
        return self
    
    def predict(self, X):
        return np.argmax(self.responsibilities_, axis=1)

# 测试
np.random.seed(42)
X = np.vstack([
    np.random.randn(100, 2) * [1, 2] + [0, 0],
    np.random.randn(100, 2) * [2, 1] + [5, 5],
    np.random.randn(100, 2) * [0.5, 0.5] + [10, 0],
])

gmm = GMM(K=3).fit(X)
print(f"混合系数: {np.round(gmm.pi, 3)}")
print(f"均值:\n{np.round(gmm.mu, 2)}")

5.2 使用 sklearn

import numpy as np
from sklearn.mixture import GaussianMixture
from sklearn.model_selection import cross_val_score
import matplotlib.pyplot as plt

np.random.seed(42)
# 椭圆形状的簇
X1 = np.random.multivariate_normal([0, 0], [[1, 0.5], [0.5, 1]], 100)
X2 = np.random.multivariate_normal([5, 5], [[2, -0.5], [-0.5, 0.5]], 100)
X = np.vstack([X1, X2])

# 用 BIC 选 K
bic_scores = []
for K in range(1, 7):
    gmm = GaussianMixture(n_components=K, random_state=42)
    gmm.fit(X)
    bic_scores.append(gmm.bic(X))

best_K = np.argmin(bic_scores) + 1
print(f"最优 K = {best_K} (BIC最小)")

# 拟合最终模型
gmm = GaussianMixture(n_components=best_K, random_state=42).fit(X)
labels = gmm.predict(X)
probas = gmm.predict_proba(X)

print(f"混合系数: {np.round(gmm.weights_, 3)}")
print(f"均值:\n{np.round(gmm.means_, 2)}")
print(f"协方差:\n{np.round(gmm.covariances_, 2)}")

六、MATLAB 实现示例

%% GMM 聚类(MATLAB/Octave)
rng(42);
% 生成数据
X1 = randn(100,2) + [0,0];
X2 = randn(100,2) + [5,5];
X = [X1; X2];

% 使用内置 gmdistribution
K = 2;
gmm = fitgmdist(X, K);
labels = posterior(gmm, X);
labels = categorical(labels == max(labels, [], 2));

% BIC 选 K
BIC = inf;
for k = 1:5
    temp = fitgmdist(X, k);
    if temp.BIC < BIC
        BIC = temp.BIC;
        bestK = k;
    end
end
fprintf('最优 K = %d, BIC = %.2f\n', bestK, BIC);

% 输出参数
disp('均值:'); disp(gmm.mu);
disp('混合系数:'); disp(gmm.weights);

七、GMM vs K-Means 对比

特性 K-Means GMM
分配方式 硬分配 软分配(概率)
簇形状 球形 椭圆形(可旋转)
参数 只需 K K + 均值 + 协方差 + 混合系数
计算复杂度 O(nKt) O(nKtd)
解释性 简单 概率语义强

八、常见误区与避坑清单

误区 正确做法
K 随便选 用 BIC/AIC 选最优 K
协方差矩阵奇异 加正则化项或对角协方差
不标准化直接拟合 必须先 StandardScaler
初始化太随机 用 K-Means 结果初始化
忽略对数似然收敛 检查 log_likelihood 是否单调递增

九、论文写作技巧

本文采用高斯混合模型(GMM)进行软聚类。GMM 假设数据由 K 个高斯分布混合生成,通过 EM 算法迭代求解参数。与 K-Means 的硬分配不同,GMM 给出每个样本属于各簇的概率,更适合存在重叠簇的场景。经 BIC 准则选择,最优簇数 K=3。


十、相关手册(延伸阅读)


完整算例(数字演示,照着算一遍)

场景:1 维数据 200 点,呈双峰,用 GMM(K=2) 拟合。

EM 迭代:收敛后两成分权重 π=(0.6,0.4),均值 μ=(2.0,5.5),方差 σ²=(1.0,1.2)。

结论:数据被分为两类,各自服从高斯分布,软归属按后验概率分配。

十一、本手册导航


本手册由「算法深度手册生成器」自动产出。