🎯 学习目标
- 了解三类分词算法:词典匹配、统计模型(HMM/CRF)、深度学习
- 熟练使用 jieba 精确/全/搜索引擎/Paddle 四种模式
- 会用自定义词典解决专业词、新词切分问题
- 掌握
jieba.posseg词性标注与 tokenize 位置偏移 - 了解 HanLP、pkuseg、THULAC、LAC 等其他分词工具
- 理解 OOV、准确率/召回率等分词评测概念
1计算机怎么分词:三类方法
方法一:基于词典的最大匹配(规则)
准备一部大词典,扫描句子按词典切词。按扫描方向分为正向最大匹配(FMM)、逆向(RMM)、双向。
词典中有:研究、研究生、生命、命、的、起源
句子:研究生命的起源
正向最大匹配(每次取最长):研究生 / 命 / 的 / 起源 ← 错
正确切分:研究 / 生命 / 的 / 起源
→ 纯词典法无法解决歧义,且对未登录词(新词)无能为力
方法二:基于统计的模型
从大规模已分词语料中学习:字与字相邻出现的概率(成词概率)、字在词首/词中/词尾的概率。代表模型:HMM(隐马尔可夫)、CRF(条件随机场)。CRF 至今仍是工业界重要基线。
方法三:深度学习
BILSTM-CRF、BERT-CRF 把分词转化为字序列标注问题(给每个字标 B/M/E/S:词首/词中/词尾/单字成词),准确率最高,需要 GPU 与训练数据。
自 然 语 言 处 理 很 有 意 思
S B E B E S B E B E 自然/语言/处理/很/有意思
jieba 的策略:前缀词典扫描 + DAG(有向无环图)找出所有可能切分 → 用动态规划求最大概率路径 → 对未登录词用 HMM(BEMS 标注)识别。兼顾速度与准确率,是中文分词最流行的入门与工程选择。
2jieba 四种分词模式
import jieba
sent = "我来到北京清华大学研究自然语言处理"
# ① 精确模式(默认,最常用):最准确地切开,不重复
list(jieba.cut(sent, cut_all=False))
# ['我', '来到', '北京', '清华大学', '研究', '自然语言', '处理']
# ② 全模式:把所有可能成词的都扫出来,速度快,但有冗余、不解决歧义
list(jieba.cut(sent, cut_all=True))
# ['我', '来到', '北京', '清华', '清华大学', '华大', '大学',
# '研究', '自然', '自然语言', '语言', '处理']
# ③ 搜索引擎模式:在精确模式基础上把长词再切细,提高召回
list(jieba.cut_for_search("小明硕士毕业于中国科学院计算技术研究所"))
# ['小明', '硕士', '毕业', '于', '中国', '科学', '学院', '中科院',
# '中国科学院', '计算', '技术', '研究', '研究所', '计算技术研究所']
# lcut 是 cut 的"直接返回 list"版本(cut 返回的是生成器)
jieba.lcut("Python分词很简单")
# ['Python', '分词', '很', '简单']
| 模式 | 函数 | 特点 | 用途 |
|---|---|---|---|
| 精确模式 | lcut(s) | 准确无冗余 | 文本分析默认选择 |
| 全模式 | cut(s, True) | 快、有冗余 | 很少单独使用 |
| 搜索引擎 | cut_for_search(s) | 长词再切,召回高 | 倒排索引、搜索 |
| Paddle 模式 | cut(s, use_paddle=True) | 深度学习分词,更准 | 需 pip install paddlepaddle jieba -U |
# cut 返回生成器:大文本流式处理时省内存
for word in jieba.cut(very_long_text):
process(word)
# HMM 控制:是否识别未登录词(默认开启,关掉后完全依赖词典)
jieba.lcut("他在嗑CP时还种草了新款耳机", HMM=True)
3自定义词典:解决专业词与新词
通用分词器在垂直领域(医疗、金融、法律)和新词上经常切错:
print(jieba.lcut("我想学习大语言模型并做提示词工程"))
# ['我', '想', '学习', '大', '语言', '模型', '并', '做', '提示', '词', '工程']
# "大语言模型""提示词工程"被切碎了
# ① 逐个添加:add_word(词, 词频, 词性)
jieba.add_word("大语言模型")
jieba.add_word("提示词工程")
print(jieba.lcut("我想学习大语言模型并做提示词工程"))
# ['我', '想', '学习', '大语言模型', '并', '做', '提示词工程']
# ② 删除词:让某个词不要被切成整体
jieba.del_word("清华大学")
# ③ 批量加载自定义词典文件
# jieba.load_userdict("domain_words.txt")
# domain_words.txt 格式:词语 词频(可省) 词性(可省),每行一个
大语言模型 1000 nz
提示词工程 800 nz
云计算 500
区块链 500
# 词频越大越倾向整体切分;遇到总被切碎的词就加大词频
# 实战:从语料自动挖掘新词
# jieba 提供 jieba.analyse.textrank/TF-IDF 抽取关键词(第5章),
# 工业界也常用互信息(PMI)+左右熵 自动发现领域新词,再加入用户词典。
动态调节词频(细粒度修正)
# 如果某词仍被切碎/黏连,又不想改词典文件:
jieba.add_word("出柜")
jieba.suggest_freq(("中", "将"), tune=True) # 强制让"中将"分开
print(jieba.lcut("中将中将的任命书中将详细说明"))
jieba.suggest_freq("台中", tune=True) # 强制合并
# 建议只在具体文本上临时调节,全局优先维护词典文件
4词性标注 posseg
import jieba.posseg as pseg
for word, flag in pseg.cut("我爱北京天安门,Python是最好的编程语言"):
print(f"{word}/{flag}", end=" ")
# 我/r 爱/v 北京/ns 天安门/ns ,/x Python/eng 是/v
# 最好/a 的/u 编程/n 语言/n
jieba 采用ICTCLAS 北大标注集,常见标记:
| 标记 | 词性 | 标记 | 词性 |
|---|---|---|---|
n | 普通名词 | v | 动词 |
nr | 人名 | a | 形容词 |
ns | 地名 | d | 副词 |
nt | 机构团体 | m | 数词 |
nz | 其他专名 | q | 量词 |
eng | 英文 | r | 代词 |
t | 时间词 | p | 介词 |
u | 助词(的/地/得) | x | 标点/非语素 |
# 实用:只保留名词(关键词/主题分析常用粗过滤)
words = [w for w, f in pseg.cut("苹果发布了新款手机并投资人工智能")
if f.startswith("n")]
print(words) # ['苹果', '新款', '手机', '人工智能']
# 结果转成成对列表
pairs = [(w, f) for w, f in pseg.cut("他/r 在/p 北京/ns 读/v 书/n")]
5tokenize:获取词在原文中的位置
# 默认模式
result = jieba.tokenize("我爱自然语言处理")
for word, start, end in result:
print(f"{word} [{start}:{end}]")
# 我 [0:1]
# 爱 [1:2]
# 自然语言 [2:6]
# 处理 [6:8]
# 搜索引擎模式:mode="search",长词会带子词的多重区间
# 用途:高亮搜索词、回标原文位置、NER 结果定位
6并行分词与性能
# jieba 自带多进程并行(按行切大文件)
jieba.enable_parallel(4) # 开启 4 进程(仅支持 Linux/Mac 多进程 fork)
with open("huge.txt", encoding="utf-8") as f:
for line in f:
words = jieba.lcut(line)
jieba.disable_parallel() # Windows 上建议直接用 ProcessPoolExecutor
性能建议:① 启动时 jieba 首次加载词典有几百毫秒开销,常驻服务中启动时预热(先切一句);② 超大批量语料按行用多进程;③ 词典加载、自定义词在程序入口统一完成,避免重复加载。
7其他主流中文分词工具
| 工具 | 单位 | 特点 |
|---|---|---|
| jieba | 开源社区 | 最简单、生态最好、速度快,入门与中小项目首选 |
| HanLP 2.x | 汉科大何晗 | 功能全家桶:分词/词性/NER/句法/情感,有深度学习版,Java 为主也有 Python 包 hanlp |
| pkuseg | 北大 | 多领域模型(新闻/医药/旅游),准确率高,速度较慢 |
| THULAC | 清华 | 分词+词性,模型紧凑 |
| LAC | 百度 PaddleNLP | 词法分析(分词+词性+专名),深度学习,pip 可装 |
| spaCy(zh) | Explosion | 工业级流水线,NER/句法强(第4章) |
# pkuseg 示例(选学)
# pip install pkuseg
import pkuseg
seg = pkuseg.pkuseg()
print(seg.cut("我爱自然语言处理"))
# LAC 示例(选学,同时给出词性)
# pip install lac
# from LAC import LAC
# lac = LAC()
# print(lac.run("我爱北京天安门"))
8分词效果如何评测
把机器切分结果与人工标注的"金标准"对比,三个核心指标:
金标准: 我 / 爱 / 自然语言 / 处理
机 器: 我 / 爱 / 自然 / 语言 / 处理
边界完全正确的词才算命中(本例命中:我、爱、处理 = 3 个)
- 精确率 Precision = 切对的词数 / 机器切出的词总数
- 召回率 Recall = 切对的词数 / 金标准词总数
- F1 = 两者调和平均,综合指标
另一个常说的概念:OOV(Out Of Vocabulary)未登录词,即词典里没有的新词/专名;IV 即登录词。分词器的差距主要体现在 OOV 召回上。
# 简单计算示例(教学版)
# 金标准: 我 / 爱 / 自然语言 / 处理
# 机 器: 我 / 爱 / 自然 / 语言 / 处理
# 边界和类型都完全一致的词才算命中 → 命中:我、爱、处理 = 3
gold = ["我", "爱", "自然语言", "处理"]
pred = ["我", "爱", "自然", "语言", "处理"]
hit = 3
P = hit / len(pred) # 精确率 = 3/5
R = hit / len(gold) # 召回率 = 3/4
F1 = 2 * P * R / (P + R)
print(f"P={P:.2f}, R={R:.2f}, F1={F1:.2f}")
# 严格评测要按"起止位置"对齐,工业界常用 seqeval 库直接计算
9综合案例:新闻分词与词频 TopN
import jieba
from collections import Counter
news = """人工智能技术正在重塑各行各业。大语言模型的突破让自然语言处理
进入新阶段,企业纷纷布局人工智能应用。自然语言处理、计算机视觉和
语音识别是人工智能的三大核心方向,其中大语言模型最受关注。"""
# 1) 自定义领域词
for w in ["大语言模型", "人工智能", "自然语言处理", "计算机视觉", "语音识别"]:
jieba.add_word(w)
# 2) 分词(去掉标点和单字噪声,按任务决定)
tokens = [w for w in jieba.lcut(news) if len(w.strip()) > 1
and w not in {"的", "和", "在", "让", "是"}]
# 3) 词频统计
counter = Counter(tokens)
print("总词数:", len(tokens))
for word, freq in counter.most_common(8):
print(f"{word}: {freq}")
总词数: 33
人工智能: 3
大语言模型: 2
自然语言处理: 2
核心: 1
方向: 1
计算机视觉: 1 ...
注意:高频词不等于关键词("的、了、在"永远最多)。第 5 章会用 TF-IDF / TextRank 自动过滤常见词、提取真正有信息量的关键词。
10本章小结与练习
📌 关键结论
- 分词三流派:词典匹配 → HMM/CRF 统计 → 深度学习;jieba = DAG 最大概率 + HMM 未登录词。
- 分析用精确模式
lcut,索引用cut_for_search;cut 是生成器适合流式。 - 垂直领域务必建自定义词典,这是提升分词效果最划算的手段。
- 词性用 posseg,位置用 tokenize;评测看 P/R/F1 与 OOV 召回。
练习1:"他从小学游泳" 存在哪两种切分?这说明词典分词的什么问题?
可以切为 他/从小/学/游泳,也可以切为 他/从/小学/游泳,两种都"符合词典"但意思不同(从小学习 vs 在小学里)。这说明歧义切分仅靠词典无法解决,需要统计概率或结合上下文语义,这也是 jieba 用概率路径、深度模型用语境消歧的原因。
练习2:jieba 把"生成式人工智能"切成"生成/式/人工智能",如何用两种方式修正?
方式一:jieba.add_word("生成式人工智能", freq=1000) 直接加词;方式二:把词写入用户词典文件(每行:词 词频 词性),程序启动时 jieba.load_userdict() 批量加载。项目中推荐词典文件方式,便于维护;单句临时修正可用 suggest_freq("生成式人工智能", tune=True)。
练习3:对一段产品评论完成分词,只保留名词类(n 开头的词性)并统计 Top10。
import jieba.posseg as pseg;[w for w,f in pseg.cut(text) if f.startswith('n') and len(w)>1] 取名词;再用 Counter(...).most_common(10)。可先 add_word 补充产品领域词,过滤标点 x 与停用词。下一章将介绍更智能的关键词提取方法。