📖 一句话说清全文:从中文分词到词向量,NLP 早期技术的核心逻辑就是——让机器从「认识字」进化到「理解语义」。本文 10 章,由浅入深讲透原理、公式、面试考点和工业落地。
📋 本文目录
| 章节 | 内容 | 难度 |
|---|---|---|
| 一 | 中文分词基础 & 词表匹配算法 | 🟢 |
| 二 | 分词 DAG 有向无环图 | 🟡 |
| 三 | TF-IDF & BM25 核心原理(附公式推导 + 实例) | 🟡🔴 |
| 四 | TF-IDF 工业落地应用 | 🟢 |
| 五 | TF-IDF vs BM25 优缺点对比 | 🟡 |
| 六→七 | 从 One-Hot 到 Word2Vec 演进 | 🟡 |
| 八 | 神经概率语言模型(理论基石) | 🔴 |
| 九 | 静态词向量核心痛点 | 🟡 |
| 十 | 延伸:句向量 & K-Means 聚类 | 🟢🟡 |
一、中文分词基础与词表匹配算法 🟢
1.1 中文分词基础概述
🎯 面试官会问:中文 NLP 和英文 NLP 最大的处理差异是什么?
2018 年某电商搜索「南京市长裙」,返回了大量「南京市 + 长江大桥」的图片。因为分词器把「南京市长」切出来了——一次分词事故,直接导致关键词匹配翻车。
中文和英文最大的区别就在这:英文单词自带空格,中文是一大坨汉字糊你脸上,你自己切。
英文: I / love / natural / language / processing
中文: 我爱自然语言处理 → 我 / 爱 / 自然语言 / 处理
分词就是把连续中文文本切成独立有语义的词语。它是所有中文 NLP 任务的前置必经步骤——检索、分类、情感分析,谁都绕不开。
两大硬难点:
| 难点 | 说明 | 经典翻车现场 |
|---|---|---|
| 😵 歧义切分 | 同一段话有多个合法切法 | 南京市长江大桥 → 南京市长/江大桥?南京市/长江大桥? |
| 🤯 新词识别 | 网络热词随时冒,词表永远追不上 | 绝绝子、大模型、RLHF、遥遥领先 |
🕳 踩坑实录:某新闻 App 上线分词后,「特朗普」被切成「特/朗/普」三个单字,热搜榜直接崩了。最后发现词表里没这个词。
工业现状:几乎没人自己手写。业务直接上结巴(jieba) 等开源工具,好使不折腾。传统分词算法更多是面试考点——工程谁自己写谁加班 😅
1.2 基于词表的分词算法
全部依赖词表做匹配,最经典的是正向最大匹配法(FMM)。
核心逻辑:从左往右扫,先挑最长的下手——吃自助餐先拿最大的盘子 🍽️
词表: ["南京", "南京市", "市长", "长江", "长江大桥", "大桥"]
文本: "南京市长江大桥"
第 1 轮:取"南京市长江大"→ 无 → 缩短 → "南京市长江"→ 无 → ...
直到 "南京市" → 命中!切出 ✅
第 2 轮:从"长江大桥"继续 → "长江大桥" → 命中!切出 ✅
结果:南京市 / 长江大桥 ✅
🤔 思考题:如果词表里同时有「南京」和「南京市」,FMM 会优先切哪个? A. 南京(短的) B. 南京市(长的) C. 看词表顺序 👇 评论区告诉我答案
| ✅ 优点 | ❌ 缺点 |
|---|---|
| 逻辑简单,10 行代码搞定 | 看词表脸色——词表拉胯一切拉胯 |
| 实现零门槛 | 缺词或歧义立刻翻车 |
前缀字典优化:给前缀打标记,0=仅前缀,1=完整词。不用反复回退,直接跳。
"长江大桥" 的前缀标记:
长→0 长江→1 长江大→0 长江大桥→1
↑
命中就切,不等了
全切分(🔥高频考点):给定词表,枚举文本所有合法切分方式。
输入:文本"abc",词表 {a, ab, bc, c}
输出:["a/bc", "ab/c"] ← 枚举所有合法路径
没有词表就没有全切分。本质考递归 + 回溯,面试官最爱 🎯
二、分词 DAG 有向无环图 🟡
DAG 是结巴分词的底层核心数据结构。
原理:以每个汉字为节点,记录当前字往后能构成合法词的所有终点位置。
文本:南京市长江大桥
DAG 图结构:
0(南): → 1(京) → 2(市) # "南京"、"南京市"
1(京): → 2(市) # "京市"(单字)
2(市): → 3(长) → 5(大) # "市长"
3(长): → 4(江) → 6(桥) # "长江"、"长江大桥"
4(江): → 5(大) → 6(桥) # "江大桥"
5(大): → 6(桥) # "大桥"
6(桥): # 终点
完整流程:
① 遍历文本,逐字查词表
② 每个字作起点,记录可达的终点下标
③ 建图后遍历所有路径 → 穷举全部分词结果
④ 动态规划选最优路径
DAG 是全切分的高效底层支撑——没有 DAG,结巴就是散沙 🏖️
三、TF-IDF 与 BM25 算法核心原理 🟡🔴
3.1 TF-IDF 核心原理(附公式 + 手算实例)
🎯 面试官会问:TF-IDF 的 IDF 为什么要取 log?如果文档集只有一篇文章怎么办?
TF-IDF = TF(词频) × IDF(逆文档频率)
一句话:一个词在本文出现多 + 在其他文档出现少 = 核心关键词。
完整公式链:
| 符号 | 含义 | 直觉 |
|---|---|---|
| 词 在文档 中出现次数 | 这个我说了多少遍 | |
| 文档总词数 | 归一化,不被长文欺负 | |
| 文档总数 | 全局视野 | |
| 含 的文档数 | 这词到底有多通用 | |
| 平滑项 | 防止 log(0) |
手算一笔账 📊:
文档集 D = {doc1, doc2, doc3, doc4, doc5}
词 "NLP" 在各文档的词频:
doc1: 3次/100词 doc2: 0次/80词
doc3: 5次/200词 doc4: 0次/120词
doc5: 2次/150词
TF("NLP", doc1) = 3/100 = 0.030
IDF("NLP", D) = log(5/(1+3)) = log(1.25) ≈ 0.223
TF-IDF = 0.030 × 0.223 ≈ 0.0067 ✅
对比停用词「的」:
TF("的", doc1) = 15/100 = 0.150 ← 词频超高
IDF("的", D) = log(5/(1+5)) = log(0.83) ≈ -0.079 ← 到处都有,IDF 极低
TF-IDF = 0.150 × (-0.079) ≈ -0.012 ❌ → 直接过滤掉
| TF-IDF | TF | IDF | 得分 |
|---|---|---|---|
| "NLP" | 0.030 | 0.223 | 0.0067 ✅ |
| "的" | 0.150 | -0.079 | -0.012 ❌ |
这就是为什么停用词天然被压——不是刻意过滤,是数学决定的 🧮
💡 原理:IDF 取 log 是基于「信息量」的直觉——一个词在越少文档中出现,携带的信息量越大。log 让分值增长变平滑,不至于某个稀有词一枝独秀。
3.2 BM25 算法核心原理(附公式 + 双栏对比)
BM25 = TF-IDF 的进化版。TF-IDF 是自行车,BM25 是电动车 🚲→🛵
核心公式:
BM25 的 IDF 变体(做过饱和处理):
| 参数 | 含义 | 默认值 | 调大后果 |
|---|---|---|---|
| 词频饱和控制 | 1.2~2.0 | 高频词影响力↑ | |
| 长度归一化强度 | 0.75 | 长文档惩罚↑ |
TF-IDF vs BM25 双栏对比:
📌 TF-IDF 📌 BM25
─────────────────────────────────────────────────────
score = TF × IDF score = Σ IDF · TF_sat
无词频饱和 → 高频词无脑膨胀 有词频饱和 → 边际收益递减
无长度归一 → 长文档天然高分 长度归一 → 公平竞争
无超参可调 k₁、b 双旋钮适配场景
效果:凑合用 效果:行业标配 ✅
BM25 的直觉:同样一个词,出现 100 次 ≠ 出现 2 次的 50 倍重要。刷票无效,边际递减 📉
词频 TF-IDF 得分 BM25 得分
────────────────────────────
2次 2 × IDF 2 × IDF × 系数 ≈ 正常
10次 10 × IDF ≈ 5倍 被分母压住 ≈ 2.5倍
100次 100 × IDF = 50倍 几乎饱和 ≈ (k₁+1) 倍 ≈ 锁死
🕳 踩坑实录:某搜索服务用 TF-IDF 做召回,一篇 5000 字长文反复堆砌关键词,排名常年第一。接入 BM25 后,该文章直接掉到第 7 页——专业作弊 vs 专业反作弊 🤣
四、TF-IDF 工业落地应用 🟢
| 场景 | 做法 | 一句话 |
|---|---|---|
| 🔑 关键词提取 | 统计 TopK | 「老板给我提炼行业关键词」→ 跑一下 |
| 🔍 简易搜索 | 预计算 TF-IDF,Query 分词后排序 | 2000 年的 Google 就这样 😂 |
| 📝 抽取式摘要 | 算单句平均分,取 Top 拼接 | 丐版自动摘要,但真的好使 |
| 📊 相似度计算 | 词频向量 + 余弦公式 | 查重、推荐都靠它 |
余弦相似度公式:
比如两篇文章的词频向量夹角为 15°,——高度相似 ✅
五、TF-IDF 优缺点及 BM25 改进 🟡
5.1 TF-IDF 优缺点
| ✅ 优点 | ❌ 缺点 |
|---|---|
| 可解释性强——每个词都能追溯 | 分词崩了它就崩 |
| 计算飞快,CPU 就够 | 同义词?不认识。「苹果」和「apple」是两个词 🍎 |
| 无需标注 | 没词序——「我打你」=「你打我」 |
| 可组合复用 | 换领域重算 |
| 成本≈一杯奶茶钱 | 长文档天生占便宜 |
5.2 BM25 改进(公式对比)
原始 TF vs BM25 饱和 TF:
当 : — 高频词得分被硬上限锁死 🔒
当 :分母增大 — 长文档被压制 ⚖️
BM25 改进总结:
✅ 文档长度归一化 → 公平竞技
✅ 词频饱和压制 → 禁止刷榜
✅ 可调超参数 → 适配不同场景
✅ 全面替代 TF-IDF → 行业召回标配
🤔 思考题:极端情况——如果 ,BM25 退化成什么? A. TF-IDF B. 纯词频模型 C. 还是 BM25 提示: 意味着「完全不考虑文档长度」
六、从文本雏形到词向量演进 🟡
6.1 One-Hot 编码
每个词对应稀疏向量,只有一个位置是 1:
它有多离谱 🤦♂️:
"猫" = [1, 0, 0, 0, ..., 0]
"狗" = [0, 1, 0, 0, ..., 0]
"猫" · "狗" = 0 → 内积为 0 → 完全不相关???
| 缺陷 | 说明 |
|---|---|
| 维度 = 词表大小 | 10 万词 → 10 万维,稀疏到爆炸 |
| 零语义 | 「苹果」「iPhone」「水果」互相正交 |
| 零扩展性 | 加个新词就得加一维 |
6.2 文本向量化核心目标
6.3 Word Embedding
Embedding = 查找表:
One-Hot "NLP" × Embedding矩阵 = Embedding["NLP"]
[0,0,1,0] [w11 w12 w13] [w31 w32 w33]
[w21 w22 w23]
[w31 w32 w33] ← 查表第 3 行
[w41 w42 w43]
等价于:直接查表 ✅
这是面试高频题:「One-Hot 乘 Embedding 矩阵,到底是不是矩阵乘法?」答案是:数学上是,工程上是查表。
6.4 词向量训练逻辑
① 随机初始化 Embedding
② 设计预训练任务(预测下一个词)
③ 计算损失 → 梯度下降 → 更新 Embedding
④ 重复到收敛
核心靠语言模型自回归:挖掉一个词让模型猜。猜对了就学到语义——学的是词,猜的是上下文,练的是向量 🧠
七、词向量经典训练框架 🟡
Word2Vec 三大训练方式:
| 方法 | 原理 | 一句话 |
|---|---|---|
| ⏩ Skip-Gram | 中间词→猜上下文 | 给「苹果」猜「很好吃」🍎 |
| ⏪ CBOW | 上下文→猜中间词 | 完形填空:「_很好吃」→猜「苹果」 |
| 🌐 GloVe | 全局词共现概率比 | 全图视角看词与词的关系 |
核心超参 🔧:
- 窗口大小:看多远的朋友圈(默认 5)
- 词频过滤:太生僻的词不要(默认 min_count=5)
- 向量维度:128 够用,256 更好,512 真香
- 迭代轮数:欠拟合 vs 过拟合的博弈
八、神经概率语言模型 🔴(NLP 理论基石)
🎯 大厂面试:2003 年 Bengio 的 NNLM 论文解决了什么核心问题?
2003 年 Bengio 经典论文 NNLM——NLP 深度学习开山之作 🔥
核心贡献:
① 首次将神经网络 + 语言模型结合
② 提出「词分布式表示」= 今天的词向量
③ 解决传统 n-gram 的稀疏性和泛化性差
n-gram 的死穴:
句子:「我在 798 看了一场 ____ 展览」
n-gram 见过"看了一场画展" → 能猜"画展"
但没见过"看了一场装置艺术展" → 猜不出 ❌
NNLM 知道"装置艺术"和"画"是类似语境 → 能猜 ✅
这就是词向量的革命性——相似词聚在一起,没见过的组合也能推 🧠
九、静态词向量的核心痛点 🟡
| 痛点 | 表现 | 扎心实例 |
|---|---|---|
| 📉 无统一评价 | 只能靠下游验证 | 「这个向量好不好?」「跑一下分类」 |
| 🔀 一词多义 | 同词不同语境向量不变 | 「苹果很好吃」vs「苹果发新机」→ 向量一样 🍎📱 |
| 🔄 反义词尴尬 | 同语境,向量接近 | 「好」和「坏」距离≈0 |
| 🔃 不对称 | A 最似B ≠ B 最似A | 「医生」最似「护士」,「护士」最似「患者」 |
这些痛点催生了 ELMo、BERT——动态词向量,但那是另一个故事了
十、延伸拓展知识点 🟢🟡
10.1 句向量构建方式
| 方案 | 说明 | 评价 |
|---|---|---|
| 🏆 词向量平均 | 全句词向量取平均 | 最笨但最好使,基线首选 |
| 🔧 CNN/RNN 池化 | 卷积或循环网络提取 | 有参数能学,但得训练 |
| 💰 预训练编码 | BERT/GPT 直接出 | 效果最好,也最贵 |
10.2 K-Means 无监督聚类
目标函数(最小化类内距离):
流程:
① 指定 K 值(我要聚几堆?)
② 随机挑 K 个点当老大(质心)
③ 剩下的投奔最近的老大(分配)
④ 老大重算中心(更新)
⑤ 重复③④→老大不动了→收敛 ✅
| ✅ 优点 | ❌ 缺点 |
|---|---|
| 快——10 万条秒级 | K 值靠猜——「聚 5 类还是 8 类?」 |
| 不用标注 | 初始质心选不好,结果天差地别 |
| 简单好理解 | 离群点一个带崩全局 |
💎 全文总结
从分词到词向量的演进逻辑:
分词 → 让机器知道"词在哪里" TF-IDF/BM25 → 让机器知道"哪些词重要" One-Hot/Word2Vec → 让机器知道"词是什么意思"这些技术到今天依然是工业落地的基石,也是大厂面试的必考点。老祖宗的东西,学就完事了 💪
互动题答案 👇
- Q1(FMM 优先切哪个):B. 长的 → 所以词表里「南京市」排在「南京」前面不影响 FMM 结果
- Q2(b=0 退化):B. 长度归一化被关闭,只剩词频饱和逻辑,不再是标准 BM25
文中所有翻车案例均为真实改编,如有雷同,说明你也遇到过 😅