分布式语义学详解

文档概述

当我们说”苹果”的时候,你脑海里浮现的是什么?是一个红彤彤的水果,还是那个被咬了一口的手机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降维通过以下步骤解决这问题:

  1. 提取主要结构:奇异值从大到小排列,前几个奇异值往往包含了矩阵中最核心的信息。
  2. 去除噪声:把小的奇异值对应的成分扔掉,这些往往是数据中的噪声。
  3. 获得稠密表示:降维后的词向量不再是稀疏的,而是每个维度都有意义。

降维后,维度通常选择50-300维,这个范围既能保留足够的语义信息,又不会太稀疏。

LSA的局限与适用场景

LSA的优点是可解释性相对较好,而且不需要标注数据,可以直接从无监督的语料中学习。

但它也有明显的局限:

  • 线性假设:LSA本质上是线性方法,无法捕捉非线性语义关系
  • 主题数量需要预设:你得告诉它要找几个主题
  • 上下文窗口固定:只看文档级别的共现,丢失了局部的词语搭配信息

LSA在以下场景表现不错:

  • 信息检索(query-doc匹配)
  • 文档聚类
  • 初级的语义相似度计算

但在需要更精细语义理解的任务上(比如情感分析、机器阅读理解),LSA就显得力不从心了。

LDA:另一种主题模型

LDA和LSA的区别

LDA(Latent Dirichlet Allocation,潜在狄利克雷分配)也是主题模型,但它比LSA多了几层”概率”的包装。

如果说LSA是”发现”主题,那么LDA就是在”生成”文档。

LDA的假设是:

  1. 每篇文档是多个主题的混合
  2. 每个主题是词的概率分布
  3. 写文档的时候,是先决定要写哪些主题(按一定比例混合),再从每个主题里”抽样”出词来
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 | 根据上下文动态变化的词向量 |


参考文献与推荐阅读

  1. Firth, J. R. (1957). Studies in linguistic analysis. Blackwell.
  2. Harris, Z. (1954). Distributional structure. Word, 10(2-3), 146-162.
  3. 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.
  4. Deerwester, S., et al. (1990). Indexing by latent semantic analysis. JASIS, 41(6), 391-407.
  5. Blei, D. M., Ng, A. Y., & Jordan, M. I. (2003). Latent Dirichlet allocation. JMLR, 3, 993-1022.
  6. Turney, P. D., & Pantel, P. (2010). From frequency to meaning: Vector space models of semantics. JAIR, 37, 141-188.
  7. Mikolov, T., et al. (2013). Efficient estimation of word representations in vector space. ICLR Workshop.
  8. Pennington, J., Socher, R., & Manning, C. (2014). GloVe: Global vectors for word representation. EMNLP.
  9. Peters, M. E., et al. (2018). Deep contextualized word representations. NAACL.
  10. Devlin, J., et al. (2019). BERT: Pre-training of deep bidirectional transformers for language understanding. NAACL.

关联文档