3、中文分词技术:jieba分词详解、分词模式选择、自定义词典与停用词
中文分词,说白了就是把一句话切成一个个有意义的词。
你想想看,英文单词之间自带空格,天然分好了。中文呢?「我爱北京天安门」——计算机怎么知道「北京」是一个词,「天安门」是另一个词?这就是分词要解决的问题。
我在做新闻文本分类项目时,第一道坎就是分词。分得不好,后面的特征提取、模型训练全是白搭。今天咱们就聊聊jieba这个工具,我用了快十年,算是老朋友了。
3.1 jieba分词的核心原理
jieba为什么快?因为它用了基于前缀词典的贪心扫描。
说白了,它先拿一个超大的词典,里面存了各种词和它们的出现频率。然后从左到右扫描句子,尽可能匹配最长的词。比如「北京大学」,词典里既有「北京」也有「北京大学」,jieba会优先匹配「北京大学」。
嗯,这里要注意:如果遇到词典里没有的词,jieba会用HMM模型(隐马尔可夫模型)来猜。它根据汉字之间的转移概率,推断哪些字更可能组成一个词。我在处理新闻中的新造词时,这个功能帮了大忙。
核心要点:jieba = 词典匹配 + HMM模型。词典负责常见词,HMM负责生僻词和新词。
3.2 三种分词模式,你选对了吗?
jieba提供了三种模式,很多人一开始搞混。我直接说结论:
| 模式 | 特点 | 速度 | 适用场景 |
|---|---|---|---|
| 精确模式 | 最精准,不冗余 | 快 | 新闻文本分析、关键词提取 |
| 全模式 | 把所有可能的词都切出来 | 最快 | 搜索引擎索引构建 |
| 搜索引擎模式 | 在精确模式基础上,对长词再切分 | 中等 | 搜索引擎召回、文本匹配 |
我个人习惯:做新闻分类时,90%的情况用精确模式。全模式虽然快,但会产生大量冗余词。比如「中国人民银行」会被切成「中国」「中国人」「中国人民银行」「银行」——你想想看,这会给特征空间带来多少噪音?
看个代码例子:
import jieba
text = "我在人民日报发表了一篇关于人工智能的文章"
# 精确模式
seg_exact = jieba.lcut(text, cut_all=False)
print("精确模式:", seg_exact)
# 输出: ['我', '在', '人民日报', '发表', '了', '一篇', '关于', '人工智能', '的', '文章']
# 全模式
seg_all = jieba.lcut(text, cut_all=True)
print("全模式:", seg_all)
# 输出: ['我', '在', '人民', '人民日报', '日报', '发表', '了', '一篇', '关于', '人工', '人工智能', '智能', '的', '文章']
# 搜索引擎模式
seg_search = jieba.lcut_for_search(text)
print("搜索引擎模式:", seg_search)
# 输出: ['我', '在', '人民', '日报', '人民日报', '发表', '了', '一篇', '关于', '人工', '智能', '人工智能', '的', '文章']
我的建议:如果你做的是文本分类、情感分析这类任务,用精确模式就够了。全模式适合做搜索引擎的倒排索引,因为需要尽可能多地召回。
3.3 自定义词典:让分词更懂你的领域
jieba自带的词典覆盖了通用场景,但遇到专业领域就抓瞎了。
我曾经处理一批财经新闻,里面全是「量化宽松」「逆回购」「MLF操作」这类词。jieba默认会把「量化宽松」切成「量化」和「宽松」——这显然不对。怎么办?加自定义词典。
自定义词典的格式很简单,一个文本文件,每行三个字段:
量化宽松 5 n
逆回购 3 n
MLF操作 2 nz
字段含义:词、词频(越大越优先)、词性。词频可以随便填,但建议按实际出现频率来。我一般先跑一遍数据,统计高频词,再手动筛选加到词典里。
加载方式:
jieba.load_userdict("my_dict.txt")
text = "央行开展MLF操作,进行逆回购"
seg = jieba.lcut(text)
print(seg)
# 输出: ['央行', '开展', 'MLF操作', ',', '进行', '逆回购']
注意:自定义词典的优先级高于默认词典。如果你不小心把「的」这种常用词加进去了,分词结果会变得很奇怪。我曾经犯过这个错,排查了半天才发现是词典里多了一个「的」字。
3.4 停用词:去掉噪音,保留精华
分词之后,你会发现大量「的」「了」「在」「是」这类词。它们对文本理解没什么帮助,反而会稀释关键词的权重。
停用词表就是用来干这个的。我一般用哈工大停用词表,再根据具体任务手动增删。比如做体育新闻,我会把「比赛」「球员」这类高频但无区分度的词也加进去。
实现方式:
def load_stopwords(path):
with open(path, 'r', encoding='utf-8') as f:
return set([line.strip() for line in f])
stopwords = load_stopwords("stopwords.txt")
text = "我今天在图书馆看了一本关于机器学习的书"
words = jieba.lcut(text)
filtered = [w for w in words if w not in stopwords and len(w) > 1]
print(filtered)
# 输出: ['今天', '图书馆', '一本', '关于', '机器学习', '书']
嗯,这里要注意:停用词过滤后,最好保留长度大于1的词。单字词「我」「你」「他」大部分是停用词,但「书」「水」这种单字词有时是有意义的。我一般根据任务灵活调整。
3.5 本章知识体系
下面这张图总结了中文分词的核心流程,我画了很久,希望能帮你理清思路:
3.6 避坑指南
最后分享几个我踩过的坑:
- 词典编码问题:自定义词典一定要用UTF-8编码。我曾经用GBK编码的词典,jieba直接报错,排查了半小时才发现是编码问题。
- 停用词表别太激进:有些词在A任务中是停用词,在B任务中可能是关键词。比如「不错」在情感分析中很重要,但在主题分类中可能是噪音。我一般每个任务单独维护一个停用词表。
- 分词速度优化:如果处理海量新闻,建议用jieba.enable_parallel()开启并行分词。我处理100万条新闻时,速度提升了3倍。
- HMM开关:如果你的文本很规范(比如新闻稿),可以关掉HMM模式,速度更快。但如果文本中有大量新词(比如社交媒体),建议开启。
一句话总结:分词是文本特征工程的基石。选对模式、加对词典、滤对停用词,后面的工作才能事半功倍。
公众号:蓝海资料掘金营,微信deep3321