查看全课大纲(第 15 / 69 节)
- 1.NLP 的研究领域、应用与学习路径
- 2.自然语言的基本术语
- 3.信息论基础:信息熵与交叉熵
- 4.语言的进化与语义变迁
- 5.主观概率、客观概率与条件概率
- 6.贝叶斯原理与推理
- 7.随机变量:二项式、期望方差与联合概率
- 8.常见概率分布
- 9.辛普森悖论与贝叶斯解题实例
- 10.语言模型:语言概率与词袋模型
- 11.n-gram 语言模型(二元 / 三元 / N-Gram)
- 12.语言模型评价:交叉熵、困惑度与插值
- 13.朴素贝叶斯文本分类:垃圾邮件
- 14.拼写检查
- 15.中文分词:构词法、最大匹配、最优路径与 Jieba
- 16.词表示问题与语义相似度
- 17.TF-IDF 权重处理
- 18.One-Hot 表达与词表示的局限
- 19.Word2Vec 核心思想
- 20.Word2Vec 训练过程
- 21.Skip-gram 模型详解
- 22.词性标注任务与标注方法(规则 + N-Gram)
- 23.EM 算法与混合模型
- 24.高斯混合模型 GMM
- 25.从混合模型到隐马尔可夫模型
- 26.隐马尔可夫模型(HMM)推导与维特比解码
- 27.线性链条件随机场 CRF
- 28.贝叶斯网络与图模型
- 29.隐马尔可夫链与 HMM 推导
- 30.PLSA 主题模型
- 31.LSI 与 SVD 向量表达
- 32.LDA 与狄利克雷分布
- 33.主题模型实验复现(困惑度 / 分类 / 相似度 / 延展)
- 34.上下文无关文法(CFG)与句法分析
- 35.概率上下文无关文法 PCFG
- 36.统计机器翻译:词对齐与翻译模型
- 37.统计机器翻译中的对齐模型与参数估计
- 38.从统计机器翻译到神经机器翻译
- 39.神经元与反向传播速览(指向深度学习课)
- 40.CNN 原理及其在 NLP 中的应用
- 41.循环神经网络的基本原理与 Elman / Jordan 网络
- 42.LSTM:长短期记忆网络的核心思想与分步实现
- 43.Encoder-Decoder 框架
- 44.Seq2Seq 与早期注意力机制
- 45.注意力机制的背景与动机
- 46.注意力模型实现原理与匹配函数
- 47.记忆网络:组成与计算
- 48.注意力机制的应用与历史延展
- 49.Transformer 结构:Encoder-Decoder 栈与 Self-Attention
- 50.Multi-Head Attention、FFNN 与位置编码
- 51.层归一化、损失函数与 Universal Transformer 延展
- 52.预训练范式:从 ELMo 到 BERT
- 53.BERT 与掩码语言模型
- 54.BERT 下游任务微调与 GLUE 口径
- 55.GPT 与自回归语言建模
- 56.GPT-1 到 GPT-4 的演进
- 57.指令微调与 RLHF
- 58.分词器:BPE、WordPiece 与中文词表
- 59.上下文窗口与长文本处理
- 60.能力边界、成本与适用场景
- 61.文本分类实战:从朴素贝叶斯到逻辑回归
- 62.命名实体识别实战
- 63.文本生成与摘要实战
- 64.语义检索与向量库实战
- 65.RAG 知识库问答
- 66.NLP 评估指标:BLEU / ROUGE / BERTScore 与人工评估
- 67.幻觉与事实性问题
- 68.文本与知识结合(知识图谱压缩)
- 69.跨媒体信息检索与未来展望
中文分词:构词法、最大匹配、最优路径与 Jieba
小象实战讲义 · 自然语言处理
在上一节我们探讨了语言模型在拼写纠错、语音识别等任务中的核心作用。然而,当我们面对中文文本时,一个更基础、更独特的问题首先浮现出来:如何将一串连续的汉字序列,切分成有意义的词语单元?这就是中文分词。本节我们将深入探讨中文构词法的复杂性,介绍几种经典的分词算法(最大匹配、最优路径),并学习如何使用成熟的工具(如 Jieba)进行实战分词。
💡 核心导读
- 中文构词法的独特性:理解中文在拼音、字形、语义上的复杂性,以及为何中文分词比英文更具挑战性。
- 分词标准与“先有鸡还是先有蛋”:认识分词任务中标准不统一的问题,以及如何通过“分词规范+词表+分词语料库”来定义可计算的词语。
- 经典分词算法:掌握基于词典的最大匹配算法(正向、反向、双向)及其局限性,理解将分词视为最优路径搜索的动态规划思想。
- 实用分词工具:学会使用 Python 的 Jieba 库进行中文分词,了解其基本用法和停用词处理。
中文构词法的挑战
在英文等以空格分隔单词的语言中,分词(Word Segmentation)问题相对简单。然而,中文文本是连续的字符流,词与词之间没有显式的分隔符。这仅仅是挑战的开始。
中文构词法(Chinese Morphology) 的复杂性体现在多个层面:
- 拼音同音异义:相同的拼音可能对应多个完全不同的词。例如,拼音
qing tian可能对应“晴天”、“青天”、“青田”(地名)、“清甜”等多个两音节候选。这给语音识别带来了巨大困难,因为英文中一个读音通常唯一对应一个单词(如student)。 - 字形与语义的关联与分离:中文汉字是表意文字,同一个“字”可能出现在不同词语中,含义既有联系又有区别。
- “机”字家族:“激光”(laser,受激辐射产生的光)、“激起”(arouse,刺激引起)、“飞机”(aeroplane,飞行机器)、“攻击”(attack)、“机枪”(machine gun)。这些词中的“机”在语义上或与“机器”相关,或已独立成词,关联性弱化。
- “鸡蛋”问题:“鸡”和“蛋”可以单独成词,也可以组合成“鸡蛋”这个复合词。这引出了分词领域著名的“先有鸡还是先有蛋”的哲学问题:是先正确分词才能更好地理解句子,还是先理解句子才能正确分词?
这些特性使得中文的形态分析(Morphology)比英文复杂得多,也直接导致了中文语音识别、机器翻译等任务面临更高的技术门槛。例如,早期将语音识别系统部署到广东法院时,因缺乏足够的方言训练语料,识别准确率远低于普通话场景。
分词标准:从模糊到可计算
既然人对“词”的界定都存在分歧(研究表明,不同人对同一文本的分词认同率平均只有 0.76 左右),计算机该如何处理?
早期,人们希望建立一个统一的“汉语大词典”作为分词标准。但很快发现,标准本身难以统一。例如:
- “我爱北京天安门”可以切分为
我|爱|北京|天安门,但也有人可能将“北京天安门”视为一个整体。 - 对于句子“李航空天天梦想去以空天信为主要强项的北京航空航天大学学习航空航天。”,至少有两种合理的切分:
李航空|天天|梦想|去|以|空天信|为|主要|强项|的|北京航空航天大学|学习|航空|航天。李航空|天天|梦想|去|以|空天信|为|主要|强项|的|北京|航空航天|大学|学习|航空航天。
哪种正确?关键在于遵循哪种分词规范。
国际中文分词评测 Bakeoff 采用了一种务实的思路:不再追求单一标准,而是提供多种遵循不同规范(如北大标准、微软亚洲研究院标准等)的分词语料库。每个语料库都通过“分词规范 + 词表 + 人工标注”的方式,为计算机提供了可计算的词语定义。参评系统可选择一种或多种标准语料库,评测按语料库及封闭/开放测试分别报告指标;如需跨标准汇总,应另行明确平均口径,并非一律取跨标准平均性能。研究表明,基于这种可计算定义训练出的不同分词系统之间,词语平均认同率高达 0.90,远高于人之间的 0.76。这标志着中文词语的定义从模糊走向了规范化。
经典分词算法
基于词典的最大匹配法
最大匹配法(Maximum Matching, MM)是最直观的分词方法,它需要一个预先构建好的词典。
核心思想:对于待分词的句子,从左到右(或从右到左)扫描,尽可能匹配词典中最长的词。
正向最大匹配(Forward MM, FMM):从左向右扫描。
- 示例:
南京航空航天大学自动化系 - 过程:
南->南京->南京航空->南京航空航天->南京航空航天大学(匹配到最长词,切分)。剩余自动化系继续匹配。 - 结果:
南京航空航天大学|自动化|系
- 示例:
反向最大匹配(Backward MM, BMM):从右向左扫描。
- 示例:
南京市长江大桥 - 过程:
桥->大桥->江大桥->长江大桥(匹配到最长词,切分)。剩余南京市继续匹配。 - 结果:
南京市|长江大桥
- 示例:
双向最大匹配(Bi-directional MM):同时执行 FMM 和 BMM,然后根据某种规则(如分词数目、词频概率)选择更优结果。
- 示例:
南京市长江大桥 - FMM 结果(如果词典有
南京市长,且无江大桥):南京市长|江|大桥 - BMM 结果:
南京市|长江大桥 - 比较:按一元词概率独立相乘的口径,应比较两条完整切分路径的概率乘积(或负对数概率之和):
P(南京市长)P(江大桥)与P(南京市)P(长江大桥)。仅比较长江大桥与江大桥单个词频,不足以保证整条路径总分更高;此处仅凭长江大桥更常见作直观说明,并非充分的全局判据。
- 示例:
下面我们用简化的 Python 代码演示正向最大匹配的原理。注意,实际工具(如 Jieba)的算法更复杂,这里仅为教学演示。
def forward_maximum_matching(text, word_dict, max_len=5):
"""
正向最大匹配分词(简化演示版)
:param text: 待分词字符串
:param word_dict: 词典集合
:param max_len: 词典中最长词的长度
:return: 分词结果列表
"""
result = []
index = 0
text_length = len(text)
while index < text_length:
matched = False
# 从最大长度开始尝试匹配
for length in range(min(max_len, text_length - index), 0, -1):
word = text[index:index + length]
if word in word_dict:
result.append(word)
index += length
matched = True
break
# 未匹配到,按单字切分
if not matched:
result.append(text[index])
index += 1
return result
# 定义一个微型词典
word_dict = {"南京", "南京市", "市长", "长江", "长江大桥", "大桥", "江", "市"}
# 待分词文本
sentence = "南京市长江大桥"
max_word_len = max(len(w) for w in word_dict)
# 执行分词
seg_result = forward_maximum_matching(sentence, word_dict, max_word_len)
print("待分词文本:", sentence)
print("分词结果:", seg_result)待分词文本: 南京市长江大桥
分词结果: ['南京市', '长江大桥']基于最优路径的分词模型
最大匹配法是一种“贪心”策略,只考虑局部最长匹配,可能不是全局最优。更优的方法是将分词问题转化为寻找最优路径的问题,通常使用动态规划(如 Viterbi 算法)求解。
模型构建:
- 将句首、字间和句尾的 个切分边界作为图中的节点(长度为 的句子有 共 个边界)。
- 如果从位置
i到位置j的子串是一个词(在词典中),则建立一条从边界i到边界j的边,词为text[i:j]。 - 为每条边赋予一个权重,这个权重通常与该词出现的概率(来自语言模型)负相关(如
-log(P(word)))。 - 分词任务就变成了从句首边界
0到句尾边界n,寻找一条路径权重和最小(即整体概率最大)的路径。
示例:中国人民银行 我们可以构建一个词图,可能的词边包括:中、中国、国人、人民、中国人民银行、银行等。通过动态规划,我们可以找到概率最大的路径,例如 中国|人民|银行。
这种方法综合考虑了所有可能的分词组合,并利用语言模型选择最流畅、最可能的一种,是统计分词方法的经典思路。后续基于序列标注(如用 CRF 对每个字打上 B、M、E、S 标签)的现代分词方法,在思想上与此一脉相承。
实战:使用 Jieba 进行中文分词
今天,我们很少需要从零实现分词算法。Jieba(结巴分词)是一个优秀的、广泛使用的中文分词 Python 库。
# 以下代码展示了 Jieba 的基本用法。
# 注意:在实际运行环境中,你需要先执行 `pip install jieba`。
# 本讲义块内不执行实际安装和 import,仅展示伪代码和预期输出。
# 伪代码:Jieba 基本分词
"""
import jieba
# 示例句子
sentences = [
"我来到北京清华大学",
"他来到了网易杭研大厦",
"我爱北京天安门"
]
print("精确模式(默认):")
for sent in sentences:
seg_list = jieba.cut(sent, cut_all=False)
print(f"'{sent}' -> {'/'.join(seg_list)}")
print("\n全模式(输出所有可能成词的组合):")
for sent in sentences:
seg_list = jieba.cut(sent, cut_all=True)
print(f"'{sent}' -> {'/'.join(seg_list)}")
print("\n搜索引擎模式(对长词再次切分):")
for sent in sentences:
seg_list = jieba.cut_for_search(sent)
print(f"'{sent}' -> {'/'.join(seg_list)}")
"""除了分词,在实际的文本预处理中,我们经常需要移除停用词(Stop Words)。停用词是指那些对文本核心含义贡献甚微的常见词,如中文的“的”、“了”、“在”,英文的“the”、“a”、“in”、“on”等。
# 伪代码:分词与停用词过滤结合
"""
import jieba
# 一个简单的停用词列表
stop_words = {"的", "了", "在", "是", "我", "和", "就", "都", "而", "及", "与", "着", "或", "一个", "啊", "呢"}
text = "自然语言处理是一门很有趣的学科,它涉及到计算机科学、人工智能和语言学的知识。"
# 分词
words = jieba.cut(text, cut_all=False)
# 过滤停用词并组成新文本
filtered_words = [word for word in words if word not in stop_words and word.strip() != '']
filtered_text = ' '.join(filtered_words)
print("原始文本:", text)
print("分词后过滤停用词:", filtered_text)
"""Jieba 还支持用户自定义词典、调整词频、并行分词等高级功能,足以应对大多数中文分词需求。它内部综合使用了基于前缀词典的动态规划方法和 HMM 模型,兼顾了精度和效率。
📝 动手练一练
- 概念辨析:简述“正向最大匹配(FMM)”和“反向最大匹配(BMM)”算法在切分“南京市长江大桥”时可能产生不同结果的原因。假设词典包含
{南京, 南京市, 市长, 长江, 长江大桥, 大桥}。
👉 点击查看参考答案
- FMM:从左向右扫描。首先看到“南京”,尝试匹配更长词“南京市”,成功。剩余“长江大桥”。匹配“长江大桥”成功。最终结果:
南京市|长江大桥。 - BMM:从右向左扫描。首先看到“大桥”,尝试匹配更长词“长江大桥”,成功。剩余“南京市”。匹配“南京市”成功。最终结果:
南京市|长江大桥。 - 结果分析:在这个特定词典和句子下,FMM 和 BMM 结果一致。但如果词典中包含“南京市长”,FMM 会先匹配到“南京市长”;余串“江大桥”中“江”不在给定词典内,按最大匹配规则单字回退,结果为
南京市长|江|大桥(只有词典另含“江大桥”时,原答案南京市长|江大桥才成立)。而 BMM 仍会得到南京市|长江大桥。这体现了双向匹配和利用词频概率进行消歧的必要性。
- 代码思考:如果只用最大匹配算法,遇到词典中不存在的词(未登录词,OOV),如“空天信”(一个新造的技术名词),算法会如何切分?这揭示了基于词典的分词方法的主要弱点是什么?
👉 点击查看参考答案
对于未登录词“空天信”,只有在其内部没有任何可匹配的较长词典项时,最大匹配算法才会逐字回退,切成 空|天|信;若词典含“空天”,同一算法会输出 空天|信。OOV 整体未登录,并不等于它的所有子串都未登录。这揭示了基于词典的分词方法对未登录词识别能力弱的核心弱点。未登录词(包括新词、专有名词、特定领域术语)是影响分词精度的最主要因素,远比分词歧义的影响更大。现代基于序列标注或深度学习的分词方法,主要目标就是提升对未登录词的识别能力。
本章小结
本节我们深入探讨了中文自然语言处理的第一道关卡——分词。我们认识到中文构词法的内在复杂性是分词的根源挑战,而通过“规范+词表+语料库”建立可计算的词语定义是技术发展的基石。从基于词典和启发式规则的最大匹配法,到基于统计和全局最优路径的动态规划方法,分词技术不断演进。最终,我们无需重复造轮子,可以借助像 Jieba 这样成熟高效的工具快速上手。分词是后续词性标注、句法分析、情感分析等几乎所有中文 NLP 任务的基础预处理步骤。
📋 行动清单
- 在你的 Python 环境中安装 Jieba (
pip install jieba),并尝试对一段中文新闻或小说段落进行分词。 - 对比 Jieba 的“精确模式”和“全模式”在不同类型句子上的输出差异,理解其适用场景。
- 查找或构建一个中文停用词列表,尝试在分词后对文本进行停用词过滤,观察文本内容的变化。
—— 小象教研组