第 五 章

文本向量化

以数载文,方可计算

一、为什么要向量化

计算机只认得数字。文本向量化(Text Vectorization)就是把字、词、句子映射成实数向量,使文本能够参与加减、距离、概率等数学运算。它是从「符号处理」迈向「统计计算」的关键一跃。

本章的技术谱系,也是表示能力不断升级的过程:

One-Hot(离散、稀疏、无语义)
   └─ 词袋模型 BoW(计数、稀疏、仍无语义)
        └─ TF-IDF(加权、稀疏、部分语义)
             └─ 分布式词向量 Word2Vec(稠密、含语义)
                  └─ 上下文表示 ELMo / BERT(动态、多义词)

二、One-Hot 编码

最朴素的想法:为词表中的每个词分配一个编号,用「只有该位置为 1、其余为 0」的长向量表示它。

词表 V = [分词, 向量化, 情感, 问答]

分词   = [1, 0, 0, 0]
向量化 = [0, 1, 0, 0]
情感   = [0, 0, 1, 0]
问答   = [0, 0, 0, 1]

优点是简单直观;缺点同样致命:

  • 维度灾难:词表十万,每个向量就是十万维且几乎全 0;
  • 语义鸿沟:任意两个词的向量都正交,余弦相似度恒为 0——「汽车」与「轿车」在模型看来毫无关系;
  • 词序丢失:句子被压缩成等长向量,「狗咬人」与「人咬狗」向量相同。

三、词袋与 TF-IDF 向量

词袋模型(Bag of Words, BoW)把整句/整篇文档表示为「词表上的计数向量」:

词表 [分词, 向量化, 情感, 问答]
句 A「问答机器人离不开分词」→ [1, 0, 0, 1]
句 B「情感分析需要向量化」   → [0, 1, 1, 0]

BoW 已经可以衡量文档间的重叠程度,再加权升级就是第四章学过的 TF-IDF 向量:用 TF-IDF 值替换原始计数,常见词权重更低。

两个常用的小改进:

  • N-gram:把相邻两个词也当作特征(「不/喜欢」→「不喜欢」),部分挽回词序与否定信息;
  • 子词 / 字符 n-gram:缓解未登录词问题,英文还能捕捉词形(-ing、-ed)。

词袋家族在传统文本分类(垃圾邮件、情感分类)中至今仍是又快又稳的基线。

四、分布式表示与 Word2Vec

语言学家有一句名言:「You shall know a word by the company it keeps」——一个词的意思,由它周围常出现的词决定。这就是分布式假设(Distributional Hypothesis)。

2013 年谷歌开源的 Word2Vec 用浅层神经网络从大规模语料中学习每个词的稠密低维向量(通常 100–300 维),语义相近的词在空间中彼此邻近,并出现著名的向量运算:

vec("国王") − vec("男人") + vec("女人") ≈ vec("女王")
vec("北京") − vec("中国") + vec("法国") ≈ vec("巴黎")

它有两种对称的训练结构:

模型输入 → 预测特点
CBOW上下文词 → 中心词训练快,适合高频词
Skip-gram中心词 → 上下文词对低频词更友好,常用

此后还有 GloVe(结合全局共现矩阵)、FastText(把词拆成字符 n-gram,解决未登录词)。而 BERT 类模型进一步实现动态上下文表示:「苹果」在「吃苹果」与「买苹果手机」中向量不同,从根本上处理多义词。

python · gensim 训练词向量from gensim.models import Word2Vec

sentences = [
    ["自然语言处理", "需要", "分词", "向量化"],
    ["情感分析", "基于", "向量化", "分类器"],
    # …… 实际需要海量分好词的句子
]
model = Word2Vec(sentences, vector_size=100, window=5,
                 min_count=1, sg=1)        # sg=1 即 Skip-gram

vec = model.wv["分词"]                  # 100 维向量
print(model.wv.most_similar("分词", topn=5))  # 最相近的 5 个词
生产实践中往往不自己训:可直接加载在百度百科、微博、维基等海量语料上预训练好的中文词向量(如腾讯 AI Lab 开源词向量、Chinese-Word-Vectors),再用领域语料微调。

五、余弦相似度

有了向量,如何衡量两段文本像不像?最常用的是余弦相似度——计算两个向量夹角的余弦,只看方向、不受长度影响:

cos(A, B) = (A · B) / ( ‖A‖ × ‖B‖ )

取值范围 [−1, 1]:越接近 1 越相似,0 表示正交无关

从推荐系统的「相似文章」、检索式问答的「匹配问题」,到 RAG 的语义召回,背后都有余弦相似度(或其等价的归一化向量点积)的身影。第七章的演示将直接用它计算两句话的语义近似程度。

六、Python 实战与交互演示

python · sklearn 构建词袋 / TF-IDF 向量from sklearn.feature_extraction.text import CountVectorizer, TfidfVectorizer

sents = ["问答机器人 需要 分词",
         "情感分析 需要 文本向量化"]

bow = CountVectorizer()
X = bow.fit_transform(sents)
print(bow.get_feature_names_out())
print(X.toarray())

tfidf = TfidfVectorizer()
Y = tfidf.fit_transform(sents)
print(Y.toarray().round(3))

动手一试:句子变向量

输入两个句子,演示会自动完成分词 → 构建词表 → 生成 One-Hot 与词袋向量的全过程(已自动过滤虚词):

向量化实验台BoW + One-Hot

可以看到,两个句子共享的「需要、向量化」在两个 BoW 向量中对应位置同时非零——这正是下一章句法之前、本章向量表示所能捕捉的最朴素的「语义重叠」。