用Gensim玩转Word2Vec:从《三国演义》人物关系看词向量有多准
用Gensim玩转Word2Vec:从《三国演义》人物关系看词向量有多准
翻开《三国演义》,那些纵横捭阖的英雄人物仿佛跃然纸上。但你是否想过,诸葛亮和刘备的君臣情谊、曹操与司马懿的微妙关系,其实可以用数学向量精确刻画?今天我们就用Gensim的Word2Vec模型,带你在古典文学中体验现代自然语言处理的魔力。
1. 准备工作:当NLP遇见四大名著
在开始之前,我们需要明确一个核心概念:词向量本质上是用数字表示词语的"数学身份证"。传统方法像给每个词分配一个独立编号(如诸葛亮=001,刘备=002),而Word2Vec则像绘制"人物关系地图"——通过大量文本分析,将语义关系编码成多维空间中的坐标。
所需工具包:
import jieba import re from gensim.models import Word2Vec import matplotlib.pyplot as plt import numpy as np from sklearn.decomposition import PCA提示:建议使用
jieba的精确分词模式,避免"诸葛亮"被错误拆分为"诸葛"和"亮"
2. 文本预处理:给古典文学做"分词手术"
《三国演义》原文包含大量文言表达和特殊符号,我们需要先进行清洗:
- 去除所有标点符号和特殊字符
- 处理连续书名号(如《《三国演义》》)
- 过滤单字词(文言虚词"之"、"乎"等)
典型预处理代码:
def clean_text(text): # 移除特殊符号 text = re.sub(r'[^\w\s]', '', text) # 处理嵌套书名号 text = text.replace('《', '').replace('》', '') return text with open("sanguo.txt", 'r', encoding='utf-8') as f: processed_lines = [] for line in f: words = [word for word in jieba.lcut(clean_text(line)) if len(word) > 1 and not word.isdigit()] if words: processed_lines.append(words)3. 模型训练:构建人物关系的"向量宇宙"
Word2Vec有两个经典算法选择:
| 算法类型 | 适用场景 | 三国演义案例表现 |
|---|---|---|
| Skip-gram | 小规模数据 | 能更好捕捉"诸葛亮-刘备"等稀有组合 |
| CBOW | 大规模数据 | 对常见组合如"曹操-丞相"处理更快 |
我们选择更适配文学作品的参数组合:
model = Word2Vec( processed_lines, vector_size=100, # 更高维度保留更多关系细节 window=5, # 扩大上下文窗口捕捉长距离关系 min_count=2, # 保留出现2次以上的人物 sg=1, # 选用Skip-gram epochs=20 # 增加迭代次数 )参数调优技巧:
vector_size=100:人物关系复杂度需要更高维度window=5:文言文中人物关系常跨句子epochs=20:古典文学需要更多训练轮次
4. 关系验证:用向量做"三国版"人物推理
现在进入最有趣的部分——用数学验证文学关系。我们先看基础查询:
# 查询与诸葛亮最相关人物 print(model.wv.most_similar('诸葛亮', topn=5))预期输出应包含:刘备、庞统、周瑜等
进阶关系推理:
# 类比推理:刘备之于诸葛亮,相当于曹操之于? # 即:刘备 - 诸葛亮 + 曹操 ≈ ? analogy = model.wv.most_similar( positive=['曹操', '诸葛亮'], negative=['刘备'], topn=3 )这个计算会返回司马懿、郭嘉等谋士,验证了模型的语义理解能力。
5. 可视化:绘制人物关系的"星图"
将高维向量降维到2D平面,可以直观展示人物集群:
# 提取前100个人物向量 words = model.wv.index_to_key[:100] vecs = [model.wv[word] for word in words] # PCA降维 pca = PCA(n_components=2) coords = pca.fit_transform(vecs) # 绘制核心人物 fig, ax = plt.subplots(figsize=(12, 8)) for i, word in enumerate(words): if word in ['刘备', '曹操', '孙权', '诸葛亮', '司马懿']: ax.scatter(coords[i,0], coords[i,1], c='red') ax.text(coords[i,0]+0.1, coords[i,1]+0.1, word, fontsize=12)典型聚类结果:
- 蜀汉集团:刘备、诸葛亮、关羽、张飞
- 曹魏集团:曹操、司马懿、夏侯惇
- 东吴集团:孙权、周瑜、陆逊
6. 实战挑战:你能发现这些隐藏关系吗?
让我们设计几个趣味测试,验证模型对复杂关系的捕捉:
挑战1:家族关系识别
# 关羽与关平、关兴的关系强度 print(model.wv.similarity('关羽', '关平')) print(model.wv.similarity('关羽', '关兴'))挑战2:敌对关系验证
# 诸葛亮与司马懿的"对立"程度 print(1 - model.wv.similarity('诸葛亮', '司马懿'))挑战3:职位关联分析
# 找出与"丞相"职位最相关的3个人物 print(model.wv.most_similar('丞相', topn=3))7. 模型优化:让理解更贴近原著
原始结果可能存在的不足:
- 将"曹操"和"曹丕"混淆
- 低估"吕布"与多个势力的关系
- 忽略"赵云"与"刘备"的亲密程度
改进方案:
- 添加人物别名映射(如孔明=诸葛亮)
- 调整窗口大小捕捉长距离依赖
- 引入章节权重(重点战役章节加倍计数)
优化后的模型能更准确反映:
- 吕布与董卓、貂蝉的特殊关系
- 赵云在长坂坡的单骑救主
- 诸葛亮的"卧龙"别称关联
在完成所有分析和实验后,最让我惊讶的是模型竟然自动发现了"既生瑜何生亮"的宿敌关系——周瑜和诸葛亮的向量夹角明显大于常规文臣武将。这种非监督学习捕捉到的微妙关系,正是词向量技术的迷人之处。下次你可以试试用《红楼梦》训练模型,看看宝黛钗的关系是否符合你的文学理解。
