jieba 模块
1 特点
-
支持四种分词模式:
-
精确模式,试图将句子最精确地切开,适合文本分析;
-
全模式,把句子中所有的可以成词的词语都扫描出来, 速度非常快,但是不能解决歧义;
-
搜索引擎模式,在精确模式的基础上,对长词再次切分,提高召回率,适合用于搜索引擎分词。
-
paddle 模式,利用 PaddlePaddle 深度学习框架,训练序列标注(双向GRU)网络模型实现分词。同时支持词性标注。paddle模式使用需安装paddlepaddle-tiny,pip install paddlepaddle-tiny==1.6.1。目前 paddle 模式支持 jieba v0.40 及以上版本。jieba v0.40 以下版本,请升级 jieba,pip install jieba --upgrade 。 PaddlePaddle 官网
-
-
支持繁体分词
-
支持自定义词典
-
MIT 授权协议
2 算法
- 基于前缀词典实现高效的词图扫描,生成句子中汉字所有可能成词情况所构成的有向无环图 (DAG)
- 采用了动态规划查找最大概率路径, 找出基于词频的最大切分组合
- 对于未登录词,采用了基于汉字成词能力的 HMM 模型,使用了 Viterbi 算法
3 主要功能
3.1 分词
-
jieba.cut
cut(sentence, cut_all=False, HMM=True, use_paddle=False)
- sentence:需要分词的字符串;
- cut_all:参数用来控制是否采用全模式,True 为全模式,False 为精确模式;
- HMM:参数用来控制是否使用 HMM 模型;
- use_paddle:参数用来控制是否使用 paddle 模式下的分词模式,paddle 模式采用延迟加载方式,通过 enable_paddle 接口安装 paddlepaddle-tiny,并且 import 相关代码;
-
jieba.cut_for_search
cut_for_search(sentence, HMM=True)
- sentence:需要分词的字符串;
- HMM:是否使用 HMM 模型。该方法适合用于搜索引擎构建倒排索引的分词,粒度比较细。
-
待分词的字符串可以是 unicode 或 UTF-8 字符串、GBK 字符串。注意:不建议直接输入 GBK 字符串,可能无法预料地错误解码成 UTF-8。
-
jieba.cut 以及 jieba.cut_for_search 返回的结构都是一个可迭代的 generator,可以使用 for 循环来获得分词后得到的每一个词语(unicode),或者用 jieba.lcut 以及 jieba.lcut_for_search 直接返回 list。
-
jieba.Tokenizer(dictionary=DEFAULT_DICT) 新建自定义分词器,可用于同时使用不同词典。jieba.dt 为默认分词器,所有全局分词相关函数都是该分词器的映射。
import numpy as np
import pandas as pd
import jieba
jieba.__version__ # '0.42.1'
jieba.enable_paddle() # 启动 paddle模式。 0.40版之后开始支持,早期版本不支持
strs = ["我来到北京清华大学","乒乓球拍卖完了","中国科学技术大学"]
for str in strs:
seg_list = jieba.cut(str, use_paddle=True)
print("Paddle 模式:" + '/'.join(list(seg_list)))
# 结果
Paddle enabled successfully......
Paddle 模式:我/来到/北京清华大学
Paddle 模式:乒乓球/拍卖/完/了
Paddle 模式:中国科学技术大学
seg_list = jieba.cut("我来到北京清华大学", cut_all=True) # 从默认词典构建前缀词典
print("全模式:" + "/ ".join(seg_list))
# 结果
Building prefix dict from the default dictionary ...
Dumping model to file cache /var/folders/3v/dwdrxl1n1vzf2yj1whmy4v5h0000gn/T/jieba.cache
Loading model cost 1.300 seconds.
Prefix dict has been built successfully.
全模式:我/ 来到/ 北京/ 清华/ 清华大学/ 华大/ 大学
seg_list = jieba.cut("我来到北京清华大学", cut_all=False) # 返回的结构都是一个可迭代的 generator
print(seg_list)
print("精确模式(默认模式):" + "/ ".join(seg_list))
# 结果
<generator object Tokenizer.cut at 0x1453de048>
精确模式(默认模式):我/ 来到/ 北京/ 清华大学
seg_list = jieba.cut_for_search("我来到北京清华大学")
print("搜索引擎模式:" + "/ ".join(seg_list))
# 结果
搜索引擎模式:我/ 来到/ 北京/ 清华/ 华大/ 大学/ 清华大学
seg_list = jieba.lcut("我来到北京清华大学", cut_all=False) # lcut 可以直接返回 list
seg_list
# 结果
['我', '来到', '北京', '清华大学']
seg_list = jieba.cut("他来到了网易杭研大厦") # 默认是精确模式,此处,“杭研”并没有在词典中,但是也被Viterbi算法识别出来了
print(", ".join(seg_list))
# 结果
他, 来到, 了, 网易, 杭研, 大厦
3.2 添加自定义词典
3.2.1 载入词典
-
开发者可以指定自己自定义的词典,以便包含 jieba 词库里没有的词。虽然 jieba 有新词识别能力,但是自行添加新词可以保证更高的正确率;
-
用法: jieba.load_userdict(file_name) # file_name 为文件类对象或自定义词典的路径;
-
词典格式和 dict.txt 一样,一个词占一行;每一行分三部分:词语、词频(可省略)、词性(可省略),用空格隔开,顺序不可颠倒。file_name 若为路径或二进制方式打开的文件,则文件必须为 UTF-8 编码。
-
词频省略时使用自动计算的能保证分出该词的词频,例如:
创新办 3 i
云计算 5
凱特琳 nz
台中
- 更改分词器(默认为 jieba.dt)的 tmp_dir 和 cache_file 属性,可分别指定缓存文件所在的文件夹及其文件名,用于受限的文件系统。
- 范例:
-
自定义词典:https://github.com/fxsjy/jieba/blob/master/test/userdict.txt
-
用法示例:https://github.com/fxsjy/jieba/blob/master/test/test_userdict.py
-
之前: 李小福 / 是 / 创新 / 办 / 主任 / 也 / 是 / 云 / 计算 / 方面 / 的 / 专家 /
-
加载自定义词库后: 李小福 / 是 / 创新办 / 主任 / 也 / 是 / 云计算 / 方面 / 的 / 专家 /
-
-
3.2.2 调整词典
-
使用 add_word(word, freq=None, tag=None) 和 del_word(word) 可在程序中动态修改词典。
- 向词典中添加词,freq 和 tag 可以省略。
-
使用 suggest_freq(segment, tune=True) 可调节单个词语的词频,使其能(或不能)被分出来。
- segment:期望分割后的词,如何需要词需要作为一个整体,使用一个字符串;
- tune:如果为 True,调节词频;默认 False。
-
注意:自动计算的词频在使用 HMM 新词发现功能时可能无效。
-
"通过用户自定义词典来增强歧义纠错能力"
jieba.lcut('如果放到post中将出错。', HMM=False)
jieba.suggest_freq(segment=('中', '将'), tune=True)
jieba.lcut('如果放到post中将出错。', HMM=False)
jieba.lcut('「台中」正确应该不会被切开', HMM=False)
jieba.suggest_freq('台中', True)
jieba.lcut('「台中」正确应该不会被切开', HMM=False)
# 结果
['如果', '放到', 'post', '中将', '出错', '。']
Out[6]:
494
Out[6]:
['如果', '放到', 'post', '中', '将', '出错', '。']
Out[6]:
['「', '台', '中', '」', '正确', '应该', '不会', '被', '切开']
Out[6]:
69
Out[6]:
['「', '台中', '」', '正确', '应该', '不会', '被', '切开']
3.3 关键词提取
3.3.1 基于 TF-IDF 算法的关键词抽取
idf 默认是 jieba 模块已经定义的文本语料库,也可以切换为自定义文本语料库。
-
jieba.analyse.extract_tags(sentence, topK=20, withWeight=False, allowPOS=(), withFlag=False)
使用 TF-IDF 算法从 sentence 中提取关键词:
- sentence 为待提取的文本;
- topK 为返回几个 TF/IDF 权重最大的关键词,默认值为 20;
- withWeight 为是否一并返回关键词权重值,默认值为 False;
- allowPOS 仅包括指定词性的词,默认值为空,即不筛选;
- withFlag:只有当 allowPOS 为空时起作用。如果为 True,返回如 posseg.cut 的 (word, weight) 对的列表,如果为 False,返回词列表;
-
jieba.analyse.TFIDF(idf_path=None) 新建 TFIDF 实例,idf_path 为 IDF 频率文件
import jieba.analyse
text = "线程是程序执行时的最小单位,它是进程的一个执行流,\
是CPU调度和分派的基本单位,一个进程可以由很多个线程组成,\
线程间共享进程的所有资源,每个线程有自己的堆栈和局部变量。\
线程由CPU独立调度执行,在多CPU环境下就允许多个线程同时运行。\
同样多线程也可以实现并发操作,每个请求分配一个线程来处理。"
keywords = jieba.analyse.extract_tags(sentence=text, topK=10)
print("TF-IDF 关键词提取:\n\n", "/".join(keywords))
# 结果
TF-IDF 关键词提取:
线程/CPU/进程/调度/多线程/程序执行/每个/执行/堆栈/局部变量
# withWeight=True 返回关键词权重值
keywords = jieba.analyse.extract_tags(sentence=text, topK=10, withWeight=True)
keywords
# 结果
[('线程', 1.6092956253903845),
('CPU', 0.6896981251673077),
('进程', 0.3764666465751923),
('调度', 0.32615933279615383),
('多线程', 0.2673207240769231),
('程序执行', 0.2539909706038462),
('每个', 0.22361383583346153),
('执行', 0.21377215274192307),
('堆栈', 0.212835852075),
('局部变量', 0.20620430426153843)]
# allowPOS 指定词性,比如 ['ns', 'n'] 或者 ('ns', 'n')
keywords = jieba.analyse.extract_tags(sentence=text, topK=10, withWeight=True, allowPOS=['ns', 'n'])
keywords
# 结果
[('线程', 3.984922500966667),
('进程', 0.9322031248528573),
('调度', 0.8076326335904762),
('程序执行', 0.6289300224476191),
('堆栈', 0.5270221099),
('局部变量', 0.5106011343619047),
('单位', 0.5105471403419047),
('分派', 0.4351668436752381),
('资源', 0.25532014137047615),
('环境', 0.24676257547285713)]
# withFlag=True 返回关键词权重值
keywords = jieba.analyse.extract_tags(sentence=text, topK=10, withWeight=True, withFlag=False)
keywords
# 结果
[('线程', 1.6092956253903845),
('CPU', 0.6896981251673077),
('进程', 0.3764666465751923),
('调度', 0.32615933279615383),
('多线程', 0.2673207240769231),
('程序执行', 0.2539909706038462),
('每个', 0.22361383583346153),
('执行', 0.21377215274192307),
('堆栈', 0.212835852075),
('局部变量', 0.20620430426153843)]
关键词提取所使用逆向文件频率(即IDF)文本语料库可以切换成自定义语料库的路径。
# 可以先构建一个 TFIDF 实例,再修改实例中的内容,提取关键字
import jieba.analyse
tfidf = jieba.analyse.TFIDF()
tfidf.set_stop_words("../extra_dict/stop_words.txt")
tfidf.set_idf_path("../extra_dict/idf.txt.big")
tfidf.extract_tags(sentence)
# 也可以直接调用函数修改
import jieba.analyse
jieba.analyse.set_stop_words("../extra_dict/stop_words.txt")
jieba.analyse.set_idf_path("../extra_dict/idf.txt.big")
jieba.analyse.extract_tags(sentence)
3.3.2 基于 TextRank 算法的关键词抽取
- jieba.analyse.textrank(sentence, topK=20, withWeight=False, allowPOS=('ns', 'n', 'vn', 'v'), withFlag=False) 直接使用,接口相同,注意默认过滤词性。
- jieba.analyse.TextRank() 新建自定义 TextRank 实例
算法论文:TextRank: Bringing Order into Texts
基本思想:
- 将待抽取关键词的文本进行分词
- 以固定窗口大小(默认为5,通过span属性调整),词之间的共现关系,构建图
- 计算图中节点的PageRank,注意是无向带权图
text = "线程是程序执行时的最小单位,它是进程的一个执行流,\
是CPU调度和分派的基本单位,一个进程可以由很多个线程组成,\
线程间共享进程的所有资源,每个线程有自己的堆栈和局部变量。\
线程由CPU独立调度执行,在多CPU环境下就允许多个线程同时运行。\
同样多线程也可以实现并发操作,每个请求分配一个线程来处理。"
keywords = jieba.analyse.textrank(text, topK=10)
keywords
# 结果
['线程', '进程', '调度', '单位', '操作', '请求', '分配', '允许', '基本', '并发']
keywords = jieba.analyse.textrank(text, topK=10, withWeight=True)
keywords
# 结果
[('线程', 1.0),
('进程', 0.4837352620361488),
('调度', 0.3595461575195059),
('单位', 0.3489332390176574),
('操作', 0.325898701227582),
('请求', 0.3150319289640483),
('分配', 0.3122916575249211),
('允许', 0.29138009075742605),
('基本', 0.28062153944119445),
('并发', 0.25286860151890117)]
3.4 词性标注
- jieba.posseg.POSTokenizer(tokenizer=None) 新建自定义分词器,tokenizer 参数可指定内部使用的 jieba.Tokenizer 分词器;
- jieba.posseg.dt (default) 为默认词性标注分词器;
- 标注句子分词后每个词的词性,采用和 ictclas 兼容的标记法;
- 除了 jieba 默认分词模式,提供 paddle 模式下的词性标注功能。paddle 模式采用延迟加载方式,通过 enable_paddle() 安装 paddlepaddle-tiny,并且 import 相关代码。
import jieba
import jieba.posseg as pseg
words = pseg.cut("我爱北京天安门") # jieba 默认模式
jieba.enable_paddle() # 启动 paddle 模式。 0.40版之后开始支持,早期版本不支持
words = pseg.cut("我爱北京天安门", use_paddle=True) # paddle模式
for word, flag in words:
print('%s %s' % (word, flag))
# 结果
Paddle enabled successfully......
我 r
爱 v
北京 LOC
天安门 LOC
words = pseg.cut("我爱北京天安门", use_paddle=False) # paddle模式
for word, flag in words:
print('%s %s' % (word, flag))
# 结果
我 r
爱 v
北京 ns
天安门 ns
3.5 并行分词
-
原理:将目标文本按行分隔后,把各行文本分配到多个 Python 进程并行分词,然后归并结果,从而获得分词速度的可观提升
-
基于 python 自带的 multiprocessing 模块,目前暂不支持 Windows
-
用法:
- jieba.enable_parallel(4) # 开启并行分词模式,参数为并行进程数
- jieba.disable_parallel() # 关闭并行分词模式
-
例子:https://github.com/fxsjy/jieba/blob/master/test/parallel/test_file.py
-
实验结果:在 4 核 3.4GHz Linux 机器上,对金庸全集进行精确分词,获得了 1MB/s 的速度,是单进程版的 3.3 倍。
-
注意:并行分词仅支持默认分词器 jieba.dt 和 jieba.posseg.dt。
3.6 Tokenize:返回词语在原文的起止位置
- 注意,输入参数只接受 unicode
- 默认模式
result = jieba.tokenize(u'永和服装饰品有限公司')
for tk in result:
print("word %s\t\t start: %d \t\t end:%d" % (tk[0], tk[1], tk[2]))
# 结果
word 永和 start: 0 end:2
word 服装 start: 2 end:4
word 饰品 start: 4 end:6
word 有限公司 start: 6 end:10
- 搜索模式
result = jieba.tokenize(u'永和服装饰品有限公司', mode='search')
for tk in result:
print("word %s\t\t start: %d \t\t end:%d" % (tk[0], tk[1], tk[2]))
# 结果
word 永和 start: 0 end:2
word 服装 start: 2 end:4
word 饰品 start: 4 end:6
word 有限 start: 6 end:8
word 公司 start: 8 end:10
word 有限公司 start: 6 end:10