从零开始理解词向量:共现矩阵与语义表示
本文通过共现矩阵示例讲解自然语言处理中词向量的构建原理,演示了如何计算词语间的余弦相似度。文章分析了共现矩阵在稀疏性、词序丢失及复杂关系捕捉上的局限性,并简要介绍了现代词向量技术(如 Word2Vec)的演进方向,帮助读者建立对 NLP 向量表示的基础认知。

本文通过共现矩阵示例讲解自然语言处理中词向量的构建原理,演示了如何计算词语间的余弦相似度。文章分析了共现矩阵在稀疏性、词序丢失及复杂关系捕捉上的局限性,并简要介绍了现代词向量技术(如 Word2Vec)的演进方向,帮助读者建立对 NLP 向量表示的基础认知。

在大模型时代,经常听到向量这个词,比如向量检索、相似度计算等。那么要怎样理解自然语言处理(NLP)中的向量呢?本文通过介绍一个简单的例子来理解向量,重点介绍共现矩阵。
共现矩阵是自然语言处理中一种用来表示词语之间关系的工具。在共现矩阵中,每一行代表一个词语,每一列也代表一个词语,矩阵中的每个元素则表示对应行词语和列词语在一段文本或者一组文本中同时出现的次数。简而言之,共现矩阵告诉我们哪些词语在文本中经常一起出现,从而揭示它们之间的关联性。
举例说明,有下面一个句子:
'小华喜欢吃苹果和橙子,他经常在学校买水果吃。'
将这句话按词语切分为:
'小华'、'喜欢'、'吃'、'苹果'、'和'、'橙子'、'他'、'经常'、'在'、'学校'、'买'、'水果'。
我们设置一个规则,即窗口大小为 2。然后,对于每个词,看它周围 2 个词内出现了哪些其他词语,如果出现了就在共现矩阵中对应位置加 1。
以"小华"为例,它周围 2 个词是"喜欢"、"吃",所以我们在共现矩阵中"小华"行,"喜欢"、"吃"列的位置上加 1。
依此类推,我们可以构建出如下的共现矩阵(为了简洁起见,这里只展示部分共现关系):
| 小华 | 喜欢 | 吃 | 苹果 | 和 | 橙子 | 他 | 经常 | 在 | 学校 | 买 | 水果 | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 小华 | 0 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| 喜欢 | 1 | 0 | 1 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| 吃 | 1 | 1 | 0 | 1 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 0 |
| 苹果 | 0 | 1 | 1 | 0 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 0 |
| ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
(注:实际矩阵为对称矩阵,此处仅示意逻辑)
有了这个共现矩阵之后,我们就可以用向量来表示词了。例如:
[0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0][0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0]我们来看看,'苹果'和'橙子'之间有多大关联。这里可以用余弦相似度来衡量。
已知:
计算点积:两个向量的对应位相乘,然后相加。 $$ A \cdot B = (0\times0) + (0\times0) + (1\times0) + (0\times1) + (1\times1) + (1\times0) + (0\times1) + ... = 1 $$
计算模长: $$ ||A|| = \sqrt{0^2 + 0^2 + 1^2 + 0^2 + 1^2 + 1^2 + ...} = \sqrt{3} $$ $$ ||B|| = \sqrt{0^2 + 0^2 + 0^2 + 1^2 + 1^2 + 0^2 + 1^2 + ...} = \sqrt{3} $$
计算余弦相似度: $$ \text{Similarity}(A, B) = \frac{A \cdot B}{||A|| \times ||B||} = \frac{1}{\sqrt{3} \times \sqrt{3}} = \frac{1}{3} $$
因此,"苹果"和"橙子"之间的余弦相似度为 1/3。这意味着在给定的上下文中,苹果和橙子有 1/3 的共现情况,这种相似度反映了苹果和橙子在上下文中的共现模式。
再来看看'苹果'和'喜欢'的相似度:
[0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0][1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0]而'苹果'和'学校'的相似度则为 0,这表明它们在共现矩阵中共现的情况很少或根本没有。换句话说,这两个词在文本中很少同时出现在相同的上下文中。因此,它们之间的共现模式非常不同,可以认为它们在语义上没有明显的联系或相关性。
我们来计算一下'他'与'经常'的相似度,结果是 1/3,而'小华'与'经常'的相似度为 0。而从语义来看,这里的'他'代指'小华',但从上面的共现矩阵并没有发现这种联系,说明了共现矩阵在捕捉词语语义关系方面的不足。共现矩阵的不足,主要表现在以下几点:
相比之下,机器学习中的词向量具有以下优点:
为了解决共现矩阵的稀疏性问题,早期研究常使用奇异值分解(SVD)对共现矩阵进行降维。通过保留前 k 个主成分,可以将高维稀疏矩阵转化为低维稠密矩阵,从而得到初步的词向量表示。这种方法被称为潜在语义分析(LSA)。
随着深度学习的发展,Word2Vec 模型应运而生。它通过预测上下文(Skip-gram)或预测中心词(CBOW)的方式,直接训练出稠密的词向量。相比基于统计的共现矩阵,Word2Vec 能够更高效地利用大规模数据,并捕捉到更细微的语义关系。
以下是一个简单的 Python 示例,演示如何构建共现矩阵并计算余弦相似度:
import numpy as np
from sklearn.metrics.pairwise import cosine_similarity
# 定义词汇表
words = ["小华", "喜欢", "吃", "苹果", "和", "橙子", "他", "经常", "在", "学校", "买", "水果"]
word_to_idx = {w: i for i, w in enumerate(words)}
# 初始化共现矩阵 (12x12)
count_matrix = np.zeros((len(words), len(words)))
# 模拟句子分词
tokens = ["小华", "喜欢", "吃", "苹果", "和", "橙子", "他", "经常", "在", "学校", "买", "水果"]
window_size = 2
# 构建共现矩阵
for i, word in enumerate(tokens):
start = max(0, i - window_size)
end = min(len(tokens), i + window_size + 1)
for j in range(start, end):
if i != j:
neighbor = tokens[j]
count_matrix[word_to_idx[word], word_to_idx[neighbor]] += 1
# 获取向量
apple_vec = count_matrix[word_to_idx["苹果"]]
orange_vec = count_matrix[word_to_idx["橙子"]]
# 计算余弦相似度
similarity = cosine_similarity([apple_vec], [orange_vec])[0][0]
print(f"苹果和橙子的余弦相似度:{similarity:.4f}")
本文介绍了自然语言处理中的向量表示,着重介绍了共现矩阵的概念和应用。共现矩阵是一种用于表示词语之间关系的工具,通过统计词语在文本中的共现情况,揭示词语之间的关联性。文章以一个简单的例子演示了如何构建共现矩阵,并计算了词语之间的相似度。虽然共现矩阵能捕捉词语的共现关系,但在理解语义关系方面存在不足。相比之下,机器学习中的词向量能更准确地捕捉语义信息,具有更丰富的语义表示,对 NLP 任务更为有效。
在实际应用中,理解词向量的底层原理有助于更好地选择和使用预训练模型,从而提升大模型应用的效果。

微信公众号「极客日志」,在微信中扫描左侧二维码关注。展示文案:极客日志 zeeklog
使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online
生成新的随机RSA私钥和公钥pem证书。 在线工具,RSA密钥对生成器在线工具,online
基于 Mermaid.js 实时预览流程图、时序图等图表,支持源码编辑与即时渲染。 在线工具,Mermaid 预览与可视化编辑在线工具,online
解析常见 curl 参数并生成 fetch、axios、PHP curl 或 Python requests 示例代码。 在线工具,curl 转代码在线工具,online
将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online