从词袋到话题
文本分析的第一步通常是把文档变成向量。最朴素的做法是词袋模型(Bag of Words):建一张词表,大小为 ;有 篇文档;构造一个 的词-文档矩阵 ,其中 表示第 个词在第 篇文档中出现的频次(或 TF-IDF 权重)。
这个矩阵有两个致命问题:
- 极度稀疏。词表通常几万甚至几十万,但一篇文档只用几百个词。 里绝大多数元素是零。
- 语义缺失。"汽车"和"轿车"是不同的行,在 里完全正交——但它们语义几乎相同。反过来,"苹果"一个词对应水果和公司两种含义,在 里却只有一行。
问题的根源在于:词袋模型工作在单词向量空间( 维),维度太高,每个维度只对应一个具体的词,没有抽象出「话题」这个概念。
我们需要一种降维方法:把 维的单词空间压到 维的话题向量空间(),使得语义相近的词被映射到相近的方向。这恰好是矩阵分解擅长的事情。
如果你已经读过 SVD 篇,你知道截断 SVD 是最优低秩近似。如果你读过 PCA 篇,你知道降维的关键是保留方差最大的方向。LSA 和 NMF 就是把这些工具用到词-文档矩阵上。
潜在语义分析 (LSA)
潜在语义分析(Latent Semantic Analysis,也叫 LSI——Latent Semantic Indexing)的核心思路极其简单:对词-文档矩阵 做截断 SVD,用低秩近似来发现隐藏的话题结构。
截断 SVD 回顾
SVD 篇详细介绍了:任意 矩阵 都可以精确分解为
其中 正交, 是奇异值对角矩阵(), 正交。
截断 SVD 只保留前 个最大的奇异值:
其中 ,,。根据 Eckart-Young 定理,这是 Frobenius 范数下最优的秩- 近似。
LSA 的语义解读
把截断 SVD 的三个矩阵放到文本语境下:
- ():每一行是一个词的 维话题表示。语义相近的词(如"机器"和"算法")在这个空间里方向接近。
- ():每一行是一个文档的 维话题表示。内容相似的文档被映射到相近的位置。
- ():对角线上的奇异值表示每个话题的「强度」。 最大,对应最主要的话题维度。
几何意义很清楚:原来 维的单词空间里,每个词是一个极度稀疏的 one-hot 向量;经过 LSA 之后,每个词变成了一个稠密的 维向量,坐标的含义是「这个词在各个话题上的参与度」。
LSA 的计算流程
- 构造词-文档矩阵 (通常用 TF-IDF 加权而非原始频次)
- 对 做截断 SVD,取前 个奇异值( 通常取 100~300)
- 用 的行向量作为词的表示,用 的行向量作为文档的表示
- 在低维空间里用余弦相似度做检索、分类、聚类
LSA 的局限
- 分解结果可以是负数。 和 的元素可正可负。说一个词在某个话题上的参与度是 ——负的参与度很难解释。
- 话题不可叠加解读。一篇文档不能被理解为"30% 话题A + 70% 话题B",因为有负值搅局。
- 不能处理多义词。每个词只有一个向量,无法区分"苹果(水果)"和"苹果(公司)"。
第一个问题催生了 NMF;第三个问题后来被 Word2Vec 和 BERT 解决。
非负矩阵分解 (NMF)
非负矩阵分解(Non-negative Matrix Factorization,NMF)只加了一条看似简单的约束——所有元素都不能是负数——但这一条约束带来了质的变化。
基本形式
给定非负矩阵 ,NMF 寻找两个非负矩阵 ,,使得:
其中 是话题数,通常 。
和 SVD 的关键区别: 和 的所有元素都 。
非负约束的意义
这条约束为什么重要?因为它让分解结果有了直觉上的「可加性」解读:
每个文档是几个话题的加法叠加(没有减法)。 是第 个词对第 个话题的贡献强度(非负 = "有多大关系"), 是第 个话题在第 篇文档中的激活程度(非负 = "有多强")。
这就像调鸡尾酒:每杯酒是几种基酒的正比例混合,不存在"减去50ml伏特加"这种操作。你可以直接说:这篇文档 = 40% 体育话题 + 60% 科技话题。LSA 做不到这一点。
直觉总结:
| SVD / LSA | NMF | |
|---|---|---|
| 元素取值 | 可正可负 | 非负 |
| 解读 | 话题方向(可以"反向参与") | 话题强度(纯粹的"有多少") |
| 类比 | 正交坐标系 | 鸡尾酒配方 |
目标函数
NMF 最常见的两种损失函数:
平方损失(Frobenius 范数):
KL 散度损失(也叫广义 KL 散度):
两种损失对应不同的噪声模型:平方损失假设高斯噪声,KL 散度假设泊松噪声。实际中平方损失用得更多。
乘法更新规则
NMF 的优化不是凸问题( 和 耦合),没有全局最优的闭式解。Lee & Seung (1999, 2001) 提出了经典的乘法更新规则,简洁优雅:
对于平方损失,更新公式是:
关键性质:
- 自动保非负。只要初始值非负,乘法更新(乘一个非负因子)的结果永远非负。不需要额外做投影或裁剪。
- 单调递减。每一步更新都保证目标函数不增。这个可以严格证明——分子分母的比值恰好对应梯度下降的步长。
- 收敛到局部最优。由于问题非凸,不同的初始化可能得到不同的结果。
和梯度下降的关系:乘法更新其实是一种缩放梯度下降——用当前值除以分母来自适应调整步长,同时保证非负性。这比普通梯度下降 + ReLU 裁剪更稳定。
交互演示
下面的演示展示了两种分解方式的对比。切换 LSA / NMF 模式,调整话题数 ,观察分解矩阵和重建误差的变化。注意 NMF 模式下所有矩阵格子都是暖色调(非负),而 LSA 模式可能出现蓝色(负值)。
LSA vs NMF 对比
把两种方法放在一起看:
| 维度 | LSA(截断 SVD) | NMF |
|---|---|---|
| 数学基础 | 奇异值分解,Eckart-Young 最优性 | 非负矩阵分解,乘法更新 |
| 约束 | 正交性(,) | 非负性(,) |
| 元素取值 | 实数(可正可负) | 非负 |
| 全局最优 | 是(SVD 是闭式解) | 否(非凸,局部最优) |
| 可解释性 | 弱——话题方向难以命名 | 强——话题是词的「正叠加」 |
| 稀疏性 | 不稀疏(, 通常稠密) | 自然稀疏(很多元素接近零) |
| 唯一性 | 唯一(奇异值排序固定) | 不唯一(依赖初始化) |
| 计算效率 | 高效(有成熟的稀疏 SVD 算法) | 需迭代,较慢 |
| 典型用途 | 信息检索、文档相似度 | 话题建模、文本挖掘、推荐系统 |
怎么选?
- 如果你要做检索或降维,关心的是相似度计算的质量,LSA 更合适——它有最优性保证,且计算快。
- 如果你要做话题发现,想看到"话题1 = 机器 + 学习 + 模型"这样可读的结果,NMF 更合适——非负约束让每个话题自然呈现为一组相关词的组合。
- 在实际管线中,两者经常和 TF-IDF 加权配合使用。
sklearn.decomposition.TruncatedSVD和sklearn.decomposition.NMF都只需要几行代码。