查看全课大纲(第 30 / 69 节)
  1. 1.NLP 的研究领域、应用与学习路径
  2. 2.自然语言的基本术语
  3. 3.信息论基础:信息熵与交叉熵
  4. 4.语言的进化与语义变迁
  5. 5.主观概率、客观概率与条件概率
  6. 6.贝叶斯原理与推理
  7. 7.随机变量:二项式、期望方差与联合概率
  8. 8.常见概率分布
  9. 9.辛普森悖论与贝叶斯解题实例
  10. 10.语言模型:语言概率与词袋模型
  11. 11.n-gram 语言模型(二元 / 三元 / N-Gram)
  12. 12.语言模型评价:交叉熵、困惑度与插值
  13. 13.朴素贝叶斯文本分类:垃圾邮件
  14. 14.拼写检查
  15. 15.中文分词:构词法、最大匹配、最优路径与 Jieba
  16. 16.词表示问题与语义相似度
  17. 17.TF-IDF 权重处理
  18. 18.One-Hot 表达与词表示的局限
  19. 19.Word2Vec 核心思想
  20. 20.Word2Vec 训练过程
  21. 21.Skip-gram 模型详解
  22. 22.词性标注任务与标注方法(规则 + N-Gram)
  23. 23.EM 算法与混合模型
  24. 24.高斯混合模型 GMM
  25. 25.从混合模型到隐马尔可夫模型
  26. 26.隐马尔可夫模型(HMM)推导与维特比解码
  27. 27.线性链条件随机场 CRF
  28. 28.贝叶斯网络与图模型
  29. 29.隐马尔可夫链与 HMM 推导
  30. 30.PLSA 主题模型
  31. 31.LSI 与 SVD 向量表达
  32. 32.LDA 与狄利克雷分布
  33. 33.主题模型实验复现(困惑度 / 分类 / 相似度 / 延展)
  34. 34.上下文无关文法(CFG)与句法分析
  35. 35.概率上下文无关文法 PCFG
  36. 36.统计机器翻译:词对齐与翻译模型
  37. 37.统计机器翻译中的对齐模型与参数估计
  38. 38.从统计机器翻译到神经机器翻译
  39. 39.神经元与反向传播速览(指向深度学习课)
  40. 40.CNN 原理及其在 NLP 中的应用
  41. 41.循环神经网络的基本原理与 Elman / Jordan 网络
  42. 42.LSTM:长短期记忆网络的核心思想与分步实现
  43. 43.Encoder-Decoder 框架
  44. 44.Seq2Seq 与早期注意力机制
  45. 45.注意力机制的背景与动机
  46. 46.注意力模型实现原理与匹配函数
  47. 47.记忆网络:组成与计算
  48. 48.注意力机制的应用与历史延展
  49. 49.Transformer 结构:Encoder-Decoder 栈与 Self-Attention
  50. 50.Multi-Head Attention、FFNN 与位置编码
  51. 51.层归一化、损失函数与 Universal Transformer 延展
  52. 52.预训练范式:从 ELMo 到 BERT
  53. 53.BERT 与掩码语言模型
  54. 54.BERT 下游任务微调与 GLUE 口径
  55. 55.GPT 与自回归语言建模
  56. 56.GPT-1 到 GPT-4 的演进
  57. 57.指令微调与 RLHF
  58. 58.分词器:BPE、WordPiece 与中文词表
  59. 59.上下文窗口与长文本处理
  60. 60.能力边界、成本与适用场景
  61. 61.文本分类实战:从朴素贝叶斯到逻辑回归
  62. 62.命名实体识别实战
  63. 63.文本生成与摘要实战
  64. 64.语义检索与向量库实战
  65. 65.RAG 知识库问答
  66. 66.NLP 评估指标:BLEU / ROUGE / BERTScore 与人工评估
  67. 67.幻觉与事实性问题
  68. 68.文本与知识结合(知识图谱压缩)
  69. 69.跨媒体信息检索与未来展望

PLSA 主题模型

小象实战讲义 · 自然语言处理

在掌握了隐马尔可夫模型(HMM)和期望最大化(EM)算法等概率图模型基础后,我们正式进入主题模型(Topic Model)的世界。主题模型旨在从大量文本中自动发现其隐含的“主题”结构,是文本挖掘、信息检索和自然语言理解的核心技术之一。本节将首先回顾经典的潜在语义分析(LSA),然后深入其概率化版本——概率潜在语义分析(PLSA),理解其如何将矩阵分解转化为概率生成模型,为后续学习更强大的主题模型(如 LDA)奠定坚实基础。

💡 核心导读

  • 从矩阵到概率:理解如何将文档-词矩阵的奇异值分解(SVD)转化为概率模型,引入“主题”作为隐含变量。
  • PLSA 的生成过程:掌握 PLSA 的核心假设——文档由多个主题混合而成,而每个主题是词的概率分布。
  • 模型表示与似然:学习 PLSA 的图模型表示(盘式记法)及其联合概率与似然函数的数学形式。
  • 与 LSA 的关联:明确 PLSA 作为 LSA 的概率化扩展,其优势在于提供了清晰的概率解释。
  • 通向现代模型:认识 PLSA 作为经典主题模型的承上启下作用,了解其局限性及后续发展。

从潜在语义分析(LSA)到概率模型

在深入 PLSA 之前,我们必须回顾其前身——潜在语义分析(Latent Semantic Analysis, LSA),有时也称为潜在语义索引(LSI)。其核心思想源于线性代数中的矩阵分解。

文档-词矩阵与 SVD

我们处理文本集合时,首先构建一个 文档-词矩阵(Term-Document Matrix)。假设我们有 M 篇文档和 N 个不同的词(词汇表大小)。这个矩阵 X 的维度是 N x M,其中元素 X[i, j] 表示词 i 在文档 j 中出现的次数(或经过 TF-IDF 加权的值)。

# 示例:一个极小的文档-词矩阵 (N=4个词, M=3篇文档)
import numpy as np

# 词汇表: ['计算机', '算法', '圣经', '祈祷']
# 文档: D1 (科技), D2 (科技), D3 (宗教)
term_doc_matrix = np.array([
    [5, 4, 0],  # '计算机'
    [3, 6, 1],  # '算法' (在D3中出现1次,可能是个例或歧义)
    [0, 0, 7],  # '圣经'
    [0, 0, 5],  # '祈祷'
], dtype=float)

print("文档-词矩阵 (词 x 文档):")
print(term_doc_matrix)
print(f"矩阵形状: {term_doc_matrix.shape} (N={term_doc_matrix.shape[0]}, M={term_doc_matrix.shape[1]})")
文档-词矩阵 (词 x 文档):
[[5. 4. 0.]
 [3. 6. 1.]
 [0. 0. 7.]
 [0. 0. 5.]]
矩阵形状: (4, 3) (N=4, M=3)

LSA 的核心是对这个矩阵 X 进行 奇异值分解(Singular Value Decomposition, SVD): X≈UkΣkVkTX \approx U_k \Sigma_k V_k^T 其中:

  • UkU_k 是 N x K 矩阵,每一列可以理解为与“词”相关的潜在语义维度(左奇异向量)。
  • Σk\Sigma_k 是 K x K 对角矩阵,对角线上的奇异值表示对应潜在维度的重要性。
  • VkTV_k^T 是 K x M 矩阵,每一行可以理解为与“文档”相关的潜在语义维度(右奇异向量的转置)。
  • KK 是选取的潜在维度数(主题数),通常 K≪min⁡(N,M)K \ll \min(N, M)。

# —— 重新构建上文用到的微型数据(本节各代码块相互独立,可单独运行)
import numpy as np
term_doc_matrix = np.array([
    [5, 4, 0],  # '计算机'
    [3, 6, 1],  # '算法' (在D3中出现1次,可能是个例或歧义)
    [0, 0, 7],  # '圣经'
    [0, 0, 5],  # '祈祷'
], dtype=float)

# 对上述矩阵进行 SVD 分解(仅作演示,实际中K=min(N,M))
U, S, Vt = np.linalg.svd(term_doc_matrix, full_matrices=False)
K = S.shape[0]
print(f"\nSVD 分解结果:")
print(f"U 形状: {U.shape}")
print(f"S (奇异值): {S}")
print(f"Vt 形状: {Vt.shape}")
print(f"潜在维度 K = {K}")

# 假设我们只保留前2个最重要的维度 (K' = 2)
K_prime = 2
U_reduced = U[:, :K_prime]
S_reduced = np.diag(S[:K_prime])
Vt_reduced = Vt[:K_prime, :]

print(f"\n保留前{K_prime}个主题后的压缩表示:")
print(f"U_k' 形状: {U_reduced.shape}")
print(f"S_k' 形状: {S_reduced.shape}")
print(f"Vt_k' 形状: {Vt_reduced.shape}")

# 重建近似矩阵
X_approx = U_reduced @ S_reduced @ Vt_reduced
print(f"\n原始矩阵 X:\n{term_doc_matrix}")
print(f"\n近似重建矩阵 X_approx:\n{X_approx}")

SVD 分解结果:
U 形状: (4, 3)
S (奇异值): [9.2728253  8.43163808 1.98045204]
Vt 形状: (3, 3)
潜在维度 K = 3

保留前2个主题后的压缩表示:
U_k' 形状: (4, 2)
S_k' 形状: (2, 2)
Vt_k' 形状: (2, 3)

原始矩阵 X:
[[5. 4. 0.]
 [3. 6. 1.]
 [0. 0. 7.]
 [0. 0. 5.]]

近似重建矩阵 X_approx:
[[ 3.87984945  4.88881384 -0.02775031]
 [ 4.06494177  5.15499306  1.02638258]
 [-0.10637593  0.08440687  6.99736467]
 [-0.07598281  0.06029062  4.99811762]]

通过 SVD,我们将高维(N 维)的文档向量(矩阵的列)映射到了低维(K' 维)的潜在语义空间(由 VkTV_k^T 的行表示)。在这个空间中,语义相似的文档(如 D1 和 D2)距离会更近,语义不同的文档(如 D1 和 D3)距离会更远。这解决了 词项匹配中的同义词和多义词问题,因为潜在维度捕获了词与词、文档与文档之间更深层的关联。

然而,LSA/SVD 是纯粹的线性代数方法,缺乏概率解释。我们无法将奇异向量直接解释为“文档属于某个主题的概率”或“主题下词的概率分布”。

概率潜在语义分析(PLSA)

为了给潜在语义分析提供一个稳固的概率基础,Hofmann 于 1999 年提出了 概率潜在语义分析(Probabilistic Latent Semantic Analysis, PLSA)。

基本思想与生成过程

PLSA 的核心是引入一个隐含的随机变量 zz,表示 主题(Topic)。它假设每篇文档 dd 是多个主题的混合,而每个主题 zz 则是一个在词汇表上的多项分布,即定义了每个词 ww 出现的概率。

PLSA 的生成过程可以想象如下:

  1. 以概率 P(d)P(d) 选择一篇文档 dd。
  2. 对于文档 dd 中的每一个词的位置: a. 根据条件分布 P(z∣d)P(z|d) 选择一个主题 zz。 b. 在给定主题 zz 的条件下,根据分布 P(w∣z)P(w|z) 生成一个词 ww。

这一过程隐含一条条件独立假设:在给定主题 zz 后,词 ww 与文档 dd 条件独立,即 w⊥d∣zw \perp d \mid z,等价于 P(w∣d,z)=P(w∣z)P(w \mid d, z) = P(w \mid z)。正是这条假设把 P(w∣d,z)P(w \mid d, z) 约简为 P(w∣z)P(w \mid z),后面的边缘化求和似然才成立;它是建模假设,不是概率恒等式。

这个过程可以用下面的概率图模型(盘式记法)表示:

        |‾‾‾‾‾|
        |  d  |   (文档,观察变量,M篇文档)
        |_____|
          |
          | P(z|d)
          v
        |‾‾‾‾‾|
        |  z  |   (主题,隐含变量,K个主题)
        |_____|
          |
          | P(w|z)
          v
        |‾‾‾‾‾|
        |  w  |   (词,观察变量,N个词)
        |_____|

        重复 N_d 次 (文档d的长度)

图:PLSA 的图模型表示。方板(plate)表示重复。d 和 w 是观察到的,z 是隐含的。

联合概率与似然函数

根据上述生成过程,观察到一个词 ww 出现在一篇特定文档 dd 中的联合概率为: P(d,w)=P(d)P(w∣d)P(d, w) = P(d) P(w|d) 在 PLSA 中,P(w∣d)P(w|d) 不是直接统计得到的,而是通过主题 zz “解释”的: P(w∣d)=∑z∈ZP(w∣z)P(z∣d)P(w|d) = \sum_{z \in Z} P(w|z) P(z|d) 因此,联合概率可以写为: P(d,w)=P(d)∑z∈ZP(w∣z)P(z∣d)P(d, w) = P(d) \sum_{z \in Z} P(w|z) P(z|d) 其中:

  • P(d)P(d) 是选择文档 dd 的先验概率。
  • P(z∣d)P(z|d) 是文档 dd 属于主题 zz 的概率(文档-主题分布)。
  • P(w∣z)P(w|z) 是主题 zz 下生成词 ww 的概率(主题-词分布)。

给定整个语料库,我们观察到的数据是 文档-词共现频率 n(d,w)n(d, w),即词 ww 在文档 dd 中出现的次数。PLSA 的模型参数是 θ=P(d),P(z∣d),P(w∣z)\theta = { P(d), P(z|d), P(w|z) }。数据的对数似然函数为: L=log⁡P(Corpus)=∑d∈D∑w∈Wn(d,w)log⁡P(d,w)\mathcal{L} = \log P(\text{Corpus}) = \sum_{d \in D} \sum_{w \in W} n(d, w) \log P(d, w) 代入 P(d,w)P(d, w) 得: L=∑d∈D∑w∈Wn(d,w)log⁡[P(d)∑z∈ZP(w∣z)P(z∣d)]\mathcal{L} = \sum_{d \in D} \sum_{w \in W} n(d, w) \log \left[ P(d) \sum_{z \in Z} P(w|z) P(z|d) \right] 我们的目标是找到参数 θ\theta 以最大化这个对数似然 L\mathcal{L}。

与 LSA 的对比

PLSA 为 LSA 提供了一个明确的概率生成框架:

  • LSA:通过 SVD 进行确定性矩阵分解。潜在维度(奇异向量)有正有负,难以直接解释为概率。
  • PLSA:通过引入隐含主题变量 zz,将文档和词的联系建模为概率混合模型。所有参数 P(z∣d)P(z|d) 和 P(w∣z)P(w|z) 都是非负的概率值,具有清晰的解释性。

从模型能力上看,PLSA 可以看作是 LSA 的一种概率化扩展。两者都试图找到文档和词在低维潜在空间中的表示,但 PLSA 的统计基础更牢固,为使用 EM 算法进行参数估计铺平了道路。

LSA (SVD) 视角:
文档d -> 在潜在空间中的向量表示 (Vt中的列) -> 用于计算相似度。

PLSA 视角:
文档d -> 主题分布 P(z|d) (一个K维概率向量) -> 每个主题z -> 词分布 P(w|z)。
文档相似度可以通过比较它们的主题分布 (P(z|d)) 来计算,例如使用 KL 散度或余弦相似度。

PLSA 的参数估计与 EM 算法

最大化 PLSA 的对数似然函数没有解析解,因为求和对数内部包含了隐含变量 zz 的求和。这正是 期望最大化(EM)算法 的用武之地。

E步(期望步):在给定当前参数估计 θold\theta^{old} 下,计算隐含主题 zz 的后验概率: P(z∣d,w)=Pold(w∣z)Pold(z∣d)∑z′Pold(w∣z′)Pold(z′∣d)P(z|d, w) = \frac{P^{old}(w|z) P^{old}(z|d)}{\sum_{z'} P^{old}(w|z') P^{old}(z'|d)} 这个后验概率表示,对于观察到的 (d,w)(d, w) 这对共现,其由主题 zz 生成的责任(responsibility)有多大。

M步(最大化步):利用 E 步计算出的后验概率作为权重,更新模型参数以最大化完整数据的期望似然。

  • 更新主题-词分布: Pnew(w∣z)=∑dn(d,w)P(z∣d,w)∑d,w′n(d,w′)P(z∣d,w′)P^{new}(w|z) = \frac{\sum_{d} n(d, w) P(z|d, w)}{\sum_{d, w'} n(d, w') P(z|d, w')}
  • 更新文档-主题分布: Pnew(z∣d)=∑wn(d,w)P(z∣d,w)n(d)P^{new}(z|d) = \frac{\sum_{w} n(d, w) P(z|d, w)}{n(d)} 其中 n(d)=∑wn(d,w)n(d) = \sum_{w} n(d, w) 是文档 dd 的总词数。
  • 文档先验 P(d)P(d) 通常简单地用文档的相对频率估计:P(d)=n(d)/∑d′n(d′)P(d) = n(d) / \sum_{d'} n(d')。

重复执行 E 步和 M 步直到对数似然收敛,即可得到 PLSA 的模型参数。

# 注意:以下为 PLSA EM 算法的伪代码示意,用于说明流程。
# 实际应用中,可借助 numpy 等做向量化自行实现 PLSA 的 EM;若使用第三方主题模型库,需确认其明确提供 PLSA/PLSI,而不是 LSI 或 LDA。

print("PLSA EM 算法伪代码流程:")
print("1. 初始化参数:")
print("   - 随机初始化 P(z|d) 和 P(w|z),并确保每行和为1 (概率分布)。")
print("2. 迭代直至收敛:")
print("   【E步】对每个 (d, w) 对,计算后验 P(z|d, w):")
print("        P(z|d,w) = P_old(w|z) * P_old(z|d) / sum_over_z( P_old(w|z') * P_old(z'|d) )")
print("   【M步】用后验更新参数:")
print("        P_new(w|z) = sum_over_d[ n(d,w) * P(z|d,w) ] / sum_over_d,w'[ n(d,w') * P(z|d,w') ]")
print("        P_new(z|d) = sum_over_w[ n(d,w) * P(z|d,w) ] / n(d) (文档总词数)")
print("3. 输出: 文档-主题分布 P(z|d) 和 主题-词分布 P(w|z)。")
PLSA EM 算法伪代码流程:
1. 初始化参数:
   - 随机初始化 P(z|d) 和 P(w|z),并确保每行和为1 (概率分布)。
2. 迭代直至收敛:
   【E步】对每个 (d, w) 对,计算后验 P(z|d, w):
        P(z|d,w) = P_old(w|z) * P_old(z|d) / sum_over_z( P_old(w|z') * P_old(z'|d) )
   【M步】用后验更新参数:
        P_new(w|z) = sum_over_d[ n(d,w) * P(z|d,w) ] / sum_over_d,w'[ n(d,w') * P(z|d,w') ]
        P_new(z|d) = sum_over_w[ n(d,w) * P(z|d,w) ] / n(d) (文档总词数)
3. 输出: 文档-主题分布 P(z|d) 和 主题-词分布 P(w|z)。

📝 动手练一练

  1. 概念辨析:LSA 和 PLSA 都旨在发现文本的潜在语义结构。请简述它们最根本的区别是什么?PLSA 引入的概率框架带来了哪些优势?
👉 点击查看参考答案

根本区别: LSA 基于线性代数(SVD),是一种确定性的矩阵分解方法。PLSA 则基于统计学,是一种概率生成模型,引入了“主题”作为隐含随机变量。

PLSA 的优势:

  1. 概率解释:所有输出(文档-主题分布 P(z∣d)P(z|d)、主题-词分布 P(w∣z)P(w|z))都是严格的概率值,意义清晰。例如,P(z1∣d)=0.7P(z_1|d)=0.7 可以直接解释为文档 dd 有 70% 的内容关于主题 z1z_1。
  2. 统计基础:基于似然最大化,可以自然地融入统计推断框架,并使用 EM 算法进行稳健的参数估计。
  3. 模型灵活性:为后续更复杂的概率主题模型(如 LDA)提供了直接的建模基础。LDA 可以看作是 PLSA 的贝叶斯版本,通过引入先验分布解决了 PLSA 的一些固有问题(如过拟合)。
  1. 手算理解:假设一个极简语料库只有 1 篇文档 d1d_1,词汇表只有 2 个词 w1,w2{w_1, w_2},且我们设定主题数 K=2K=2。观察到词频为 n(d1,w1)=3n(d_1, w_1)=3, n(d1,w2)=1n(d_1, w_2)=1。在 PLSA 的某次 EM 迭代中,当前参数为: P(z1∣d1)=0.6,P(z2∣d1)=0.4P(z_1|d_1)=0.6, P(z_2|d_1)=0.4 P(w1∣z1)=0.9,P(w2∣z1)=0.1P(w_1|z_1)=0.9, P(w_2|z_1)=0.1 P(w1∣z2)=0.2,P(w2∣z2)=0.8P(w_1|z_2)=0.2, P(w_2|z_2)=0.8 请计算对于共现 (d1,w1)(d_1, w_1),主题 z1z_1 和 z2z_2 的后验概率 P(z∣d1,w1)P(z|d_1, w_1)。
👉 点击查看参考答案

根据 E 步公式: P(z∣d,w)=P(w∣z)P(z∣d)∑z′P(w∣z′)P(z′∣d)P(z|d, w) = \frac{P(w|z) P(z|d)}{\sum_{z'} P(w|z') P(z'|d)}

对于 (d1,w1)(d_1, w_1):

  • 分母 = P(w1∣z1)P(z1∣d1)+P(w1∣z2)P(z2∣d1)=0.9∗0.6+0.2∗0.4=0.54+0.08=0.62P(w_1|z_1)P(z_1|d_1) + P(w_1|z_2)P(z_2|d_1) = 0.9*0.6 + 0.2*0.4 = 0.54 + 0.08 = 0.62
  • P(z1∣d1,w1)=(0.9∗0.6)/0.62=0.54/0.62≈0.871P(z_1|d_1, w_1) = (0.9*0.6) / 0.62 = 0.54 / 0.62 \approx 0.871
  • P(z2∣d1,w1)=(0.2∗0.4)/0.62=0.08/0.62≈0.129P(z_2|d_1, w_1) = (0.2*0.4) / 0.62 = 0.08 / 0.62 \approx 0.129

计算结果显示,对于词 w1w_1,模型认为它更可能(约 87.1% 的责任)是由主题 z1z_1 生成的,这与参数设定一致(P(w1∣z1)P(w_1|z_1) 远高于 P(w1∣z2)P(w_1|z_2))。

本章小结

本节我们深入探讨了概率潜在语义分析(PLSA)模型。我们从其前身 LSA 出发,理解了通过 SVD 对文档-词矩阵进行降维以捕获潜在语义的思想。PLSA 的关键创新在于为这一过程赋予了概率解释,引入了“主题”作为连接文档和词的隐含变量,并定义了一个清晰的生成过程:文档生成主题,主题再生成词。

我们学习了 PLSA 的图模型表示、联合概率与似然函数形式,并了解了其参数如何通过 EM 算法进行估计。与 LSA 相比,PLSA 的优势在于其所有参数都具有概率意义,为文本分析提供了更丰富的解释性工具,例如得到文档的主题构成 P(z∣d)P(z|d) 和每个主题下的关键词分布 P(w∣z)P(w|z)。

PLSA 是主题模型发展史上的重要里程碑,但它也存在局限性,最主要的是其参数 P(z∣d)P(z|d) 与训练文档直接绑定,导致模型参数数量随文档数量线性增长,容易过拟合,并且难以处理训练集之外的新文档。这直接催生了其贝叶斯扩展——潜在狄利克雷分配(LDA),我们将在下一节中学习。

📋 行动清单

  • 在本地尝试用 numpy 实现一个简化版的 PLSA EM 算法(例如,固定迭代次数),在小规模人造数据上运行,观察 P(z∣d)P(z|d) 和 P(w∣z)P(w|z) 的收敛情况。
  • 思考:如果一篇文档明显只讨论一个主题(如“圣经”),PLSA 学出的 P(z∣d)P(z|d) 应该呈现什么特点?如果一篇文档混合了“科技”和“体育”主题,其 P(z∣d)P(z|d) 又会如何?
  • 预习 LDA,对比其图模型与 PLSA 的差异,理解“狄利克雷先验”在模型中扮演的角色。

—— 小象教研组