分布式语义学详解
文档概述
当我们说”苹果”的时候,你脑海里浮现的是什么?是一个红彤彤的水果,还是那个被咬了一口的手机logo?这看似简单的问题,实际上触及了语言学最核心的谜题之一:词语的意义到底是怎么来的?分布式语义学给出了一个既反直觉又令人信服的答案——词的意义,就藏在它出现的环境里。这个文档会带你从Firth的经典论断出发,一步步理解分布式语义学的理论基础、数学原理、以及它如何演变成今天大语言模型的基石。
入门篇:词的意义存在于使用中
为什么这个问题值得思考?
先别急着往下看,停下来想想”意义”这件事。
我们从小就被教育说,每个词都有一个”正确”的含义。字典里写得清清楚楚,“狗”的定义是”一种哺乳动物,嗅觉灵敏,听觉发达”。听起来很有道理,对吧?
但问题来了。
想象你说”今天的股票像条狗一样跌跌不休”,这句话里的”狗”还是字典里那个”嗅觉灵敏”的四脚动物吗?显然不是。这里的”狗”更像是”忠诚”(股票一直忠诚地跌)或者”倒霉”(持有它的人很倒霉)的意思。
这就是语言有趣的地方——词的意义是活的,它随着上下文变化而变化。分布式语义学的核心观点就是:别去硬编码词的意义,让计算机自己去从大量的语言使用中”悟”出道理来。
Firth说了什么?
1957年,英国语言学家John Rupert Firth(约翰·鲁珀特·弗思)说了一句被后世奉为经典的话:
“You shall know a word by the company it keeps.” (欲知其词,观其伴焉。)
这句话翻译成大白话就是:看一个词跟哪些词经常一起出现,就能知道它是什么意思。
举个例子。“医生”这个词,你几乎不需要查字典,光看它出现的地方——“医生说”、“医院”、“病人”、“诊断”、“处方”、“白大褂”——你就能大概知道”医生”是干什么的了。
这个看似简单的想法,实际上是整个现代NLP的起点。
从哲学基础说起
Firth的观点和哲学家维特根斯坦(Wittgenstein)的”意义即使用”不谋而合。维特根斯坦认为,词的意义不在脑子里,而在语言的实际使用中。就像你学会骑自行车不是靠背骑行手册,而是靠真正去骑一样,学语言也得靠”泡”在语言环境里。
这种思路在当时可是相当激进的。传统语言学喜欢研究语法规则、词性标注这些”结构”层面的东西,而分布式语义学把注意力转向了”使用”——看词怎么被用,比看词本身是什么更重要。
这种转变的意义怎么说都不为过。它让计算机处理语言的方式从”查字典”变成了”学例子”。而当语料库足够大的时候,这种基于统计的方法往往比专家编写的规则库更准确、更鲁棒。
分布式假说的核心原理
假说是怎么工作的?
分布式假说(Distributional Hypothesis)的逻辑链条其实很清晰:
上下文相似的词 → 意义也相似
或者用更形式化的方式表达:如果两个词 w1 和 w2 出现在几乎相同的上下文中(出现在 w1 周围的词,和出现在 w2 周围的词高度重合),那么 w1 和 w2 的意义就是相似的。
这个假设之所以成立,有几个直观的理由:
第一,语言是功能性的。 人们用词是有目的的。当你想描述”医生”这个概念时,你会发现周围几乎所有的词都指向同一个语义区域——医疗、健康、治疗等等。这种功能性约束让相似意义的词自然地聚集在一起。
第二,学习语言的过程本身就是分布式的。 小孩学说话的时候,没有人给他们逐词讲解字典。相反,他们通过反复听到词在不同情境下的使用,逐渐建立起对词义的理解。这本质上就是一个统计学习的过程。
第三,信息论的角度。 如果两个词的上下文几乎相同,那么关于其中一个词的信息几乎可以完全由另一个词提供。从信息压缩的角度看,它们确实是”同义”的。
上下文窗口:看多近才算”上下文”?
说到这儿,一个很自然的问题就是:什么叫”上下文相似”?我们该看多大的范围?
这就是”上下文窗口”的概念。简单来说,就是在你关注的词周围圈出一块区域,看这个区域里出现了什么词。
句子:"The quick brown fox jumps over the lazy dog"
↑____↑
窗口=2
对于"fox"这个词,窗口=2意味着看它左右各2个词:
左边:quick, brown
右边:jumps, over
所以"fox"的上下文 = {quick, brown, jumps, over}
窗口大小的选择很有讲究:
- 小窗口(1-2词):关注的是语法搭配关系。比如”run”和”running”在小窗口里会很接近,因为它们经常和相同的词搭配。
- 中等窗口(3-5词):捕捉的是语义相似性。“猫”和”狗”会出现在相似的上下文中——它们都可以”叫”、有”毛”、是”宠物”。
- 大窗口(8词以上):更多反映主题或领域。比如”算法”和”数据”在计算机科学的文章里会频繁共现。
在实际应用中,中等窗口是最常见的选择,因为它在语法信息和语义信息之间取得了较好的平衡。
两种分布式表示:词-文档 vs 词-词共现
词-文档矩阵:看词出现在哪些文档里
想象你有一个图书馆,每个抽屉里放着一本书。现在你要给每本书贴标签——不是书名,而是书里出现的关键词。
词-文档矩阵的做法就是:统计每个词在每个文档中出现的频率。如果”算法”在10本计算机相关的书里都出现了,而在文艺小说里几乎不出现,那”算法”这个词的向量表示就是它在这些文档中的出现频率。
文档集合:
- D1: 计算机科学论文
- D2: 文学作品
- D3: 经济学文章
词-文档矩阵(简化示例):
D1 D2 D3
算法 15 0 3
爱情 0 20 5
市场 2 1 18
...
"算法"的向量:[15, 0, 3]
"爱情"的向量:[0, 20, 5]
这种表示的优点是主题信息很强。属于同一主题的词自然会在相似的文档中扎堆,从而获得相似的向量。比如”深度学习”、“神经网络”、“机器学习”这些词几乎总是在一起出现。
这种方法是主题模型(如LSA、LDA)的基础。
词-词共现矩阵:看词和哪些词相邻
另一种思路是:不去看文档,而是看词和词之间的相邻关系。
还是上面那个例子,对于”fox”,我们记录它和哪些词挨得近:
"fox"出现在以下上下文词附近:
- brown (出现15次)
- jumps (出现12次)
- quick (出现10次)
- dog (出现8次)
...
"fox"的向量:[brown:15, jumps:12, quick:10, dog:8, ...]
词-词共现矩阵的对称性让它天然适合做语义相似度计算——如果两个词的上下文词几乎一样,那它们八成是同义词或者语义相近的词。
两种方法各有优劣:
| 特性 | 词-文档矩阵 | 词-词共现矩阵 |
|---|---|---|
| 捕捉的信息 | 主题/领域 | 局部语义搭配 |
| 矩阵大小 | 词数 × 文档数 | 词数 × 词数 |
| 适合的任务 | 主题聚类、信息检索 | 语义相似度、类比推理 |
| 计算成本 | 文档数通常较小 | 词表大小是瓶颈 |
TF-IDF:给词的重要性打个分
为什么简单的词频不够用?
你可能会想:统计词出现的频率不就行了?出现次数多的词更重要,对吧?
没那么简单。考虑这两个句子:
- “这只猫很可爱。”
- “这只可爱的猫很可爱。”
第二句里”很”和”可爱”都出现了两次,但”很”显然是更”普通”的词——它几乎在所有句子都能出现,没什么区分度。
这就是”停用词”问题。像”的”、“了”、“在”、“是”这样的高频词,几乎每个文档里都会出现,单独看频率根本分不出文档的特色。
TF-IDF的直觉
TF-IDF(Term Frequency - Inverse Document Frequency)就是来解决这个问题的。它的核心思想是:
一个词如果在自己的文档里出现得多,但在其他文档里出现得少,那它就是重要的。
公式拆解:
- TF(词频):词 i 在文档 j 中出现的次数。出现越多越重要。
- IDF(逆文档频率):,其中 N 是文档总数,df_i 是包含词 i 的文档数。出现在越多文档里,IDF越低。
例子:
- 语料有100篇文档
- "算法"出现在15篇文档中
- "的"出现在100篇文档中
IDF("算法") = log(100/15) ≈ 1.85
IDF("的") = log(100/100) = 0
所以"算法"的重要性被放大,"的"的重要性被压到0
TF-IDF在信息检索领域用得特别多。搜索引擎判断一个文档和查询词的相关性时,经常会用到类似的思想。
从词-文档矩阵提取语义:LSA详解
什么是LSA?
LSA(Latent Semantic Analysis,潜在语义分析)是一种经典的主题建模方法。它的核心思想很朴素:
文档和词之间可能存在一个隐藏的”主题层”,这个主题层才是真正决定词出现在哪些文档的原因。
比如,一篇关于”机器学习”的论文,里面会出现”算法”、“数据”、“模型”这些词,但这些词之间并不是直接关联的——它们是通过”机器学习”这个隐藏主题间接关联的。
LSA的任务就是把这个隐藏的主题层给”还原”出来。
LSA的工作原理
LSA的技术基础是矩阵分解(更准确地说,是SVD奇异值分解)。它把巨大的词-文档矩阵分解成几个小矩阵的乘积,从而提取出潜在语义。
原始矩阵 M(词 × 文档,维度可能达到 50000 × 10000)
≈
U(词 × 主题) × Σ(主题强度对角阵) × VT(主题 × 文档)
分解之后:
- U 矩阵:每行是一个词在主题空间中的表示
- Σ 矩阵:对角线上是每个主题的”强度”
- VT 矩阵:每列是一个文档在主题空间中的表示
这就是为什么叫”潜在”语义分析——语义信息本来是”隐藏”在词-文档共现里的,通过SVD我们把它”挖”了出来。
SVD降维:为什么需要降维?
你可能会问:为什么要搞这么复杂,直接用原始的词-文档矩阵不行吗?
答案在于稀疏性和噪声。
一个典型的词-文档矩阵,99%以上的元素都是0(因为每个词只出现在少数文档里)。这种稀疏性让相似度计算变得不稳定——两个词可能只在极其罕见的一两个文档里碰巧同时出现,频率上是1和0的区别,语义上可能根本不是那么回事。
SVD降维通过以下步骤解决这问题:
- 提取主要结构:奇异值从大到小排列,前几个奇异值往往包含了矩阵中最核心的信息。
- 去除噪声:把小的奇异值对应的成分扔掉,这些往往是数据中的噪声。
- 获得稠密表示:降维后的词向量不再是稀疏的,而是每个维度都有意义。
降维后,维度通常选择50-300维,这个范围既能保留足够的语义信息,又不会太稀疏。
LSA的局限与适用场景
LSA的优点是可解释性相对较好,而且不需要标注数据,可以直接从无监督的语料中学习。
但它也有明显的局限:
- 线性假设:LSA本质上是线性方法,无法捕捉非线性语义关系
- 主题数量需要预设:你得告诉它要找几个主题
- 上下文窗口固定:只看文档级别的共现,丢失了局部的词语搭配信息
LSA在以下场景表现不错:
- 信息检索(query-doc匹配)
- 文档聚类
- 初级的语义相似度计算
但在需要更精细语义理解的任务上(比如情感分析、机器阅读理解),LSA就显得力不从心了。
LDA:另一种主题模型
LDA和LSA的区别
LDA(Latent Dirichlet Allocation,潜在狄利克雷分配)也是主题模型,但它比LSA多了几层”概率”的包装。
如果说LSA是”发现”主题,那么LDA就是在”生成”文档。
LDA的假设是:
- 每篇文档是多个主题的混合
- 每个主题是词的概率分布
- 写文档的时候,是先决定要写哪些主题(按一定比例混合),再从每个主题里”抽样”出词来
LDA的生成过程(简化版):
对于每篇文档 d:
1. 从 Dirichlet 分布中抽样文档-主题分布 θ_d
2. 对于文档中的每个词 w:
a. 从 θ_d 中抽样一个主题 z
b. 从主题 z 的词分布中抽样一个词 w
这个概率框架让LDA有几个优势:
- 概率解释更清晰:每个词-主题、主题-文档的关系都有概率含义
- 主题分配更灵活:一篇文档可以有多个主题,不像LSA是单一主题
- 对新文档友好:可以计算新文档的主题分布,而不需要重新训练
LDA的实际应用
LDA在以下场景很常见:
- 新闻话题追踪(把每天的新闻自动归类到若干话题)
- 学术文献分析(发现某领域的研究主题)
- 社交媒体内容分析(用户讨论的核心话题)
- 推荐系统的内容理解(给商品打上主题标签)
sklearn和gensim都有现成的LDA实现,几行代码就能跑起来。
分布式表示 vs 符号表示:两种意义理论
什么是符号表示?
在说分布式表示之前,先说说它的”对手”——符号表示(Symbolic Representation)。
符号表示的核心思想是:词的意义可以用符号、规则、逻辑来形式化描述。
最典型的例子是WordNet这样的知识库。在WordNet里,“dog”被组织在一个复杂的同义词网络里:
- 上位词:canine → mammal → animal → organism
- 下位词:puppy, hound, cur…
- 部分:tail, paw, snout…
- 属性:domesticated, carnivorous…
还有一种符号表示是逻辑形式化。比如用一阶逻辑来描述”医生”:
∃x. Doctor(x) ∧ Profession(x, medicine)
符号表示的优点是可解释性强、推理能力明确。你知道每个词在符号系统里代表什么,可以做精确的逻辑推导。
符号表示的困境
但符号表示也有致命的问题:
第一,词义的边界很难划定。 “水果”算不算”食物”?“苹果”算不算”水果”?“iPhone”是”水果”吗?这些边界问题在现实语言中比比皆是,用硬编码的符号系统很难优雅地处理。
第二,语言是模糊的、概率性的。 “年轻人”是多大?“很高”是多高?这种模糊性很难用精确的规则描述。
第三,新词、新用法层出不穷。 每年都有大量新词出现(比如”内卷”、“躺平”),符号系统需要人工维护更新,成本极高。
第四,组合性问题。 符号表示很难处理”组合性”——把简单元素的含义组合成复杂表达的含义。比如”红色的苹果”比”苹果”多了”红色”这个修饰,这该怎么编码?
分布式表示的应对
分布式表示(也就是我们一直在讨论的词向量)用连续向量来代表词的意义,这些问题在一定程度上被绕开了:
- 边界模糊:向量空间是连续的,不存在硬边界,相似度是渐变的
- 概率性:相似度本身就是一种概率性的度量
- 自动学习:不需要人工标注,从语料中自动学习
- 组合性潜力:向量的加法、乘法操作可以实现一定程度的语义组合
当然,分布式表示也有自己的问题(后面会讨论)。两种方法各有优劣,现在的AI趋势是把它们结合起来——用符号系统提供结构化的知识,用分布式表示提供灵活的语义理解。
分布式表示的局限性
组合性问题:1+1不一定等于2
分布式表示面临的最大挑战之一是**组合性(compositionality)**问题。
什么叫组合性?简单说就是:整体的意义由部分的意义组合而成。
“红色的苹果”这个词组,意思是”红色的”和”苹果”的组合。但如果只知道”红色”的向量和”苹果”的向量,怎么得到”红色的苹果”的向量?
向量的简单相加/相乘虽然可以凑合用,但往往丢失了修饰关系。“红苹果”和”苹果红”用简单加法可能得到几乎一样的向量,但它们的语义完全不同。
这暴露了分布式表示的一个根本局限:它擅长表示”相似性”,但不擅长表示”结构关系”。
语境依赖:同一个词的多种意义
分布式表示的另一个问题是语境依赖。
想想”bank”这个词:
- “I went to the bank to deposit money”(银行)
- “The river bank was covered in grass”(河岸)
在Word2Vec这样的静态词向量模型里,“bank”只有一个向量,无论在哪个语境下都是同一个表示。这显然是不够的。
这就是为什么后来出现了上下文词向量(contextualized word embeddings),比如ELMo和BERT。它们会根据上下文动态调整词的表示——“bank”在第一句里会得到接近”银行”意义的向量,在第二句里会得到接近”河岸”意义的向量。
其他局限
- 对语料的依赖:词向量的质量完全取决于训练语料。语料有偏见,向量就有偏见。
- 不可解释性:向量是黑盒,你很难说清楚为什么”猫”和”狗”相似。
- 缺乏推理能力:分布式表示擅长模式识别,但不擅长逻辑推理。
- 对低频词不友好:训练语料里出现少的词,学到的向量往往不准确。
BERT时代的突破
从Word2Vec到ELMo
Word2Vec(Skip-gram、CBOW)开创了词向量时代,但它的问题是静态的——每个词只有一个固定的向量。
2018年,ELMo(Embeddings from Language Models)带来了改变。它的核心创新是使用语言模型来生成上下文相关的词向量。
传统方法:bank → [0.2, -0.1, 0.5, ...] (固定不变)
ELMo:bank in "bank account" → [0.8, 0.1, 0.2, ...]
bank in "river bank" → [-0.3, 0.7, 0.1, ...]
ELMo使用双向LSTM,从左到右和从右到左各跑一遍语言模型,然后把两边的表示拼接起来。更重要的是,它不是只输出最后一层,而是把多层LSTM的表示都保留下来,让下游任务自己去选择用哪些层。
BERT的双向Transformer
ELMo虽然引入了上下文,但它的双向是”浅”的——左右两个方向实际上是分开建模的。
BERT(Bidirectional Encoder Representations from Transformers)用Transformer架构实现了真正的双向上下文建模。
BERT的核心创新:
1. 遮蔽语言模型(Masked LM)
不再预测下一个词,而是随机遮蔽一些词,让模型根据上下文去”猜”被遮住的词。这种”完形填空”式的训练让模型必须同时考虑左右两侧的上下文。
2. 下一句预测(NSP)
训练时还给了一个辅助任务:判断句子对是否是连续的上下文。这帮助模型学习句子之间的关系,对问答、推理等任务很有帮助。
3. 深层表示
BERT有12层(base版本)或24层(large版本),每一层都编码了不同粒度的信息:
- 浅层:形态学、基础语法
- 中层:句法关系、实体类型
- 深层:深层语义、任务相关知识
这种层次化的表示给了我们很大的灵活性——不同的任务可以选择不同的层来做。
为什么BERT的语义空间更好?
BERT的语义空间比Word2Vec有几个显著改进:
第一,多义消歧能力。 因为每个词的表示都是上下文相关的,所以一词多义的问题被大大缓解。
第二,更强的语义组合能力。 Transformer的自注意力机制允许模型学习词与词之间的复杂关系,不仅仅是简单的共现。
第三,跨任务迁移能力更强。 BERT在大规模通用语料上预训练后,只需要在具体任务的小数据上微调就能取得很好的效果。
第四,句子级别的表示。 BERT有专门的[CLS]token来聚合整个句子的信息,对句子级别的任务(如文本分类)特别有用。
跨语言分布式语义
为什么跨语言是个问题?
英语的”dog”和法语的”chien”说的是同一个动物,但它们的向量在各自的语义空间里可能天差地别。
为什么?因为”dog”的上下文是英文语料决定的——它周围是”cat”、“bark”、“pet”这些词;而”chien”的上下文是法语语料决定的——是”chat”、“aboyer”、“animal de compagnie”这些词。
这两个向量从数学上看可能完全不相似,尽管它们指向同一个概念。
跨语言对齐的方法
怎么把不同语言的语义空间对齐?有几种主要思路:
方法一:平行语料对齐
如果有大量的平行语料(同一个句子的不同语言翻译),可以直接用对齐信息来约束模型。比如”dog”和”chien”在很多平行句子里是翻译关系,让它们的向量尽可能接近就行了。
平行语料:
"The dog is cute." → "Le chien est mignon."
"Dog is a pet." → "Le chien est un animal de compagnie."
通过这些对齐,让:
v("dog") ≈ v("chien")
方法二:双语词向量
在训练词向量的时候,把两种语言的词放进同一个空间。比如MUSE、VecMap这些方法,通过对抗训练或正交变换,把不同语言的向量空间对齐。
方法三:多语言预训练模型
现在最流行的方法是直接训练多语言模型,比如mBERT、XLM-R。这些模型在一个包含100多种语言的超大规模语料上联合训练,让不同语言的对应词在向量空间里自然地接近。
mBERT/XLM-R的效果:
v("狗") + (v("可爱") - v("cute") = v("mignon") - v("cute")) ≈ v("mignon")
分布式语义与认知科学
人脑中的语义表示
一个有趣的问题是:人脑是怎么表示词语意义的?
fMRI(功能性磁共振成像)和EEG(脑电图)等神经科学技术给了我们一些线索:
第一,语义表示是分布式的。 当大脑处理”苹果”这个词时,并不是某个特定的脑区被激活,而是多个脑区同时活动——视觉皮层(想象苹果的样子)、味觉皮层(回忆苹果的味道)、语言区(理解”苹果”这个词)。
第二,相似概念激活相似模式。 fMRI实验显示,语义相关的词(如”苹果”和”橙子”)激活的脑区模式高度相似,而语义无关的词(如”苹果”和”椅子”)激活的模式差异很大。
第三,具体的词和抽象的词加工方式不同。 具体词(如”锤子”)更多激活感知运动皮层,而抽象词(如”自由”)更多依赖前额叶皮层。
这些发现和分布式语义学的假设惊人地吻合——意义的表示确实是分布的、基于相似性的。
LSA和人的语义知识
LSA的一个经典实验(Landauer & Dumais, 1997)发现,单纯通过统计分析语料库学到的语义表示,在很多方面和人类对词义的理解高度一致。
比如用LSA向量来模拟人类的词义相似度判断,发现相关性可以达到0.6-0.7左右——对于无监督的方法来说,这是相当不错的成绩。
更重要的是,LSA还能预测人类的词汇学习速度。那些在语料中经常与其他词一起出现的词,往往也是人类学得更快的词。这暗示分布式统计可能是人类语言习得的重要机制之一。
分布式vs结构化表示
认知科学里有一个长期的争论:人脑用的是分布式表示还是结构化表示?
- 分布式表示:意义分散在大量神经元的激活模式中
- 结构化表示:意义由符号结构组成,有明确的组合规则
最新的证据表明,两者可能都有。分布式表示负责存储和处理语义内容,而前额叶皮层负责把这些内容组合成复杂的结构。
这给AI的启示是:也许我们不应该只用分布式方法或只用符号方法,而是把它们结合起来——用分布式方法做语义理解,用结构化方法做逻辑推理。
动手实验:用LSA分析新闻语料
实验目标
用scikit-learn自带的新闻语料库(20 Newsgroups),演示如何用LSA提取主题。
完整代码
from sklearn.datasets import fetch_20newsgroups
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.decomposition import TruncatedSVD
import numpy as np
# 1. 加载数据
print("加载20新闻组数据集...")
newsgroups = fetch_20newsgroups(subset='all', remove=('headers', 'footers', 'quotes'))
print(f"文档数量: {len(newsgroups.data)}")
print(f"类别数量: {len(newsgroups.target_names)}")
print(f"类别列表: {newsgroups.target_names}")
# 2. TF-IDF向量化
print("\n进行TF-IDF向量化...")
vectorizer = TfidfVectorizer(
max_df=0.5, # 忽略出现在50%以上文档中的词
min_df=5, # 至少在5篇文档中出现
max_features=10000, # 最多保留10000个特征词
stop_words='english' # 去掉英语停用词
)
tfidf_matrix = vectorizer.fit_transform(newsgroups.data)
print(f"TF-IDF矩阵形状: {tfidf_matrix.shape}")
# 3. LSA分解
print("\n进行LSA分解...")
n_topics = 10
lsa = TruncatedSVD(n_components=n_topics, random_state=42)
lsa.fit(tfidf_matrix)
print(f"LSA分解完成")
print(f"解释方差比例: {lsa.explained_variance_ratio_.sum():.2%}")
# 4. 查看每个主题的关键词
feature_names = vectorizer.get_feature_names_out()
print("\n" + "="*60)
print("LSA提取的10个主题及其关键词")
print("="*60)
for topic_idx, topic in enumerate(lsa.components_):
# 取权重最大的10个词
top_indices = topic.argsort()[:-11:-1]
top_words = [feature_names[i] for i in top_indices]
top_weights = [topic[i] for i in top_indices]
print(f"\n主题 {topic_idx} ({newsgroups.target_names[topic_idx]}):")
print(" 关键词: " + ", ".join(top_words[:5]))
# 5. 可视化:每个文档的主题分布
print("\n" + "="*60)
print("文档主题分布示例")
print("="*60)
# 取几个文档展示
doc_topics = lsa.transform(tfidf_matrix)
for i in [0, 100, 500, 1000]:
print(f"\n文档 {i} (类别: {newsgroups.target_names[newsgroups.target[i]]}):")
print(f" 内容预览: {newsgroups.data[i][:200]}...")
dominant_topic = doc_topics[i].argmax()
print(f" 主导主题: 主题{dominant_topic} (权重: {doc_topics[i][dominant_topic]:.3f})")
# 6. 语义相似度搜索
print("\n" + "="*60)
print("语义相似度搜索演示")
print("="*60)
def find_similar_documents(query, vectorizer, lsa, documents, doc_vectors, top_k=5):
"""根据查询文本找相似文档"""
# 把查询向量化并转换到LSA空间
query_tfidf = vectorizer.transform([query])
query_lsa = lsa.transform(query_tfidf)
# 计算余弦相似度
from sklearn.metrics.pairwise import cosine_similarity
similarities = cosine_similarity(query_lsa, doc_vectors)[0]
# 排序
top_indices = similarities.argsort()[-top_k:][::-1]
return [(i, similarities[i], documents[i][:200]) for i in top_indices]
# 测试查询
query = "computer graphics and image processing"
results = find_similar_documents(
query, vectorizer, lsa,
newsgroups.data, doc_topics, top_k=5
)
print(f"\n查询: '{query}'")
print(f"\n最相似的5篇文档:")
for idx, score, content in results:
print(f" - 文档{idx} (相似度: {score:.3f})")
print(f" 类别: {newsgroups.target_names[newsgroups.target[idx]]}")
print(f" 内容: {content}...")实验结果解读
运行这个代码,你会看到:
第一,LSA成功识别出了新闻组的类别。比如”comp.graphics”主题下的关键词会是”image, graphics, software”等;“sci.space”主题下的关键词会是”space, nasa, launch”等。
第二,有些主题会有交叉——比如”politics”和”religion”可能会有一些共同词汇(“people”, “government”)。
第三,语义相似度搜索能找到主题相关的文档,即使查询词和文档词没有字面重叠。
这个实验展示了LSA的核心能力:从词的共现中自动发现语义结构。
分布式语义学的未来展望
和知识图谱的结合
纯粹从文本语料中学习的分布式语义,虽然强大,但缺少结构化的知识。把词向量和知识图谱结合起来,是当前的一个活跃研究方向。
比如:
- 用知识图谱的实体关系来增强词向量的语义
- 用词向量来做知识图谱的补全和推理
- 融合符号逻辑和神经网络的”神经符号AI”
多模态语义
现实世界是多模态的——我们不仅有文字,还有图像、声音、视频。让语义表示融合多种模态的信息,是迈向更通用AI的必经之路。
CLIP、DALL-E这些模型已经展示了图文对齐的潜力,把”猫”的视觉特征和语言表示统一到同一个空间里。
动态语义和持续学习
语言是不断演化的——新词出现,旧词获得新义。固定的词向量无法捕捉这种动态变化。
持续学习、在线学习、动态更新——这些是未来语义系统需要解决的问题。
关键词速览
|| 术语 | 英文 | 一句话解释 | ||------|------|----------| || 分布式假说 | Distributional Hypothesis | 上下文相似的词意义也相似 | || 共现矩阵 | Co-occurrence Matrix | 统计词和上下文一起出现的频率 | || SVD | Singular Value Decomposition | 把大矩阵分解成几个小矩阵,提取核心信息 | || PMI | Pointwise Mutual Information | 衡量两个词关联强度的信息论指标 | || LSA | Latent Semantic Analysis | 用SVD从文档中挖掘隐藏主题 | || LDA | Latent Dirichlet Allocation | 用概率模型做主题建模 | || Skip-gram | Skip-gram Model | 用中心词预测周围上下文 | || CBOW | Continuous Bag-of-Words | 用周围词预测中心词 | || 词嵌入 | Word Embedding | 把词映射到连续的向量空间 | || 上下文词向量 | Contextualized Embedding | 根据上下文动态变化的词向量 |
参考文献与推荐阅读
- Firth, J. R. (1957). Studies in linguistic analysis. Blackwell.
- Harris, Z. (1954). Distributional structure. Word, 10(2-3), 146-162.
- Landauer, T. K., & Dumais, S. T. (1997). A solution to Plato’s problem: The latent semantic analysis theory of acquisition. Psychological Review, 104(2), 211-240.
- Deerwester, S., et al. (1990). Indexing by latent semantic analysis. JASIS, 41(6), 391-407.
- Blei, D. M., Ng, A. Y., & Jordan, M. I. (2003). Latent Dirichlet allocation. JMLR, 3, 993-1022.
- Turney, P. D., & Pantel, P. (2010). From frequency to meaning: Vector space models of semantics. JAIR, 37, 141-188.
- Mikolov, T., et al. (2013). Efficient estimation of word representations in vector space. ICLR Workshop.
- Pennington, J., Socher, R., & Manning, C. (2014). GloVe: Global vectors for word representation. EMNLP.
- Peters, M. E., et al. (2018). Deep contextualized word representations. NAACL.
- Devlin, J., et al. (2019). BERT: Pre-training of deep bidirectional transformers for language understanding. NAACL.
关联文档