1. 问题的源起:词向量空间模型的局限性
文本信息处理的一个核心任务是度量文档之间的语义相似度。最基础且直观的方法是向量空间模型(Vector Space Model, VSM)。
其基本思想十分简洁:给定一个由 个单词组成的词典和 篇文档组成的语料库,我们可以构建一个 的词-文档矩阵 (term-document matrix) 。
在这个矩阵中:
- 每一行代表一个单词 ()。
- 每一列代表一篇文档 ()。
- 矩阵中的元素 代表单词 在文档 中的重要性权重。这个权重最简单的可以是词频,但更常用的是 TF-IDF 值。
这样一来,每篇文档 都可以被表示成一个 维的列向量 。两篇文档的相似度,则可以通过计算它们对应向量的余弦相似度来衡量。
这个模型非常强大,至今仍是许多系统的基石。但它存在两个根本性的语义层面的问题:
-
同义词问题(Synonymy): 比如,“计算机”和“电脑”是同义词。但在VSM中,它们是两个不同的维度,是严格正交的。如果一篇文档用“计算机”,另一篇用“电脑”,即使它们讨论的是同一主题,它们的向量内积在这些维度上的贡献也为零。模型无法捕捉到这种语义上的等价性。
-
多义词问题(Polysemy): 比如,“bank”这个词,可以指“银行”,也可以指“河岸”。VSM会把所有上下文中出现的“bank”都映射到同一个维度上,混淆了其不同的含义,导致语义不精确。
LSA的提出,正是为了从根本上缓解这两个问题。它的核心洞察在于:直接在词汇层面上进行比较是不可靠的,我们应该在一个更抽象的“概念”或“主题”层面上进行比较。
2. LSA与奇异值分解 (SVD)
LSA认为,词-文档矩阵 中存在着大量的“噪声”,而真正有价值的语义结构,隐藏在一个更低维度的空间中。寻找这个空间的工具,就是奇异值分解(Singular Value Decomposition, SVD)。
SVD是线性代数中一种强大的矩阵分解技术,它可以将任意一个 的矩阵 分解为三个矩阵的乘积:
- (): 我们的原始词-文档矩阵。
- (): 这是一个正交矩阵。它的每一列 被称为左奇异向量。在LSA的语境下,我们可以将 理解为一个“词-主题”矩阵。它的每一列都代表一个抽象的、相互正交的“主题”或“概念”,而列向量中的元素则表示每个词汇对这个主题的贡献度。
- (): 这是一个对角矩阵(或块对角矩阵)。其对角线上的元素 被称为奇异值。这些值是非负的,并且通常从大到小排列。每个奇异值 衡量了与之对应的第 个主题的重要性或“能量”。值越大,说明这个主题在整个语料库中的解释力度越强。
- (): 也是一个正交矩阵,它的每一列 被称为右奇异向量。因此 的每一行是 。在LSA中,我们可以将 理解为一个“文档-主题”矩阵。它的每一列(即 的每一行)同样代表了上面由 定义的那些抽象主题,而列向量中的元素则表示每篇文档在这些主题上的分布情况。
所以,SVD的分解 X = UΣV^T 可以被解读为:
“词与文档的关系(),可以被分解为‘词与主题的关系’()、‘各个主题的重要性’()以及‘文档与主题的关系’()这三者的结合。”
3. 使用截断SVD完成从原始空间到语义空间的映射
SVD本身只是一个精确的数学分解。LSA的“魔法”发生在降维这一步,也就是截断奇异值分解 (Truncated SVD)。
我们假设语料库中真正核心的主题只有 个( 远小于 和 )。这意味着,那些较小的奇异值 可能对应的是一些噪声或者过于细节的语义变化。我们可以大胆地将它们丢弃,只保留前 个最大的奇异值,以及它们对应的左、右奇异向量。
这就得到了SVD的近似形式,也即是公式(17.13):
我们来严格定义截断后的矩阵:
- :取 的前 列,尺寸为 。现在,每一行代表一个词,而这一行中的 个元素,就是这个词在 个核心主题上的坐标。这就是词的语义向量。
- :取 的左上角 的对角子矩阵。尺寸为 。它包含了前 个最重要的奇异值。
- :取 的前 行,尺寸为 。现在,每一列代表一篇原始文档,而这一列中的 个元素,就是这篇文档在 个核心主题上的坐标。这就是文档的语义向量。
现在,我们得到了最重要的东西:
- 词的 维语义表示:矩阵 的第 行,就是一个 维向量,它代表了单词 在这个新的语义空间中的表示。
- 文档的 维语义表示:矩阵 的第 列,就是一个 维向量,它代表了文档 在这个新的语义空间中的表示。这正如《机器学习方法》中所述:“将其左奇异矩阵与对角矩阵的乘积作为单词在话题向量空间的表示,将其右奇异矩阵与对角矩阵的乘积作为文本在话题向量空间的表示。”更常见的做法是,直接用 的列向量(或者说 的行向量)作为文档的表示,或者用 的列向量。两者都是有效的,后者考虑了主题的权重。
LSA如何解决VSM的问题?
- 解决同义词问题:在原始语料中,“计算机”和“电脑”可能从未在同一篇文档中出现,但在大量文档中,它们总是和相似的词(如“CPU”、“编程”、“软件”)一起出现。SVD作为一个全局的矩阵分解方法,能够捕捉到这种共现模式。在降维过程中,它倾向于将“计算机”和“电脑”这两个原始维度,映射到 维语义空间中非常相近的位置。因此,它们的语义向量的余弦相似度会很高。
- 解决多义词问题:对于“bank”,如果语料库中同时包含金融和地理两类主题的文档,SVD会生成至少两个与之相关的主题轴。一个可能由“银行”、“存款”、“利率”等词定义,另一个由“河岸”、“水”、“船”等词定义。“bank”这个词的最终语义向量,会是这两个主题向量的某种线性组合,从而在一定程度上消解了单一维度的歧义。
4. 一个简化的数值示例
为了让这个过程更具体,我们构想一个极小的例子。
假设我们的语料库有4篇文档,词典只有6个词:
- : learning about machine learning
- : deep learning is fun
- : i love my cat
- : my cat is fun
我们构建一个简单的词频矩阵 (这里不用TF-IDF以简化计算):
| learning | 2 | 1 | 0 | 0 |
| machine | 1 | 0 | 0 | 0 |
| deep | 0 | 1 | 0 | 0 |
| fun | 0 | 1 | 0 | 1 |
| cat | 0 | 0 | 1 | 1 |
| love | 0 | 0 | 1 | 0 |
直观上,我们可以看到 是关于“学习”的主题,而 是关于“猫”的主题。
现在,我们对 进行SVD,并选择 (因为我们直观地看到了两个主题)。通过计算(例如使用Python的numpy.linalg.svd),我们会得到 , , 。
假设计算结果(为了说明,这里是示意值)给出的文档语义表示 如下:
(注意:实际SVD结果中可能有负值,这里为了解释性而简化)
每一列现在是对应文档的2维表示:
现在,我们计算文档间的余弦相似度。
- Sim(): 向量 和 的夹角会非常小,相似度接近1。这成功捕捉到了它们都关于“学习”主题的深层联系,尽管它们共享的词只有一个(“learning”)。
- Sim(): 向量 和 的夹角会接近90度,相似度接近0。这正确地分开了两个不相关的主题。
通过这个过程,LSA成功地超越了表面词汇的限制,在“主题”层面发现了文档之间的真正关系。