欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 新闻 > 会展 > EM算法到底是什么东东

EM算法到底是什么东东

2025/4/9 16:15:18 来源:https://blog.csdn.net/Listennnn/article/details/147016470  浏览:    关键词:EM算法到底是什么东东

EM(Expectation-Maximization期望最大化)算法是机器学习中非常重要的一类算法,广泛应用于聚类、缺失数据建模、隐变量模型学习等场景,比如高斯混合模型(GMM)就是经典应用。

🐤 第一步:直观理解

EM算法的核心是:

我不知道这个数据是哪一类(隐变量),就先猜;然后根据可见的情况,慢慢猜的更准。
EM算法就是一个“猜→修正→再猜”的循环。

例子1:

  • 给你一篇文章让你读
  • 可观测数据:文档中的词语。
  • 隐变量:文档的主题分布。
  • 本质:主题是潜在的,决定了词语的出现概率。

例子2:
假设有两个数据分布(两类),然后随机从这两个分布里抽出一些样本交给你,你不知道给你的样本点属于哪一类(隐含的类别),以及这两个数据分布的统计特性(均值,方差)

EM算法的做法是:

  1. 随便猜一下每个点属于哪个类别(初始猜测)
  2. 计算:在当前参数下,每个点属于各个类别的“概率”(这是E步)
  3. 用这些概率来“反推”出最合理的类别参数(比如均值、方差)(这是M步)
  4. 重复步骤2-3,直到参数不怎么变为止。

✍️ 第二步:数学公式

你有一堆数据点 x 1 , … , x n \mathbf{x}_1, \dots, \mathbf{x}_n x1,,xn,你相信这些数据来自 K K K 个不同的高斯分布:

  • 每个分布 k k k 有自己的参数:均值 μ k \mu_k μk、方差 σ k 2 \sigma_k^2 σk2、权重 π k \pi_k πk(概率总和为1)
  • 但你不知道哪个点来自哪个分布(这是隐变量)

E步(Expectation),即“先猜”

初始化:随机初始化均值 μ k \mu_k μk、方差 σ k 2 \sigma_k^2 σk2 和权重 π k \pi_k πk

计算每个样本属于每个高斯分布的“后验概率”:

γ i k = π k ⋅ N ( x i ∣ μ k , σ k 2 ) ∑ j = 1 K π j ⋅ N ( x i ∣ μ j , σ j 2 ) \gamma_{ik} = \frac{\pi_k \cdot \mathcal{N}(x_i | \mu_k, \sigma_k^2)}{\sum_{j=1}^K \pi_j \cdot \mathcal{N}(x_i | \mu_j, \sigma_j^2)} γik=j=1KπjN(xiμj,σj2)πkN(xiμk,σk2)

这表示:样本 x i x_i xi 属于第 k k k 个高斯分布的概率。


M步(Maximization),即“反推参数”

根据这些概率 γ i k \gamma_{ik} γik 来重新估计参数:

μ k = ∑ i γ i k x i ∑ i γ i k , σ k 2 = ∑ i γ i k ( x i − μ k ) 2 ∑ i γ i k , π k = 1 n ∑ i γ i k \mu_k = \frac{\sum_i \gamma_{ik} x_i}{\sum_i \gamma_{ik}}, \quad \sigma_k^2 = \frac{\sum_i \gamma_{ik} (x_i - \mu_k)^2}{\sum_i \gamma_{ik}}, \quad \pi_k = \frac{1}{n} \sum_i \gamma_{ik} μk=iγikiγikxi,σk2=iγikiγik(xiμk)2,πk=n1iγik


🧊 第三步 :一个具体的例子——高斯混合模型(GMM)

什么是GMM?

高斯混合模型(GMM)就是用多个“高斯分布”加权叠加来组合描述一个复杂的数据分布。GMM 的参数(每个高斯的均值、方差、权重)不能直接算出来,但可以用 EM算法 来一步步逼近!

  • GMM = 模型框架
  • EM = 参数求解方法

GMM分布可视化

import numpy as np
import matplotlib.pyplot as plt
from scipy.stats import norm# 解决中文显示问题
plt.rcParams['font.sans-serif'] = ['SimHei']  # 使用黑体显示中文
plt.rcParams['axes.unicode_minus'] = False  # 解决负号显示问题# 定义两个高斯分布的参数
# 每个分布由均值(mu)、标准差(sigma)和权重(weight)组成
mu1, sigma1, weight1 = 5, 1, 0.4  # 分布1: 均值5, 标准差1, 权重40%
mu2, sigma2, weight2 = 15, 2, 0.6  # 分布2: 均值15, 标准差2, 权重60%# 生成X轴范围,覆盖两个分布的3σ范围
x_min = min(mu1 - 3*sigma1, mu2 - 3*sigma2)
x_max = max(mu1 + 3*sigma1, mu2 + 3*sigma2)
x = np.linspace(x_min, x_max, 1000)  # 在合理范围内生成1000个点# 计算单个分布的概率密度函数(PDF)
pdf1 = weight1 * norm.pdf(x, mu1, sigma1)  # 第一个高斯分布的加权PDF
pdf2 = weight2 * norm.pdf(x, mu2, sigma2)  # 第二个高斯分布的加权PDF# 计算混合后的整体分布(GMM的概率密度)
pdf_total = pdf1 + pdf2  # 高斯混合模型的PDF是两个加权高斯分布的和# 创建图形并设置大小
plt.figure(figsize=(10, 6))# 绘制各个分布
plt.plot(x, pdf1, label=f"高斯分布1 (μ={mu1}, σ={sigma1}, 权重={weight1})",linestyle='--', color='blue')
plt.plot(x, pdf2, label=f"高斯分布2 (μ={mu2}, σ={sigma2}, 权重={weight2})",linestyle='--', color='green')
plt.plot(x, pdf_total, label="混合分布 GMM", linestyle='--',color='red', linewidth=1.5)# 添加图形标题和标签
plt.title("高斯混合模型(GMM)示意图", fontsize=14)
plt.xlabel("特征值 (示例:糖分含量)", fontsize=12)
plt.ylabel("概率密度", fontsize=12)# 添加图例和网格
plt.legend(fontsize=10)
plt.grid(True, linestyle='--', alpha=0.6)# 显示图形
plt.tight_layout()  # 自动调整子图参数,使之填充整个图像区域
plt.show()

问题背景

假设我们有一堆学生身高数据,比如160cm、155cm、175cm等等,但我们不知道每个学生是小学生还是中学生。我们猜测这些身高来自两个群体:

  • 小学生:身高服从一个正态分布(高斯分布),有自己的均值和标准差。
  • 中学生:身高服从另一个正态分布,也有自己的均值和标准差。

此外,每个群体在总数据中占一定比例。我们的目标是:

  1. 弄清楚每个学生属于小学生还是中学生的概率。
  2. 估计两个群体的参数:比例( π π π)、均值( μ μ μ)、标准差( σ σ σ)。

因为我们不知道真实的类别和参数,所以要用EM算法通过迭代来解决这个问题。


EM算法是什么?

EM算法(Expectation-Maximization)是一种用来处理“隐变量”问题的工具。这里,隐变量就是“每个学生属于哪个群体”,我们看不到它,但可以通过数据推测。EM算法分为两步:

  • E步(期望):根据当前猜测的参数,算出每个学生属于小学生或中学生的概率。
  • M步(最大化):用这些概率更新参数,让模型更好地拟合数据。

这两步不断重复,直到参数稳定。


具体案例:一步步拆解

1. 初始化:随便猜参数

我们先随便猜一下两个群体的参数,作为起点:

  • 小学生
    • 比例( π 1 π_1 π1):50%(0.5)
    • 均值( μ 1 μ_1 μ1):150cm
    • 标准差( σ 1 σ_1 σ1):5cm
  • 中学生
    • 比例( π 2 π_2 π2):50%(0.5)
    • 均值( μ 2 μ_2 μ2):170cm
    • 标准差( σ 2 σ_2 σ2):6cm

这些是初始猜测,不一定准确,但EM算法会帮我们调整。


2. E步:算概率(责任值)

现在拿一个学生,身高是160cm。我们要算他属于小学生还是中学生的概率。

(1)用正态分布公式算“可能性”

每个群体都有一个正态分布曲线:

  • 小学生:均值150cm,标准差5cm。
  • 中学生:均值170cm,标准差6cm。

正态分布的公式是:
P ( X ) = 1 2 π ⋅ σ exp ⁡ ( − ( X − μ ) 2 2 σ 2 ) P(X)=\frac{1}{\sqrt{2\pi}\cdot\sigma}\exp\left(-\frac{(X-\mu)^2}{2\sigma^2}\right) P(X)=2π σ1exp(2σ2(Xμ)2)

  • 小学生
    P ( 小学生 ∣ 160 ) = 1 2 π ⋅ 5 exp ⁡ ( − ( 160 − 150 ) 2 2 ⋅ 5 2 ) P(\text{小学生}|160)=\frac{1}{\sqrt{2\pi}\cdot5}\exp\left(-\frac{(160-150)^2}{2\cdot5^2}\right) P(小学生160)=2π 51exp(252(160150)2)
    计算指数部分:(160 - 150)² = 100,2 × 5² = 50,-100 / 50 = -2,exp(-2) ≈ 0.135。所以结果是一个较小的数。

  • 中学生
    P ( 中学生 ∣ 160 ) = 1 2 π ⋅ 6 exp ⁡ ( − ( 160 − 170 ) 2 2 ⋅ 6 2 ) P(\text{中学生}|160)=\frac{1}{\sqrt{2\pi}\cdot6}\exp\left(-\frac{(160-170)^2}{2\cdot6^2}\right) P(中学生160)=2π 61exp(262(160170)2)
    计算指数部分:(160 - 170)² = 100,2 × 6² = 72,-100 / 72 ≈ -1.39,exp(-1.39) ≈ 0.25。结果比小学生的稍大。

简单来说:

  • 160cm离150cm(小学生均值)较远,所以可能性较低。
  • 160cm离170cm(中学生均值)较近,所以可能性较高。
(2)结合比例算后验概率(责任值)

光看可能性还不够,还要考虑每个群体占的总比例( π 1 = 0.5 π_1=0.5 π1=0.5 π 2 = 0.5 π_2=0.5 π2=0.5)。用贝叶斯公式:
P ( 小学生 ∣ 160 ) = π 1 ⋅ P ( 160 ∣ 小学生 ) π 1 ⋅ P ( 160 ∣ 小学生 ) + π 2 ⋅ P ( 160 ∣ 中学生 ) P(\text{小学生}|160)=\frac{π_1\cdot P(160|\text{小学生})}{π_1\cdot P(160|\text{小学生})+π_2\cdot P(160|\text{中学生})} P(小学生160)=π1P(160小学生)+π2P(160中学生)π1P(160小学生)

假设计算后:

  • P ( 小学生 ∣ 160 ) ≈ 0.3 P(\text{小学生}|160)≈0.3 P(小学生160)0.3(30%)
  • P ( 中学生 ∣ 160 ) ≈ 0.7 P(\text{中学生}|160)≈0.7 P(中学生160)0.7(70%)

意思是:这个160cm的学生有30%概率是小学生,70%概率是中学生。对所有学生都做类似计算。


3. M步:更新参数

现在我们用所有学生的概率来调整参数。假设有3个学生:160cm、155cm、175cm,E步算出的概率如下:

身高P(小学生)P(中学生)
160cm0.30.7
155cm0.60.4
175cm0.10.9
(1)更新比例( π π π
  • π 1 = π_1= π1=所有学生属于小学生的概率平均值:
    π 1 = 0.3 + 0.6 + 0.1 3 = 1.0 3 ≈ 0.33 π_1=\frac{0.3+0.6+0.1}{3}=\frac{1.0}{3}≈0.33 π1=30.3+0.6+0.1=31.00.33
  • π 2 = 1 − π 1 ≈ 0.67 π_2=1-π_1≈0.67 π2=1π10.67
(2)更新均值( μ μ μ
  • μ 1 = μ_1= μ1=身高 × 属于小学生的概率的加权平均:
    μ 1 = ( 160 ⋅ 0.3 ) + ( 155 ⋅ 0.6 ) + ( 175 ⋅ 0.1 ) 0.3 + 0.6 + 0.1 = 48 + 93 + 17.5 1.0 = 158.5 cm μ_1=\frac{(160\cdot0.3)+(155\cdot0.6)+(175\cdot0.1)}{0.3+0.6+0.1}=\frac{48+93+17.5}{1.0}=158.5\,\text{cm} μ1=0.3+0.6+0.1(1600.3)+(1550.6)+(1750.1)=1.048+93+17.5=158.5cm
  • μ 2 = μ_2= μ2=类似计算:
    μ 2 = ( 160 ⋅ 0.7 ) + ( 155 ⋅ 0.4 ) + ( 175 ⋅ 0.9 ) 0.7 + 0.4 + 0.9 = 112 + 62 + 157.5 2.0 = 165.75 cm μ_2=\frac{(160\cdot0.7)+(155\cdot0.4)+(175\cdot0.9)}{0.7+0.4+0.9}=\frac{112+62+157.5}{2.0}=165.75\,\text{cm} μ2=0.7+0.4+0.9(1600.7)+(1550.4)+(1750.9)=2.0112+62+157.5=165.75cm
(3)更新标准差( σ σ σ
  • σ 1 = σ_1= σ1= 身高偏离新均值 μ 1 μ_1 μ1的加权方差:
    σ 1 = 0.3 ⋅ ( 160 − 158.5 ) 2 + 0.6 ⋅ ( 155 − 158.5 ) 2 + 0.1 ⋅ ( 175 − 158.5 ) 2 1.0 σ_1=\sqrt{\frac{0.3\cdot(160-158.5)^2+0.6\cdot(155-158.5)^2+0.1\cdot(175-158.5)^2}{1.0}} σ1=1.00.3(160158.5)2+0.6(155158.5)2+0.1(175158.5)2
    计算后可能得到一个新值,比如4.8cm。
  • σ 2 = σ_2= σ2=类似计算,得到新值,比如5.5cm。

4. 重复迭代

用新参数( π 1 = 0.33 , μ 1 = 158.5 , σ 1 = 4.8 , π 2 = 0.67 , μ 2 = 165.75 , σ 2 = 5.5 π_1=0.33,μ_1=158.5,σ_1=4.8,π_2=0.67,μ_2=165.75,σ_2=5.5 π1=0.33,μ1=158.5,σ1=4.8,π2=0.67,μ2=165.75,σ2=5.5)再跑一遍E步和M步。每轮迭代后,参数会更接近真实值。重复直到参数几乎不变,比如:

  • 小学生 π 1 ≈ 0.4 , μ 1 ≈ 148 cm , σ 1 ≈ 4 cm π_1≈0.4,μ_1≈148\text{cm},σ_1≈4\text{cm} π10.4,μ1148cm,σ14cm
  • 中学生 π 2 ≈ 0.6 , μ 2 ≈ 172 cm , σ 2 ≈ 5 cm π_2≈0.6,μ_2≈172\text{cm},σ_2≈5\text{cm} π20.6,μ2172cm,σ25cm

这意味着EM算法成功把混合的身高数据分成了两个群体,并估计了它们的特征。


📊 第四步:完整Python代码

import numpy as np
from scipy.stats import norm
from sklearn.cluster import KMeans
import seaborn as sns
import matplotlib.pyplot as pltclass GMM_EM:"""高斯混合模型(GMM)的EM算法核心实现 - 用于学生身高分布分析案例背景:假设数据包含两个学生群体的身高数据:1. 小学生:服从N(μ1, σ1²)2. 中学生:服从N(μ2, σ2²)每个群体在总样本中占有比例π目标:通过EM算法估计这两个群体的分布参数(π, μ, σ)"""def __init__(self, n_components=2, max_iter=100, tol=1e-6, random_state=42):"""模型初始化参数:n_components : int, default=2要区分的学生群体数量(默认2类:小学生/中学生)max_iter : int, default=100EM算法最大迭代次数tol : float, default=1e-6参数变化收敛阈值(当参数变化小于此值时停止迭代)random_state : int, default=42随机种子,保证结果可重复"""self.n_components = n_components  # 学生群体数量self.max_iter = max_iter  # 最大迭代次数self.tol = tol  # 收敛判断阈值self.random_state = random_state  # 随机种子self.pi = None  # 各群体比例(小学生/中学生的样本占比)self.mu = None  # 各群体身高均值(单位:厘米)self.sigma = None  # 各群体身高标准差self.converged = False  # 是否收敛标志self.iterations = 0  # 实际迭代次数def _validate_input(self, data):"""输入验证 - 确保数据适合学生身高分析验证条件:1. 输入必须是1维数组(每个元素代表一个学生的身高)2. 样本量必须大于群体数量(防止无法区分群体)"""if not isinstance(data, np.ndarray) or data.ndim != 1:raise ValueError("输入应为1维数组,表示学生身高测量值")if len(data) < self.n_components:raise ValueError("样本量需大于群体数量才能进行有效分析")def _initialize_parameters(self, data):"""参数初始化 - 使用K-means进行初步群体划分初始化策略:1. 通过K-means将学生按身高初步分为n_components个群体2. 按群体身高均值升序排列(确保小学生群体在前)3. 初始化参数:- π: 各群体样本占比- μ: 各群体身高均值- σ: 各群体身高标准差(至少1cm防止数值问题)"""np.random.seed(self.random_state)kmeans = KMeans(n_clusters=self.n_components,random_state=self.random_state)labels = kmeans.fit_predict(data.reshape(-1, 1))# 按身高均值升序排列群体(保证小学生群体在前)unique_labels = np.unique(labels)means = np.array([data[labels == lbl].mean() for lbl in unique_labels])order = np.argsort(means)# 初始化参数self.pi = np.array([np.mean(labels == lbl) for lbl in unique_labels[order]])self.mu = np.array([data[labels == lbl].mean() for lbl in unique_labels[order]])self.sigma = np.array([data[labels == lbl].std() if np.sum(labels == lbl) > 1 else 1.0for lbl in unique_labels[order]])def _e_step(self, data):"""期望步(E-step)- 计算学生归属各群体的后验概率计算公式:P(群体k|身高) = π_k * N(身高|μ_k, σ_k²) / Σ(π_j * N(身高|μ_j, σ_j²))返回:responsibilities : array, shape (n_samples, n_components)每个学生属于各群体的概率矩阵"""# 计算各群体的概率密度pdf = norm.pdf(data[:, np.newaxis], self.mu, self.sigma)# 计算责任矩阵(未归一化的后验概率)responsibilities = self.pi * pdf# 归一化使各学生概率和为1responsibilities /= responsibilities.sum(axis=1, keepdims=True)return responsibilitiesdef _m_step(self, data, responsibilities):"""最大化步(M-step)- 更新群体参数更新公式:1. π_k = 群体k的责任值总和 / 总样本数2. μ_k = Σ(责任值_ki * 身高_i) / 群体k的责任值总和3. σ_k = sqrt(Σ(责任值_ki * (身高_i - μ_k)^2) / 群体k的责任值总和)"""# 各群体有效样本数N_k = responsibilities.sum(axis=0)# 更新群体比例self.pi = N_k / len(data)# 更新群体均值self.mu = np.dot(responsibilities.T, data) / N_k# 更新群体标准差diff_sq = (data[:, np.newaxis] - self.mu) ** 2self.sigma = np.sqrt(np.sum(responsibilities * diff_sq, axis=0) / N_k)def _has_converged(self, prev_params):"""收敛判断 - 检查参数是否稳定判断标准:新旧参数(π, μ, σ)的变化是否均小于tol阈值"""return all(np.allclose(new, old, atol=self.tol) for new, old inzip([self.pi, self.mu, self.sigma], prev_params))def fit(self, data):"""训练模型 - EM算法主循环执行流程:1. 输入验证2. 参数初始化3. 迭代执行E步和M步4. 检查收敛或达到最大迭代次数5. 最终按身高均值排序群体"""self._validate_input(data)self._initialize_parameters(data)self.converged = Falsefor self.iterations in range(1, self.max_iter + 1):prev_params = [arr.copy() for arr in [self.pi, self.mu, self.sigma]]# E步:计算后验概率responsibilities = self._e_step(data)# M步:更新参数self._m_step(data, responsibilities)# 检查收敛if self._has_converged(prev_params):self.converged = Truebreak# 最终按身高均值排序群体(保证小学生群体在前)order = np.argsort(self.mu)self.mu = self.mu[order]self.pi = self.pi[order]self.sigma = self.sigma[order]return selfdef predict_proba(self, data):"""预测概率 - 返回每个学生属于各群体的概率返回:array, shape (n_samples, n_components)每个元素表示对应学生属于该群体的概率"""return self._e_step(data)def predict(self, data):"""预测类别 - 返回最可能的群体标签返回:array, shape (n_samples,)每个元素为0(小学生)或1(中学生)"""return np.argmax(self.predict_proba(data), axis=1)def get_params(self):"""获取训练后的模型参数返回:dict 包含:- pi : 各群体比例- mu : 各群体平均身高(cm)- sigma : 各群体身高标准差(cm)- converged : 是否收敛- iterations : 实际迭代次数"""return {'pi': self.pi,'mu': self.mu,'sigma': self.sigma,'converged': self.converged,'iterations': self.iterations}class GMM_Visualizer:"""GMM可视化工具类"""def __init__(self, model, data, true_labels=None):self.model = modelself.data = dataself.true_labels = true_labelsself.colors = sns.color_palette("husl", model.n_components)self.group_labels = ['Primary school student', 'Middle school student'] \if model.n_components == 2 else [f'Group {i+1}' for i in range(model.n_components)]def plot_results(self, save_path=None):"""可视化拟合结果"""plt.figure(figsize=(12, 7))x = np.linspace(self.data.min()-15, self.data.max()+15, 1000)# 绘制直方图sns.histplot(self.data, bins=30, kde=False, stat='density',color='gray', alpha=0.3, label='Original Data')# 绘制各成分和混合分布mixture_pdf = np.zeros_like(x)for k in range(self.model.n_components):component_pdf = self.model.pi[k] * norm.pdf(x, self.model.mu[k], self.model.sigma[k])plt.plot(x, component_pdf, color=self.colors[k], lw=2,label=f'{self.group_labels[k]} (π={self.model.pi[k]:.2f}, μ={self.model.mu[k]:.1f}, σ={self.model.sigma[k]:.1f})')mixture_pdf += component_pdf# 绘制混合分布plt.plot(x, mixture_pdf, 'k--', lw=2.5, label='Mixture Distribution')# 绘制真实分布(如果存在)if self.true_labels is not None:for k in range(self.model.n_components):sns.histplot(self.data[self.true_labels == k], bins=15, kde=False, stat='density',color=self.colors[k], alpha=0.3, label=f'True {self.group_labels[k]}')plt.title('GMM Fitting Results', fontsize=14)plt.xlabel('Height (cm)')plt.ylabel('Probability Density')plt.legend(bbox_to_anchor=(1.05, 1), loc='upper left', frameon=True)plt.grid(alpha=0.2)if save_path:plt.savefig(save_path, dpi=300, bbox_inches='tight')print(f"图像已保存到: {save_path}")else:plt.show()plt.close()def generate_data(n_primary=100, n_secondary=100,primary_mean=160, primary_std=5,secondary_mean=175, secondary_std=7,random_state=42):"""生成模拟学生身高数据案例背景:生成包含两个学生群体的身高数据集,模拟实际观测数据:- 小学生群体:身高服从正态分布N(μ1, σ1²)- 中学生群体:身高服从正态分布N(μ2, σ2²)参数:n_primary : int, default=100小学生样本数量(默认100人)n_secondary : int, default=100中学生样本数量(默认100人)primary_mean : float, default=160小学生群体平均身高(厘米)primary_std : float, default=5小学生群体身高标准差(厘米)secondary_mean : float, default=175中学生群体平均身高(厘米)secondary_std : float, default=7中学生群体身高标准差(厘米)random_state : int, default=42随机种子,保证数据生成可重复返回:data : ndarray, shape (n_samples,)打乱后的混合身高数据(单位:厘米)labels : ndarray, shape (n_samples,)对应的学生群体标签(0:小学生, 1:中学生)"""# 设置随机种子保证结果可重复np.random.seed(random_state)# 生成小学生身高数据(正态分布)primary = np.random.normal(primary_mean, primary_std, n_primary)# 生成中学生身高数据(正态分布)secondary = np.random.normal(secondary_mean, secondary_std, n_secondary)# 合并数据并创建标签data = np.concatenate([primary, secondary])labels = np.concatenate([np.zeros(n_primary), np.ones(n_secondary)])# 打乱数据以模拟真实观测场景# 保持数据与标签的对应关系idx = np.random.permutation(len(data))return data[idx], labels[idx].astype(int)def print_results(model, data, true_labels=None):"""打印结果对比"""params = model.get_params()pi, mu, sigma = params['pi'], params['mu'], params['sigma']print("\n" + "=" * 60)print("GMM-EM 模型预测结果")print("=" * 60)for k in range(len(pi)):print(f"Group {k+1}: 比例={pi[k]:.4f}, 均值={mu[k]:.2f}cm, 方差={sigma[k]:.2f}cm")if true_labels is not None:print("\n真实参数:")for k in range(len(pi)):mask = true_labels == kprint(f"Group {k+1}: 比例={np.mean(mask):.4f}, "f"均值={data[mask].mean():.2f}cm, 方差={data[mask].std():.2f}cm")accuracy = np.mean(model.predict(data) == true_labels)print(f"\n分类准确率: {accuracy:.2%}")print(f"是否收敛: {params['converged']}, 迭代次数: {params['iterations']}")print("=" * 60)if __name__ == "__main__":# 生成数据data, labels = generate_data()# 训练模型model = GMM_EM(n_components=2)model.fit(data)# 打印结果print_results(model, data, labels)# 可视化visualizer = GMM_Visualizer(model, data, labels)visualizer.plot_results(save_path="./fitted_distribution.png")

📌 第五步:总结重点

概念含义
隐变量不知道但是存在的变量(比如样本的真实类别)
E步计算每个数据点属于哪个分布的“概率”
M步根据这个概率重新计算每个分布的参数
收敛参数变化很小,不再更新,算法停止
应用场景高斯混合聚类、缺失数据估计、协同过滤、HMM 等等

版权声明:

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

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

热搜词