词嵌入:让机器理解人类语言的魔法
引言
在自然语言处理(NLP)领域,如何让计算机真正"理解"人类的语言一直是一个核心挑战。传统的文本表示方法如词袋模型(Bag-of-Words)虽然简单有效,但忽略了词语之间的语义关系和上下文信息。近年来,词嵌入(Word Embedding)技术革命性地改变了这一局面,它能够将离散的词汇映射到连续的向量空间中,从而让机器具备了"理解"词语语义的能力。
本文将深入探讨词嵌入的原理、实现方法及其在NLP中的应用,帮助读者全面理解这一关键技术。
什么是词嵌入?
从独热编码说起
传统的文本表示方法是独热编码(One-Hot Encoding),例如词汇表中有10000个词,那么"苹果"这个词会被表示为一个长度为10000的向量,其中只有第500个位置为1,其余为0。这种方法存在两个主要问题:
# 示例:独热编码
vocabulary = ["苹果", "香蕉", "橙子", "葡萄"]
wordtoidx = {"苹果": 0, "香蕉": 1, "橙子": 2, "葡萄": 3}
def onehotencode(word):
vector = [0] * len(vocabulary)
idx = wordtoidx[word]
vector[idx] = 1
return vector
print(onehotencode("苹果")) # [1, 0, 0, 0]
词嵌入的核心思想
词嵌入的核心思想是将每个词映射到一个低维连续向量空间,使得语义相似的词在向量空间中距离更近。这种表示方式能够:
- 捕捉词语之间的语义关系
- 支持数学运算(如"国王 - 男人 + 女人 ≈ 女王")
- 减少维度灾难
- 提高模型的泛化能力
主流词嵌入算法
1. Word2Vec
Word2Vec是最著名的词嵌入算法之一,由Google团队提出。它包含两种训练方法:
CBOW(Continuous Bag-of-Words)
CBOW通过上下文词预测目标词:
上下文词 -> [?] -> 目标词
from gensim.models import Word2Vec
from gensim.test.utils import commontexts
准备训练数据
sentences = [
['human', 'interface', 'computer'],
['survey', 'user', 'computer', 'system', 'response', 'time'],
['eps', 'user', 'interface', 'system']
]
训练Word2Vec模型
model = Word2Vec(sentences, vectorsize=100, window=5, mincount=1, workers=4)
获取词向量
vector = model.wv['computer'] # 返回100维向量
print(f"Computer vector shape: {vector.shape}")
查找相似词
similarwords = model.wv.mostsimilar('computer', topn=3)
print("Words similar to computer:", similarwords)
Skip-gram
Skip-gram通过目标词预测上下文词:
目标词 -> [?] -> 上下文词
Skip-gram在处理罕见词时表现更好。
2. GloVe(Global Vectors for Word Representation)
GloVe结合了全局统计信息和局部上下文信息,通过构建共现矩阵来学习词向量:
import numpy as np
from collections import defaultdict
class SimpleGloVe:
def init(self, vocabsize, embeddingdim):
self.vocabsize = vocabsize
self.embeddingdim = embeddingdim
self.W = np.random.normal(0, 0.1, (vocabsize, embeddingdim))
self.b = np.zeros((vocabsize,))
def train(self, cooccurrencematrix, learningrate=0.01, epochs=10):
for epoch in range(epochs):
totalloss = 0
for i in range(self.vocabsize):
for j in range(self.vocabsize):
if cooccurrencematrix[i][j] > 0:
xij = cooccurrencematrix[i][j]
prediction = np.dot(self.W[i], self.W[j]) + self.b[i] + self.b[j]
loss = xij - prediction
# 更新参数
gradWi = -loss * self.W[j]
gradWj = -loss * self.W[i]
gradbi = -loss
gradbj = -loss
self.W[i] -= learningrate * gradWi
self.W[j] -= learningrate * gradWj
self.b[i] -= learningrate * gradbi
self.b[j] -= learningrate * gradbj
totalloss += abs(loss)
print(f"Epoch {epoch+1}, Loss: {totalloss:.4f}")
return self.W
3. FastText
FastText是Facebook提出的改进版本,它不仅考虑词的共现关系,还考虑字符级别的n-gram信息:
from gensim.models import FastText
训练FastText模型
fasttextmodel = FastText(sentences,
vectorsize=100,
window=5,
mincount=1,
workers=4,
sg=1) # sg=1表示使用Skip-gram
FastText的优势:
- 能够处理未登录词(out-of-vocabulary words)
- 对拼写错误有更好的鲁棒性
- 适合处理形态丰富的语言
获取子词信息
subwords = fasttextmodel.wv.getsubwords('unhappiness')
print("Subwords for 'unhappiness':", subwords)
词嵌入的应用
1. 语义相似度计算
# 计算词语间的余弦相似度
from sklearn.metrics.pairwise import cosinesimilarity
def calculatesimilarity(model, word1, word2):
vec1 = model.wv[word1].reshape(1, -1)
vec2 = model.wv[word2].reshape(1, -1)
similarity = cosinesimilarity(vec1, vec2)[0][0]
return similarity
测试语义相似度
similarity = calculatesimilarity(model, "king", "queen")
print(f"Similarity between 'king' and 'queen': {similarity:.4f}")
向量运算演示
kingvector = model.wv['king']
manvector = model.wv['man']
womanvector = model.wv['woman']
result = kingvector - manvector + womanvector
mostsimilar = model.wv.similarbyvector(result, topn=1)[0]
print(f"'king - man + woman' is most similar to: {mostsimilar[0]}")
2. 情感分析
# 基于词嵌入的情感分类
from sklearn.linearmodel import LogisticRegression
from sklearn.modelselection import traintestsplit
import numpy as np
假设我们有带标签的数据
Xtrain = [...] # 训练文本的词向量平均
ytrain = [...] # 对应的情感标签
训练分类器
classifier = LogisticRegression()
classifier.fit(Xtrain, ytrain)
预测新文本
def predictsentiment(text, model, classifier):
words = text.lower().split()
vectors = [model.wv[word] for word in words if word in model.wv]
if len(vectors) == 0:
return "neutral"
avgvector = np.mean(vectors, axis=0).reshape(1, -1)
prediction = classifier.predict(avgvector)[0]
return prediction
3. 命名实体识别
# 结合词嵌入的NER系统
def extractentities(text, model):
words = text.split()
entities = []
for i, word in enumerate(words):
# 检查是否为命名实体
if word in model.wv:
# 使用上下文信息判断
contextscore = calculatecontextsimilarity(words, i, model)
if contextscore > threshold:
entities.append({
'word': word,
'position': i,
'confidence': contextscore
})
return entities
实践建议与最佳实践
1. 选择合适的算法
| 场景 | 推荐算法 |
|------|----------|
| 大规模语料库 | Word2Vec |
| 需要处理OOV词 | FastText |
| 精确捕捉全局统计信息 | GloVe |
| 小数据集 | Skip-gram |
2. 超参数调优
```python
网格搜索调优示例
from sklearn.modelselection import ParameterGrid
param
grid = {'vectorsize': [50, 100, 200],
'window': [3, 5, 7],
'mincount': [1, 2, 5],
'sg': [0, 1] # 0: CBOW, 1: Skip-gram
}