词向量空间 (Word Embeddings):从 One-Hot 到 Word2Vec

📂 所属阶段:第一阶段 — 文本预处理(基石篇)
🔗 相关章节:文本特征工程 · 分词技术


1. 为什么需要词向量?

1.1 One-Hot 编码的问题

# One-Hot 编码:每个词一个维度,只有自己为 1
import numpy as np

vocab = ["我", "爱", "机器", "学习"]
vocab_size = len(vocab)

# 词的 One-Hot 表示
def one_hot(word, vocab):
    vec = np.zeros(len(vocab))
    if word in vocab:
        vec[vocab.index(word)] = 1
    return vec

print(one_hot("机器", vocab))
# [0, 0, 1, 0]

# 问题一:维度爆炸(10万词汇 → 10万维)
# 问题二:语义无关("机器"和"电脑"都是 1,和其他词无关)
# 问题三:稀疏(99.999% 都是 0)

1.2 词向量的革命

分布式表示:将词的意思分散到多个维度

One-Hot(稀疏,高维):
  机器 = [0, 0, 1, 0, 0, ...]
  
Word2Vec(稠密,低维):
  机器 = [0.23, -0.45, 0.89, -0.12, ...]  (100-300维)

为什么有效:语义相似的词,在向量空间中距离更近!
"机器" ≈ "电脑" → 距离近
"机器" ≠ "食物" → 距离远

2. Word2Vec 原理

2.1 两个核心模型

Word2Vec 包含两个模型:

Skip-Gram:给定中心词,预测上下文词
  "机器" → 预测 "我", "爱", "学习"

CBOW(Continuous Bag-of-Words):给定上下文,预测中心词
  "我", "爱", "学习" → 预测 "机器"

训练数据来源:互联网语料(无需标注!)

2.2 Skip-Gram 示例

窗口大小 = 2

句子:"我 爱 机器 学习"
      ↓        ↓
   中心词     上下文词

"机器" 的训练样本:
  (机器, 我)  (机器, 爱)  (机器, 学习)

目标:学会 "机器" 和 "我/爱/学习" 的关系

2.3 Word2Vec 的数学本质

# Word2Vec 训练过程(简化)
"""
1. 随机初始化词向量
2. 定义损失函数:给定中心词,最大化上下文词的概率
3. 反向传播更新向量
4. 最终每个词有一个稠密向量
"""

# 关键洞察:出现在相似上下文的词有相似的向量
# "机器学习" 和 "深度学习" 经常出现在相似上下文 → 向量相似

2.4 使用预训练 Word2Vec

# 使用 Gensim 加载预训练中文词向量
pip install gensim

from gensim.models import KeyedVectors

# 加载腾讯中文词向量(需要自行下载,约 6GB)
model = KeyedVectors.load_word2vec_format(
    "Tencent_AILab_Chinese_Embedding.txt",
    binary=False
)

# 找相似词
result = model.most_similar("人工智能", topn=5)
print(result)
# [('机器学习', 0.85), ('深度学习', 0.82), ...]

# 词语类比
# 北京 - 中国 + 日本 = 东京
result = model.most_similar(
    positive=["北京", "日本"],
    negative=["中国"],
    topn=1
)
print(result)
# [('东京', 0.92)]

3. GloVe

3.1 GloVe 原理

GloVe = Global Vectors

核心思想:结合全局统计信息和局部上下文

统计信息:词-词共现矩阵(整个语料中词A和词B一起出现的次数)
         这是一个 "全局" 信息

Word2Vec:只利用局部窗口信息
GloVe:结合全局共现统计 + 局部窗口

效果:GloVe 通常训练更快,效果稳定

3.2 使用 GloVe 词向量

import numpy as np

# 加载 GloVe 词向量(英文)
# 下载:glove.6B.zip(822MB)
def load_glove(filepath, vocab):
    embeddings = {}
    with open(filepath, encoding="utf-8") as f:
        for line in f:
            values = line.strip().split()
            word = values[0]
            vector = np.array(values[1:], dtype="float32")
            if word in vocab:
                embeddings[word] = vector
    return embeddings

# 使用
vocab = {"hello": 0, "world": 1}
embeddings = load_glove("glove.6B.50d.txt", vocab)

# 平均词向量表示句子
def sentence_embedding(tokens, embeddings, dim=50):
    vectors = [embeddings[w] for w in tokens if w in embeddings]
    if vectors:
        return np.mean(vectors, axis=0)
    return np.zeros(dim)

tokens = ["hello", "world"]
vec = sentence_embedding(tokens, embeddings)
print(vec.shape)  # (50,)

4. 词向量的使用场景

4.1 文本分类

import numpy as np

def text_to_vector(text, tokenizer, embedding_model, dim=300):
    """将文本转为平均词向量"""
    tokens = tokenizer.tokenize(text)
    vectors = []
    for token in tokens:
        if token in embedding_model:
            vectors.append(embedding_model[token])
    if vectors:
        return np.mean(vectors, axis=0)
    return np.zeros(dim)

# 文本相似度
def cosine_similarity(a, b):
    return np.dot(a, b) / (np.linalg.norm(a) * np.linalg.norm(b))

vec1 = text_to_vector("机器学习", jieba_tokenizer, word2vec_model)
vec2 = text_to_vector("深度学习", jieba_tokenizer, word2vec_model)
print(cosine_similarity(vec1, vec2))  # 相似度分数

5. 小结

词向量演进:

One-Hot → Word2Vec → GloVe → BERT(上下文词向量)

One-Hot:稀疏、高维、无语义
Word2Vec:稠密、低维、捕捉语义关系(需要训练)
GloVe:结合全局统计信息
BERT:每个词在不同上下文有不同向量(最强)

💡 2026 年的实践:预训练大模型(BERT、GPT)的词向量效果远超 Word2Vec。简单任务直接用 Hugging Face 的预训练 Embedding,复杂任务才需要训练自己的词向量。


🔗 扩展阅读