自然语言处理应用篇 · 第3章

中文分词:jieba 完全实战

分词是中文 NLP 的第一道工序。本章讲解分词原理,并把 jieba 的全部核心用法(模式、自定义词典、词性标注、并行)一次讲透。

🎯 学习目标

  • 了解三类分词算法:词典匹配、统计模型(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 与停用词。下一章将介绍更智能的关键词提取方法。