介绍

在自然语言处理中,中文处理技术比西文处理技术要落后很大一段距离,许多西文的处理方法中文不能直接采用,就是因为中文必需有分词这道工序。

当我们进行自然语言处理的时候,大部分情况下,词汇是我们对句子和文章理解的基础,因此需要一个工具去把完整的文本中分解成粒度更细的词。

Python3 jieba库的安装

  • 直接命令行输入:pip install jieba
  • 百度PyPI,搜索下载jieba包,放在命令行启动目录下,输入pip install (+ jieba包的包名全称)

jieba主要功能

1. jieba分词的特点

支持三种分词模式:

  • 精确模式,试图将句子最精确地切开,适合文本分析;
  • 全模式,把句子中所有的可以成词的词语都扫描出来, 速度非常快,但是不能解决歧义;
  • 搜索引擎模式,在精确模式的基础上,对长词再次切分,提高召回率,适合用于搜索引擎分词。

支持繁体分词

支持自定义词典

MIT 授权协议

2. 分词函数

jieba.cut 以及 jieba.cut_for_search 返回的结构都是一个可迭代的 generator,可以使用 for 循环来获得分词后得到的每一个词语(unicode)
支持三种分词模式:

jieba.cut(将包含中文字符的整个句子分成单独分词)

语法:

jieba.cut(sentence, cut_all=False, HMM=True)

实例:

import jieba
# 分词
# 全模式
cut1 = jieba.cut("云南省昆明市昆明理工大学是个美丽的学校,学校在呈贡区", cut_all=True)
print("全模式: "+" / ".join(cut1))
# 精确模式
cut2 = jieba.cut("云南省昆明市昆明理工大学是个美丽的学校,学校在呈贡区", cut_all=False)
print("精确模式: "+" / ".join(cut2))
# 默认模式--精确模式
cut3 = jieba.cut("云南省昆明市昆明理工大学是个美丽的学校,学校在呈贡区" )
print("默认模式: "+" / ".join(cut3))

运行结果:

全模式: 云南 / 云南省 / 昆明 / 昆明市 / 昆明 / 明理 / 理工 / 理工大 / 理工大学 / 工大 / 大学 / 是 / 个 / 美丽 / 的 / 学校 /  /  / 学校 / 在 / 呈贡 / 区
精确模式: 云南省 / 昆明市 / 昆明 / 理工大学 / 是 / 个 / 美丽 / 的 / 学校 / , / 学校 / 在 / 呈贡 / 区
默认模式: 云南省 / 昆明市 / 昆明 / 理工大学 / 是 / 个 / 美丽 / 的 / 学校 / , / 学校 / 在 / 呈贡 / 区

jieba.cut_for_search(搜索引擎模式)

语法:

jieba.cut_for_search(sentence, HMM=True)

实例:

# 搜索引擎模式
cut4 = jieba.cut_for_search("云南省昆明市昆明理工大学是个美丽的学校,学校在呈贡区" )
print("搜索引擎模式: "+" / ".join(cut4))

运行结果:

搜索引擎模式: 云南 / 云南省 / 昆明 / 昆明市 / 昆明 / 理工 / 工大 / 大学 / 理工大 / 理工大学 / 是 / 个 / 美丽 / 的 / 学校 / , / 学校 / 在 / 呈贡 / 区

jieba.lcut以及jieba.lcut_for_search直接返回 list

实例:

cut5 = jieba.lcut("云南省昆明市昆明理工大学是个美丽的学校,学校在呈贡区" )
print(type(cut5))
print("默认模式: "+" / ".join(cut5))
# 搜索引擎模式
cut6 = jieba.lcut_for_search("云南省昆明市昆明理工大学是个美丽的学校,学校在呈贡区" )
print(type(cut6))
print("搜索引擎模式: "+" / ".join(cut6))

运行结果:

<class 'list'>
默认模式: 云南省 / 昆明市 / 昆明 / 理工大学 / 是 / 个 / 美丽 / 的 / 学校 / , / 学校 / 在 / 呈贡 / 区
<class 'list'>
搜索引擎模式: 云南 / 云南省 / 昆明 / 昆明市 / 昆明 / 理工 / 工大 / 大学 / 理工大 / 理工大学 / 是 / 个 / 美丽 / 的 / 学校 / , / 学校 / 在 / 呈贡 / 区

3. 添加用户自定义词典

很多时候我们需要针对自己的场景进行分词,会有一些领域内的专有词汇。开发者可以指定自己自定义的词典,以便包含 jieba 词库里没有的词。虽然 jieba 有新词识别能力,但是自行添加新词可以保证更高的正确率。

例如:dict.txt

云南省 nt
昆明市 nt
昆明理工大学 2 nt
是个
美丽的 a
学校
在
呈贡区

实例1:

import jieba

cut1 = jieba.cut("云南省昆明市昆明理工大学是个美丽的学校,学校在呈贡区" )
print("加入词典前: "+" / ".join(cut1))

jieba.load_userdict('dict.txt')

cut2 = jieba.cut("云南省昆明市昆明理工大学是个美丽的学校,学校在呈贡区" )
print("加入词典后: "+" / ".join(cut2))

运行结果:

加入词典前: 云南省 / 昆明市 / 昆明 / 理工大学 / 是 / 个 / 美丽 / 的 / 学校 / , / 学校 / 在 / 呈贡 / 区
加入词典后: 云南省 / 昆明市 / 昆明理工大学 / 是个 / 美丽的 / 学校 / , / 学校 / 在 / 呈贡区

实例2:

import jiieba

print('/'.join(jieba.cut('如果放到旧字典中将出错。', HMM=False)))

jieba.suggest_freq(('中', '将'), True)

print('/'.join(jieba.cut('如果放到旧字典中将出错。', HMM=False)))

运行结果:

如果/放到/旧/字典/中将/出错/。
如果/放到/旧/字典/中/将/出错/。

实例3:

import jieba

cut1 = jieba.cut("云南省昆明市昆明理工大学是个美丽的学校,学校在呈贡区" )
print("动态修改词典前: "+" / ".join(cut1))

jieba.add_word('昆明理工大学')
jieba.add_word('呈贡区')
jieba.del_word('昆明市')

cut2 = jieba.cut("云南省昆明市昆明理工大学是个美丽的学校,学校在呈贡区" )
print("动态修改词典后: "+" / ".join(cut2))

运行结果:

动态修改词典前: 云南省 / 昆明市 / 昆明 / 理工大学 / 是 / 个 / 美丽 / 的 / 学校 / , / 学校 / 在 / 呈贡 / 区
动态修改词典后: 云南省 / 昆明 / 市 / 昆明理工大学 / 是 / 个 / 美丽 / 的 / 学校 / , / 学校 / 在 / 呈贡区

实例4:

import jieba
testlist = [
('今天天气不错', ('今天', '天气')),
('如果放到post中将出错。', ('中', '将')),
('我们中出了一个叛徒', ('中', '出')),
]

for sent, seg in testlist:
    print('/'.join(jieba.cut(sent, HMM=False)))
    word = ''.join(seg)
    print('%s 调节单个词语的词频前的词频: %s, 调节单个词语的词频后的词频: %s' % (word, jieba.get_FREQ(word), jieba.suggest_freq(seg, True)))
    print('/'.join(jieba.cut(sent, HMM=False)))
    print("-"*40)

运行结果:

今天天气/不错
今天天气 调节单个词语的词频前的词频: 3, 调节单个词语的词频后的词频: 0
今天/天气/不错
----------------------------------------
如果/放到/post/中将/出错/。
中将 调节单个词语的词频前的词频: 763, 调节单个词语的词频后的词频: 494
如果/放到/post/中/将/出错/。
----------------------------------------
我们/中/出/了/一个/叛徒
中出 调节单个词语的词频前的词频: 3, 调节单个词语的词频后的词频: 3
我们/中/出/了/一个/叛徒
----------------------------------------

4. 关键词提取

import jieba.analyse

(1)基于 TF-IDF 算法的关键词抽取

语法:

jieba.analyse.extract_tags(sentence, topK=20, withWeight=False, allowPOS=())

实例1:

import jieba.analyse as analyse
lines = open('NBA.txt', encoding='utf-8').read()
print("  ".join(analyse.extract_tags(lines, topK=20, withWeight=False, allowPOS=())))

运行结果:

韦少  杜兰特  全明星  全明星赛  MVP  威少  正赛  科尔  投篮  勇士  球员  斯布鲁克  更衣柜  NBA  三连庄  张卫平  西部  指导  雷霆  明星队

实例2:

import jieba.analyse as analyse
lines1 = open('西游记.txt',encoding='gb18030').read()
print("  ".join(analyse.extract_tags(lines1, topK=20, withWeight=False, allowPOS=())))
lines2 = open('西游记语录.txt',encoding='gb18030').read()
print("  ".join(analyse.extract_tags(lines2, topK=20, withWeight=False, allowPOS=())))

运行结果:

行者  八戒  师父  三藏  大圣  唐僧  沙僧  菩萨  妖精  和尚  那怪  甚么  那里  长老  呆子  怎么  徒弟  不知  老孙  悟空
行者  师父  八戒  三藏  菩萨  和尚  甚么  唐僧  妖精  怎么  老孙  徒弟  那里  大圣  沙僧  大王  悟空  我们  不知  不曾

补充:

  • 关键词提取所使用逆向文件频率(IDF)文本语料库可以切换成自定义语料库的路径
  • 关键词提取所使用停止词(Stop Words)文本语料库可以切换成自定义语料库的路径

(2)基于 TextRank 算法的关键词抽取

语法:

jieba.analyse.textrank(sentence, topK=20, withWeight=False, allowPOS=('ns', 'n', 'vn', 'v'))

基本思想:

  • 将待抽取关键词的文本进行分词
  • 以固定窗口大小(默认为5,通过span属性调整),词之间的共现关系,构建图
  • 计算图中节点的PageRank,注意是无向带权图

实例:

import jieba.analyse as analyse
lines = open('NBA.txt', encoding='utf-8').read()
print("  ".join(analyse.textrank(lines, topK=20, withWeight=False, allowPOS=('ns', 'n', 'vn', 'v'))))
print("  ".join(analyse.textrank(lines, topK=20, withWeight=False, allowPOS=('ns', 'n'))))

lines1 = open('西游记.txt',encoding='gb18030').read()
print("  ".join(analyse.textrank(lines1, topK=20, withWeight=False, allowPOS=('ns', 'n', 'vn', 'v'))))

lines2 = open('西游记语录.txt',encoding='gb18030').read()
print("  ".join(analyse.textrank(lines2, topK=20, withWeight=False, allowPOS=('ns', 'n', 'vn', 'v'))))

运行结果:

全明星赛  勇士  正赛  指导  对方  投篮  球员  没有  出现  时间  威少  认为  看来  结果  相隔  助攻  现场  三连庄  介绍  嘉宾
勇士  正赛  全明星赛  指导  投篮  玩命  时间  对方  现场  结果  球员  嘉宾  时候  全队  主持人  照片  全程  目标  快船队  肥皂剧

行者  师父  八戒  三藏  大圣  菩萨  不知  只见  妖精  长老  国王  呆子  徒弟  却说  悟空  小妖  不见  不能  不得  出来

师父  行者  八戒  不知  三藏  菩萨  妖精  大圣  徒弟  弟子  不得  长老  贫僧  悟空  出来  取经  国王  兄弟  不能  陛下

5. 词性标注

import jieba.posseg as pseg

语法:

jieba.posseg.POSTokenizer(tokenizer=None)

实例:

import jieba.posseg as pseg
words = pseg.cut("我爱自然语言处理")
for word, flag in words:
    print('%s %s' % (word, flag))

运行结果:

我 r
爱 v
自然语言 l
处理 v

6. 其他

另外jieba还支持,并行分词

用法:

  • jieba.enable_parallel(4) # 开启并行分词模式,参数为并行进程数
  • jieba.disable_parallel() # 关闭并行分词模式

Tokenize:返回词语在原文的起止位置

实例:

import jieba
print("这是默认模式的tokenize")
result = jieba.tokenize(u'自然语言处理非常有用')
for tk in result:
    print("%s\t\t start: %d \t\t end:%d" % (tk[0],tk[1],tk[2]))

print("这是搜索模式的tokenize")
result = jieba.tokenize(u'自然语言处理非常有用', mode='search')
for tk in result:
    print("%s\t\t start: %d \t\t end:%d" % (tk[0],tk[1],tk[2]))

运行结果:

这是默认模式的tokenize
自然语言		 start: 0 		 end:4
处理		 start: 4 		 end:6
非常		 start: 6 		 end:8
有用		 start: 8 		 end:10
这是搜索模式的tokenize
自然		 start: 0 		 end:2
语言		 start: 2 		 end:4
自然语言		 start: 0 		 end:4
处理		 start: 4 		 end:6
非常		 start: 6 		 end:8
有用		 start: 8 		 end:10

写在最后

10-06 14:54