Viterbi 算法直接用在中文分词上

📅 2026/7/9 16:29:34 👁️ 阅读次数 📝 编程学习
Viterbi 算法直接用在中文分词上

我们把 Viterbi 算法直接用在中文分词上,用你熟悉的“字”和“词”来解释,保证比天气例子更贴近你的直觉。

🧩 中文分词的核心问题

中文没有空格,比如:

“我爱北京天安门”

人类知道这是:

“我 / 爱 / 北京 / 天安门”

但计算机看到的是一串字:

[我, 爱, 北, 京, 天, 安, 门]

怎么切?

🔑 关键思想:把分词变成“给每个字打标签”

我们用 4 种标签(状态) 表示每个字在词中的位置:

标签 含义 例子

B Begin(词的开头) “北” in “北京” → B

M Middle(词的中间) “安” in “天安门” → M

E End(词的结尾) “京” in “北京” → E

S Single(单字成词) “我”、“爱” → S

所以,“我爱北京天安门”的正确标签序列是:

我 爱 北 京 天 安 门

S S B E B M E

✅ 一旦有了这个标签序列,分词就很简单:

- 遇到 S → 单独一个字;

- 遇到 B...E → 从 B 到 E 是一个词。

🤖 那么问题转化为:

给定一串字(观测序列),

找出最可能的标签序列(隐藏状态序列)。

这正是 HMM + Viterbi 要解决的问题!

📚 HMM 的三个参数(从语料库学来的)

1. 初始概率 π:句子第一个字是 B/M/E/S 的概率

- 实际中:第一个字不可能是 M 或 E(因为词还没开始!)

所以:P(S) ≈ 0.7, P(B) ≈ 0.3, P(M)=P(E)=0

2. 转移概率 A:标签之间怎么跳?

比如:

- B 后面只能接 M 或 E(不能接 B 或 S)→ P(M|B)=0.6, P(E|B)=0.4

- M 后面只能接 M 或 E → P(M|M)=0.5, P(E|M)=0.5

- S 后面可以接 B 或 S → P(B|S)=0.8, P(S|S)=0.2

- E 后面可以接 B 或 S

3. 发射概率 B:某个标签下出现某个字的概率

比如:

- 字“北”在 B 状态的概率很高(因为常出现在词首);

- 字“京”在 E 状态的概率很高;

- 字“我”在 S 状态的概率极高。

这些概率都是通过大量标注好的语料(如人民日报语料库)统计出来的。

🧪 举个真实分词例子

句子:“研究生命”

可能的切分有歧义:

- “研究 / 生命” → 正确

- “研 / 究生 / 命” → 错误但可能(如果模型没见过“研究”)

我们用 Viterbi 来选!

第一步:列出所有字(观测)

[研, 究, 生, 命]

第二步:Viterbi 动态规划(简化版)

我们不列全部计算,只看关键逻辑:

- “研” 很少单独成词 → 不太可能是 S

- “究” 几乎不会在词首 → 不太可能是 B

- 但“研究”是一个高频词 → 所以“研=B, 究=E” 的组合概率很高

- “生命”也是高频词 → “生=B, 命=E”

而“研究生”虽然存在,但在这个上下文中,“研究/生命”整体路径概率更高。

Viterbi 会计算所有合法标签序列(如 B E B E, S B M E, B M E S 等),

但只保留每一步概率最大的路径,最后选出:

研 究 生 命

B E B E

→ 切分为:“研究 / 生命”

⚠️ 注意:Viterbi 只能选“模型认为概率最大”的路径

如果训练语料里“研究生”出现太多,“研究”太少,

它可能会错切成:“研 / 究生 / 命”(即 S B E S)。

这就是为什么:

- 语料质量很重要;

- 纯 HMM 分词效果有限(所以 jieba 等工具先用词典,HMM 只处理未登录词)。

✅ 总结:Viterbi 在分词中的角色

步骤 说明

输入 一串汉字(如“北京大学”)

隐藏状态 每个字的标签(B/M/E/S)

Viterbi 干什么 在所有合法标签序列中,找出联合概率最大的那一条

输出 标签序列 → 转为分词结果

💡 它就像一个“最合理的故事生成器”:

“哪个切分方式最符合我们从语料中学到的语言习惯?”

🛠️ 补充:实际工程中怎么做?

像 jieba 分词 的流程是:

1. 先用词典 + DAG + 动态规划切分已知词;

2. 对词典里没有的部分(如“大玩学城”),才用 HMM + Viterbi 来猜;

3. 这样既快又准。