阶段2 | NLP传统 · 第12课/共30课

📖 第12课:词相似度与类比

🎯 课程目标

词向量的核心价值在于编码了语义关系。本课深入探索词相似度计算和词类比的数学原理与实际应用。

📐 核心原理

相似度度量方法

词类比原理

vec(b) - vec(a) ≈ vec(d) - vec(c) 意味着 a:b = c:d

求解 d ≈ argmax cos(vec(d), vec(b) - vec(a) + vec(c))

💡 类比的本质:词向量的某些维度编码了语义属性(性别、时态、国家-首都关系),这些维度的差向量在不同词对间是平行的。

🔬 词相似度与类比实验

相似度计算与词类比

from gensim.models import Word2Vec import numpy as np sentences = [ ['国王', '女王', '男人', '女人', '王子', '公主', '皇帝', '皇后'], ['中国', '北京', '法国', '巴黎', '日本', '东京', '美国', '华盛顿'], ['苹果', '香蕉', '水果', '蔬菜', '西红柿', '黄瓜'], ['汽车', '火车', '飞机', '交通', '出行', '轮船'], ['猫', '狗', '宠物', '动物', '鱼', '鸟'], ['大学', '学院', '学校', '教育', '学生', '老师'], ['医生', '医院', '病人', '治疗', '健康', '护士'], ['程序员', '代码', '计算机', '软件', '开发', '测试'], ['自然', '语言', '处理', '人工智能', '深度', '学习', '机器', '训练'], ['开心', '快乐', '悲伤', '难过', '愤怒', '生气'], ] model = Word2Vec(sentences, vector_size=100, window=5, min_count=1, sg=1, epochs=300, seed=42) # 词相似度计算 print("=== 余弦相似度 ===") def cosine_sim(v1, v2): return np.dot(v1, v2) / (np.linalg.norm(v1) * np.linalg.norm(v2) + 1e-8) word_pairs = [ ('国王', '女王'), ('国王', '男人'), ('国王', '苹果'), ('中国', '北京'), ('中国', '法国'), ('开心', '快乐'), ('猫', '狗'), ('猫', '汽车'), ] for w1, w2 in word_pairs: if w1 in model.wv and w2 in model.wv: sim = model.wv.similarity(w1, w2) cos = cosine_sim(model.wv[w1], model.wv[w2]) print(f" sim('{w1}', '{w2}') = {sim:.4f} (cosine={cos:.4f})") # 词类比 print("\n=== 词类比实验 ===") analogies = [ (['女王', '男人'], ['国王'], '女王 - 国王 + 男人 = ?'), (['巴黎', '日本'], ['法国'], '巴黎 - 法国 + 日本 = ?'), (['公主', '男人'], ['女王'], '公主 - 女王 + 男人 = ?'), ] for positive, negative, desc in analogies: try: results = model.wv.most_similar(positive=positive, negative=negative, topn=3) print(f" {desc} → {[(w, f'{s:.3f}') for w, s in results]}") except Exception as e: print(f" {desc} → 错误: {e}") # 不匹配词检测 print("\n=== 不匹配词检测 ===") test_sets = [ ['苹果', '香蕉', '汽车', '水果'], ['国王', '女王', '北京', '公主'], ['猫', '狗', '鱼', '程序'], ] for ws in test_sets: try: odd = model.wv.doesnt_match(ws) print(f" {ws} → 不匹配: {odd}") except: pass
=== 余弦相似度 === sim('国王', '女王') = 0.9272 (cosine=0.9272) sim('国王', '男人') = 0.9250 (cosine=0.9250) sim('国王', '苹果') = 0.8627 (cosine=0.8627) sim('中国', '北京') = 0.9167 (cosine=0.9167) sim('中国', '法国') = 0.9362 (cosine=0.9362) sim('开心', '快乐') = 0.8559 (cosine=0.8559) sim('猫', '狗') = 0.9004 (cosine=0.9004) sim('猫', '汽车') = 0.8427 (cosine=0.8427) === 词类比实验 === 女王 - 国王 + 男人 = ? → [('美国', '0.889'), ('皇帝', '0.888'), ('皇后', '0.886')] 巴黎 - 法国 + 日本 = ? → [('处理', '0.922'), ('美国', '0.919'), ('中国', '0.904')] 公主 - 女王 + 男人 = ? → [('皇帝', '0.913'), ('女人', '0.904'), ('日本', '0.902')] === 不匹配词检测 === ['苹果', '香蕉', '汽车', '水果'] → 不匹配: 苹果 ['国王', '女王', '北京', '公主'] → 不匹配: 北京 ['猫', '狗', '鱼', '程序'] → 不匹配: 猫

✅ 验证通过:代码实机运行结果如上

🔧 语义维度分析

语义维度与距离矩阵

from gensim.models import Word2Vec import numpy as np # 更细致的语义关系分析 sentences = [ ['走路', '跑', '快', '慢', '速度'], ['大', '小', '多', '少', '高', '低'], ['热', '冷', '温暖', '寒冷', '温度'], ['好', '坏', '美', '丑', '善', '恶'], ['男', '女', '父', '母', '兄', '妹'], ['春天', '夏天', '秋天', '冬天', '季节'], ['东', '西', '南', '北', '方向'], ['金', '木', '水', '火', '土', '五行'], ] model = Word2Vec(sentences, vector_size=50, window=3, min_count=1, sg=1, epochs=300, seed=42) # 分析语义维度 print("=== 语义维度分析 ===") pairs = [('大', '小'), ('热', '冷'), ('好', '坏'), ('男', '女'), ('多', '少')] for w1, w2 in pairs: if w1 in model.wv and w2 in model.wv: diff = model.wv[w1] - model.wv[w2] top_dims = np.argsort(np.abs(diff))[-3:][::-1] print(f" {w1}-{w2}: 差异最大的维度={top_dims}, 差异值={diff[top_dims]}") # 语义距离矩阵 words = ['大', '小', '多', '少', '高', '低'] valid = [w for w in words if w in model.wv] print("\n=== 语义距离矩阵 ===") print(f"{'':6s}", end='') for w in valid: print(f"{w:8s}", end='') print() for w1 in valid: print(f"{w1:6s}", end='') for w2 in valid: if w1 in model.wv and w2 in model.wv: d = 1 - model.wv.similarity(w1, w2) print(f"{d:8.4f}", end='') print()
=== 语义维度分析 === 大-小: 差异最大的维度=[12 29 38], 差异值=[-0.03537961 0.03527084 0.03492232] 热-冷: 差异最大的维度=[23 18 8], 差异值=[-0.03221278 -0.03215672 -0.03150955] 好-坏: 差异最大的维度=[42 35 20], 差异值=[ 0.03422321 -0.03123304 0.03119101] 男-女: 差异最大的维度=[37 31 39], 差异值=[ 0.03968447 0.03228967 -0.02758653] 多-少: 差异最大的维度=[33 0 15], 差异值=[-0.03745282 -0.03476805 -0.03363804] === 语义距离矩阵 === 大 小 多 少 高 低 大 0.0000 0.7405 0.6186 0.5078 0.9321 0.8678 小 0.7405 0.0000 0.5166 0.6978 0.6224 0.7458 多 0.6186 0.5166 0.0000 0.7513 0.8488 0.8598 少 0.5078 0.6978 0.7513 0.0000 0.6682 0.6982 高 0.9321 0.6224 0.8488 0.6682 0.0000 0.7435 低 0.8678 0.7458 0.8598 0.6982 0.7435 0.0000

✅ 验证通过:代码实机运行结果如上

📝 练习

动手练习

  1. 实现欧氏距离和曼哈顿距离度量,与余弦相似度对比
  2. 设计10组中文词类比测试,评估不同词向量的准确率
  3. 分析词向量的不同维度各自编码了什么语义信息
🎯

🏆 成就解锁:语义测量师

掌握了词向量语义空间的量化评估方法,能精确测量词间关系。

📚 参考文献

推荐阅读

在线资源

词相似度 - 关键概念速查

概念定义应用
Pipeline处理流水线,各步骤串行执行文本处理系统
Tokenization将文本切分为词/子词单元分词、子词分割
Embedding将离散符号映射到连续向量空间词向量、句向量
Feature Engineering从原始数据提取有效数值特征传统ML模型输入
Fine-tuning在预训练模型基础上微调BERT等模型适配

本课要点回顾

  1. 词相似度是NLP技术栈的重要组件
  2. 理解原理比调用API更重要——知道为什么比知道怎么做更有价值
  3. 代码验证是学习的好方法——动手跑一遍胜过读十遍
  4. 从简单方法开始,逐步过渡到复杂方法——简单方法的基线作用不可替代
  5. 实践出真知——用自己的数据跑一遍,发现课本上没写的问题

❓ 常见问题FAQ

Q: 这个方法的数据需求量是多少?
A: 传统方法通常需要几百到几千条标注数据。深度学习方法通常需要万级以上。数据量少时优先用传统方法。
Q: 如何处理中文的特殊情况?
A: 中文没有天然词边界,分词质量直接影响下游效果。建议:1)使用领域词典优化分词 2)比较不同分词工具的效果 3)对关键任务做分词错误分析。
Q: 传统方法和深度学习如何选择?
A: 考虑三个因素:1)数据量——少数据用传统方法 2)可解释性——需要解释选传统方法 3)计算资源——资源受限选传统方法。深度学习在大数据+强算力场景下优势明显。
Q: 如何评估和调优?
A: 1)建立基线:用最简单方法确定性能下限 2)错误分析:找出模型最常犯的错误类型 3)针对性改进:根据错误模式选择改进策略 4)避免过拟合:在独立测试集上验证。
Q: 生产环境部署要注意什么?
A: 1)延迟要求:简单模型推理更快 2)吞吐量:批处理提升吞吐 3)模型版本:做好版本管理和回滚 4)监控:持续跟踪线上模型性能 5)A/B测试:新模型上线前小流量验证。

🛠️ 实用工具箱

工具用途安装
jieba中文分词pip install jieba
gensim词向量训练pip install gensim
scikit-learn传统MLpip install scikit-learn
nltk英文NLP工具pip install nltk
spaCy工业NLP管线pip install spacy
hanlp中文NLP工具包pip install hanlp
fasttextFacebook文本分类pip install fasttext
textblob简单NLP接口pip install textblob