4、中文分词挑战与常用工具:jieba、pkuseg、THULAC

英文有空格帮我们把词天然隔开,中文呢?字挨着字,词边界全是模糊的。这就是中文NLP第一道坎——分词。我刚开始做中文文本分析时,以为分词就是按词典切一刀,结果被“南京市长江大桥”这种歧义结构狠狠教育了一顿。后来才明白,中文分词其实是个综合了词典、统计、规则甚至语义的活儿。

市面上工具不少,但真正经历过生产环境考验的,我个人最常用三款:jieba、pkuseg、THULAC。它们各有脾气,选错了会踩坑。这一章我们逐个拆解。

中文分词的核心难点

先聊聊为什么分对词这么难。你想想看,一个“做”字,出现在“做事”里是词头,出现在“叫做”里就是词尾。我曾在舆情分析项目里遇到一条评论:“这本书写得真好”,jieba 默认把它切成了“写/得/真/好” —— 语义完全丢了。

总结起来,三大挑战:

  • 歧义切分:比如“他说的的确确是个问题”——“的的确确”该不该拆?交叉歧义(“的确/切”vs“的/确切”)很难处理。
  • 未登录词:人名“特朗普”、新词“给力”、缩写“NLP”——词典里没有,模型得靠上下文猜。
  • 领域迁移:通用领域分得好,切到医疗、法律、电商评论就崩了。我做过一次金融研报分词,jieba 把“多头部署”切成了“多/头/部署”,哭笑不得。
难点类型表现典型例子
交集型歧义多个切分路径都合法“有意见” → 有/意见 / 有意/见
组合型歧义一个词可拆可合“看了” → 看/了 / 看了
OOV(未登录词)词表外新词“区块链”、“弹幕”

一句话总结:中文分词本质是序列标注问题(BEMS标注),但实际落地时,词典 + 统计 + 规则的多层融合才稳妥。

三大工具横向对比

我个人的习惯是:快速原型用 jieba,精度要求高用 pkuseg,需要词性标注用 THULAC。下面这张对比表,你直接存着当备忘录用。

工具算法基础词典规模领域定制速度词性标注
jieba前缀词典 + HMM~35万词用户词典 / 调整权重极快有(但较弱)
pkusegCRF + 深度学习基础模型+多领域提供6种领域模型较慢无
THULAC结构化感知机~30万词可加用户词典中等强(PKU标注集)

避坑提示:pkuseg 的领域模型可以指定“web”、“medicine”、“tourism”等模式,但注意它刚开始加载模型比较慢,不适合在线实时服务。我曾经在生产线上用 pkuseg,被它的启动延迟坑过一次,后来改成了 jieba + 自定义词典的方案。

jieba 实战:最顺手的瑞士军刀

jieba 支持三种模式:精确模式(默认)、全模式、搜索引擎模式。下面这个代码块,我建议你直接跑一遍:

import jieba

text = "南京市长江大桥"

# 精确模式(按最概率路径切分)
seg_list = jieba.cut(text, cut_all=False)
print("精确模式:", "/".join(seg_list))
# 输出: 南京市/长江大桥

# 全模式(所有可能的词都切出来)
seg_all = jieba.cut(text, cut_all=True)
print("全模式:  ", "/".join(seg_all))
# 输出: 南京/南京市/京市/市长/长江/长江大桥/大桥

# 搜索引擎模式(精确模式的子词再切)
seg_search = jieba.cut_for_search(text)
print("搜索引擎:", "/".join(seg_search))
# 输出: 南京/京市/南京市/长江/大桥/长江大桥

注意看“南京市长江大桥”这个经典陷阱——jieba 的精确模式依靠词频统计,默认选了概率最高的路径。但如果你用的是金融领域文本,比如“多头信号出现”,jieba 会切出“多/头信号” —— 这时候就需要自定义词典了。

加词方法:jieba.add_word("多头") 或写一个 user_dict.txt 文件,每行一个词+权重。我就养成了习惯:每个新项目第一件事就是梳理领域词汇表。

pkuseg:学术精度的代表

pkuseg 是北大语言计算实验室的作品,基于 CRF+神经网络。它的优势在于领域模型 —— 你下载后可以用 pkuseg.pkuseg(model_name="medicine") 加载医学模型。我试过用它处理医疗病例文本,准确率比 jieba 高了将近10个点。

import pkuseg

# 默认通用模型
seg = pkuseg.pkuseg()
text = "我爱自然语言处理"
print("pkuseg:", " | ".join(seg.cut(text)))
# 输出: 我 | 爱 | 自然语言处理

# 医学领域模型
seg_med = pkuseg.pkuseg(model_name="medicine")
med_text = "患者出现头痛、恶心症状"
print("医学:", " | ".join(seg_med.cut(med_text)))

注意:pkuseg 不支持词性标注,而且处理长文本时内存占用较高。如果你只是想做情感分析,用 jieba 就够了;但如果要做实体提取(NER),pkuseg 的精准分词能帮你减少很多后处理工作。

THULAC:词性标注的利器

THULAC 来自清华大学,它的最大亮点是 分词 + 词性标注一体化。我早期做文本聚类时,就靠 THULAC 提取名词短语做关键词。速度上,它介于 jieba 和 pkuseg 之间。

import thulac

# 初始化(可以指定模型路径)
thu = thulac.thulac(seg_only=False)  # seg_only=False 输出词性

text = "我爱北京天安门"
result = thu.cut(text, text=False)   # text=False 返回列表
for word, pos in result:
    print(f"{word}/{pos}", end=" ")
# 输出: 我/r 爱/v 北京/ns 天安门/ns

词性标注遵循北大标注集,比如 v 动词、ns 地名。如果你需要给下游任务提供词性特征,THULAC 是开箱即用的选择。不过它的用户词典接口比较原始,我曾在加词时忘了指定权重,导致新词一直没生效 —— 嗯,这里要注意 词典格式是两列:词 + 空格 + 词性。

我的选择建议

  • 快跑原型 / 通用场景 → jieba + 自定义词典。社区活跃,踩坑资料多。
  • 垂直领域(医疗、法律、金融) → pkuseg 领域模型 + jieba 补充。启动慢,但准。
  • 需要词性信息的传统 NLP 流水线 → THULAC。词性标注质量接近商用。

顺便提一句:如果你处理的是古文献、网络用语、问答系统,三个工具都可能有偏见。我在做古诗词分析时,只好自己训练了一个基于 BERT 的分词模型——这是后话了。

中文分词工具选型决策流程 输入文本 需要词性标注? 是 否 THULAC 领域专属? pkuseg 领域模型 否(通用) jieba + 自定义词典 提示:生产环境建议 jieba 兜底 + 领域模型主打,避免单点故障

我的核心心得:没有万能分词器。选型时多问问自己——我的数据长什么样?是短文本还是长文?对速度容忍度如何?需要词性吗?建议你在小批量样本上用三个工具分别跑一遍,对比输出结果,肉眼就能看出差距。我曾经因为嫌麻烦直接用了 jieba 默认配置,结果实体识别的 F1 值硬生生少了 5 个点——时间省了,后面补坑更费时。