欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

手把手教你Python3使用Jieba工具

程序员文章站 2022-06-06 09:56:20
...

疫情宅在家,只能静下心来弄毕设~

话不多说,直接上干货,本篇博客包含:

  • 中文分词
  • 添加自定义词典
  • 词性标注
  • 关键词抽取

 

环境:

  • Python3.5
  • Jieba-0.39
  • Pycharm2018

一、安装jieba

在安装有python3 和 pip 的机子上,安装jieba库很简单,使用pip即可:

pip install jieba

二、Jieba分词特性


1、支持三种分词模式:

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

2、支持繁体分词

3、支持自定义词典

4、代码对Python2和Python3均兼容

5、支持多种编程语言,包括Java、C++、Rust、PHP、R、Node.js等

Jieba工具主要使用的算法包括:

(1)通过基于前缀词典实现高效的词图扫描,构建句子中汉字所有可能生成词情况的有向无环图;

(2)采用动态规划查找最大概率路径,寻找基于词频的最大切分组合;

(3)对于未登录词,采用基于汉字成词能力的HMM模型结合Viterbi算法


三、主要功能

参考:https://blog.csdn.net/Eastmount/article/details/97612578

1、中文分词(jieba.cut

① 何为分词?

由于中文词语之间是紧密联系的,一个汉语句子是由一串前后连续的汉字组成,词与词之间没有明显的分界标志,所以需要通过一定的分词技术把句子分割成空格连接的词序列,这就是所谓的中文分词技术。

中文分词(Chinese Word Segmentation)指将汉字序列切分成一个个单独的词或词串序列,它能够在没有词边界的中文字符串中建立分隔标志,通常采用空格分隔。中文分词是数据分析预处理、数据挖掘、文本挖掘、搜索引擎、知识图谱、自然语言处理等领域中非常基础的知识点,只有经过中文分词后的语料才能转换为数学向量的形式,继续进行后面的分析。同时,由于中文数据集涉及到语义、歧义等知识,划分难度较大,比英文复杂很多。


② 基本用法

首先看一段简单的结巴分词代码,主要调用两个函数实现。

  • jieba.cut(text,cut_all=True) ——分词函数,第一个参数是需要分词的字符串,第二个参数表示是否为全模式。分词返回的结果是一个可迭代的生成器(generator),可使用for循环来获取分词后的每个词语,更推荐读者转换为list列表再使用
  • jieba.cut_for_search(text)——搜索引擎模式分词,参数为分词的字符串,该方法适合用于搜索引擎构造倒排索引的分词,粒度比较细。
    #encoding=utf-8
    import jieba
    text = "小杨毕业于北京理工大学,从事Python人工智能相关工作。"
    
    data = jieba.cut(text,cut_all=True)
    print("【全模式】:","/".join(data)) #全模式
    
    data = jieba.cut(text,cut_all=False)
    print("【精确模式】:","/".join(data)) #精确模式
    
    data = jieba.cut(text) # 默认是精确模式
    print("【默认模式】:","/".join(data))
    
    data = jieba.cut_for_search(text)  # 搜索引擎模式
    print("【搜索引擎模式】:","/".join(data))
    
    #返回列表
    seg_list = jieba.lcut(text, cut_all=False)
    print("【返回列表】: {0}".format(seg_list))

    输出结果如下所示

       手把手教你Python3使用Jieba工具

       最终的分词结果比较理想,其中精确模式输出的“小/杨/毕业/于/北京理工大学/,/从事/Python/人工智能/相关/工作/。”比较精准。下面简单比较一下结巴中文分词的三种分词模式。

  1. 全模式:该模式将语料中所有可以组合成词的词语都构建出来,其优点是速度非常快,缺点是不能解决歧义问题,并且分词结果不太准确。
  2. 精确模式:该模式利用其算法将句子最精确地分隔开,适合文本分析,通常采用这种模式进行中文分词。其分词结果为“小/杨/毕业/于/北京理工大学/,/从事/Python/人工智能/相关/工作/。”,其中“北京理工大学”、“人工智能”这些完整的名词被精准识别,但也有部分词未被识别,后续导入词典可以实现专有词汇识别
  3. 搜索引擎模式:该模式是在精确模式基础上,对长词再次切分,提高召回率,适合用于搜索引擎分词。

③ 基于HMM模型的中文分词
     隐马尔可夫模型(Hidden Markov Model, HMM)是一种基于概率的统计分析模型,用来描述一个系统隐性状态的转移和隐性状态的表现概率。到目前为止,HMM模型被认为是解决大多数自然语言处理问题最为快速、有效的方法之一。它成功解决了语义识别、机器翻译等问题。

     在Jieba工具中,对于未登录到词库的词,使用了基于汉字成词能力的 HMM 模型和 Viterbi 算法,其大致原理是采用四个隐含状态,分别表示为单字成词、词组的开头、词组的中间和词组的结尾。通过标注好的分词训练集,可以得到 HMM的各个参数,然后使用 Viterbi 算法来解释测试集,得到分词结果。

  • jieba.cut : 方法接受三个输入参数: 需要分词的字符串;cut_all 参数用来控制是否采用全模式;HMM 参数用来控制是否使用 HMM 模型
  • jieba.cut_for_search : 方法接受两个参数:需要分词的字符串;是否使用 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 为默认分词器,所有全局分词相关函数都是该分词器的映射。
# encoding=utf-8
import jieba

text = "他来到了网易杭研大厦工作,我继续去北理读研。"
# 精确模式
data = jieba.cut(text, cut_all=False, HMM=False)
print("[精确模式]: ", "/".join(data))
# 精确模式+HMM
data = jieba.cut(text, cut_all=False, HMM=True)
print("[精确模式]: ", "/".join(data))

输出结果如下图所示,未启用HMM模型时,它无法识别“杭研”、“北理”词语,将其拆分成了“杭”、“研”和“北”、“理”,而启用HMM模型时,它有效识别了新词“杭研”、“北理”。

手把手教你Python3使用Jieba工具

 ④繁体中文分词

Jieba工具支持中文繁体字的识别,将前面示例转换为繁体字,即“小楊畢業於北京理工大學,從事Python人工智能相關工作。”,调用Jieba分词的代码如下所示。

# encoding=utf-8
import jieba

text = "小楊畢業於北京理工大學,從事Python人工智能相關工作。"

# 全模式
data = jieba.cut(text, cut_all=True)
print("【全模式】: ", "/".join(data))

# 精确模式
data = jieba.cut(text, cut_all=False)
print("【精确模式】: ", "/".join(data))

# 搜索引擎模式
data = jieba.cut_for_search(text)
print("【搜索引擎模式】: ", "/".join(data))

输出结果如下所示:

手把手教你Python3使用Jieba工具

2、添加自定义词典()

①添加词典

在进行中文分词过程中,通常会遇到一些专用词语无法精准的切分,比如“云计算”会被分割为“云”、“计算”,“贵州财经大学”会被分割为“贵州”、“财经大学”等。虽然Jieba工具有新词识别能力,但也无法识别出所有Jieba词库里没有的词语,但它为开发者提供了添加自定义词典功能,从而保证更好的分词正确率。其函数原型如下:

load_userdict(f)——该函数只有一个参数,表示载入的自定义词典路径,f 为文件类对象或自定义词典路径下的文件。词典的格式为:一个词占一行,每行分为三部分:

word  freq  word_type

其中,word为对应的词语freq为词频(可省略),word_type为词性(可省了),中间用空格隔开,顺序不可以改变。注意,文件必须为UTF-8编码。

下面举例讲解,第一个代码是未导入自定义词典的中文分词。

# encoding=utf-8
import jieba

text = "小杨在贵州财经大学工作,擅长大数据、云计算,喜欢乾清宫、黄果树瀑布等景区。"

# 精确模式
data = jieba.cut(text, cut_all=False)
print(u"[原始文本]: ", text)
print(u"[精确模式]: ", "/".join(data))

输出结果未将“贵州财经大学”、“大数据”、“云计算”、“乾清宫”、“黄果树瀑布”等词汇正确分割。

手把手教你Python3使用Jieba工具手把手教你Python3使用Jieba工具

接着导入自定义词典,其本地词典命名为“dict.txt”,如图所示,包括设置“贵州财经大学”的词性为机构名词“nt”,“大数据”、“云计算”的词性为名词“n”,,也有省略词性和词频的“乾清宫”。

手把手教你Python3使用Jieba工具

文件保存为utf-8格式: 

手把手教你Python3使用Jieba工具

完整代码如下:

#encoding=utf-8
import jieba

text = "杨秀璋在贵州财经大学工作,擅长大数据、云计算,喜欢乾清宫、黄果树瀑布等景区。"

#导入自定义词典
jieba.load_userdict("dict.txt")
#精确模式
data = jieba.cut(text, cut_all=False)
print("[原始文本]: ", text)
print("[精确模式]: ", "/".join(data))

 此时的输出结果有效地提取了“贵州财经大学”、“云计算”、“乾清宫”。但也有两个未识别出的词语,“黄果树瀑布”不在词典中,故被拆分成了“黄果树”和“瀑布”,“大数据”虽然在词典中,却仍然拆分成了“大”和“数据”。

手把手教你Python3使用Jieba工具

②动态修改词典

在Jieba工具中,可以在程序中动态修改词典,通过add_word(word, freq=None, tag=None)函数添加新词语,通过del_word(word)函数删除自定义词语

#encoding=utf-8
import jieba

text = "小杨在贵州财经大学工作,擅长大数据、云计算,喜欢乾清宫、黄果树瀑布等景区。"

#导入自定义词典
jieba.load_userdict("dict.txt")

#添加自定义词语
jieba.add_word("小杨")
jieba.add_word("黄果树瀑布")
jieba.add_word("自然语言处理", freq=10, tag="nz")

#删除自定义词语
jieba.del_word("北理工")

#精确模式
data = jieba.cut(text, cut_all=False)
print("[原始文本]: ", text, "\n")
print("[精确模式]: ", "/".join(data))

 该代码增加了新词语“小杨”、“黄果树瀑布”和“自然语言处理”,删除了“北理工”,其运行结果如下所示,它有效地将“小杨”和“黄果树瀑布”进行了精准识别。

手把手教你Python3使用Jieba工具

此时,我们可能会有一个疑问,为什么“大数据”被拆分成了“大”和“数据”呢?这是因为Jieba词库中“大”和“数据”的重要程度更高,我们可以使用suggest_freq(segment, tune=True)函数调节单个词语的词频,使其被分割出来。 

代码如下所示:

#encoding=utf-8
import jieba

text = "小杨在贵州财经大学工作,擅长大数据、云计算,喜欢乾清宫、黄果树瀑布等景区。"

#导入自定义词典
jieba.load_userdict("dict.txt")

#添加自定义词语
jieba.add_word("小杨")
jieba.add_word("黄果树瀑布")
jieba.add_word("自然语言处理", freq=10, tag="nz")

#删除自定义词语
jieba.del_word("北理工")

#调节词频
jieba.suggest_freq('大数据', True)

#精确模式
data = jieba.cut(text, cut_all=False)
print("[原始文本]: ", text, "\n")
print("[精确模式]: ", "/".join(data))

最终的输出结果为“小杨/在/贵州财经大学/工作/,/擅长/大数据/、/云计算/,/喜欢/乾清宫/、/黄果树瀑布/等/景区/。”

手把手教你Python3使用Jieba工具

终于将“小杨”、“贵州财经大学”、“大数据”、“云计算”、“乾清宫”、“黄果树瀑布”等专有词语识别出来。同时,如果自定义词典存在很多专用名词,并且需要设置它们的高权重,可以使用下面的代码循环设置每一个词语的词频。

#循环设置词频重要程度
fp = open("dict.txt", 'r', encoding='utf8')
for line in fp:
    line = line.strip()
jieba.suggest_freq(line, True)

#第二种方法
[jieba.suggest_freq(line.strip(), True) for line in open("dict.txt",'r',encoding='utf8')]

3、词性标注(jieba.posseg.cut()

词性标注(Part-Of-Speech Tagging, POS Tagging)也被称为语法标注(Grammatical Tagging)或词类消疑(Word-category Disambiguation),是将语料库内单词的词性按其含义和上下文内容进行标记的文本数据处理技术。通过词性标注处理,可以将分词得到的词序列中每个单词标注一个正确的词性。

在Jieba工具中,调用jieba.posseg.POSTokenizer(tokenizer=None)函数新建自定义分词器。tokenizer参数可指定内部使用的jieba.Tokenizer分词器,jieba.posseg.dt为默认词性标注分词器Jieba工具采用和Ictclas 兼容的标记法,标注句子分词后每个词的词性通过循环输出。Jieba工具的各个词性及含义如下表:

手把手教你Python3使用Jieba工具

巧记词性对照表
名词 (1个一类,7个二类,5个三类)
名词分为以下子类:

  • n 名词
  • nr 人名
  • nr1 汉语姓氏
  • nr2 汉语名字
  • nrj 日语人名
  • nrf 音译人名
  • ns 地名
  • nsf 音译地名
  • nt 机构团体名
  • nz 其它专名
  • nl 名词性惯用语
  • ng 名词性语素

时间词(1个一类,1个二类)

  • t 时间词
  • tg 时间词性语素

处所词(1个一类)

  • s 处所词

方位词(1个一类)

  • f 方位词

动词(1个一类,9个二类)

  • v 动词
  • vd 副动词
  • vn 名动词
  • vshi 动词“是”
  • vyou 动词“有”
  • vf 趋向动词
  • vx 形式动词
  • vi 不及物动词(内动词)
  • vl 动词性惯用语
  • vg 动词性语素

形容词(1个一类,4个二类)

  • a 形容词
  • ad 副形词
  • an 名形词
  • ag 形容词性语素
  • al 形容词性惯用语

区别词(1个一类,2个二类)

  • b 区别词
  • bl 区别词性惯用语

状态词(1个一类)

  • z 状态词

代词(1个一类,4个二类,6个三类)

  • r 代词
  • rr 人称代词
  • rz 指示代词
  • rzt 时间指示代词
  • rzs 处所指示代词
  • rzv 谓词性指示代词
  • ry 疑问代词
  • ryt 时间疑问代词
  • rys 处所疑问代词
  • ryv 谓词性疑问代词
  • rg 代词性语素

数词(1个一类,1个二类)

  • m 数词
  • mq 数量词

量词(1个一类,2个二类)

  • q 量词
  • qv 动量词
  • qt 时量词

副词(1个一类)

  • d 副词

介词(1个一类,2个二类)

  • p 介词
  • pba 介词“把”
  • pbei 介词“被”

连词(1个一类,1个二类)

  • c 连词
  • cc 并列连词

助词(1个一类,15个二类)

  • u 助词
  • uzhe 着
  • ule 了 喽
  • uguo 过
  • ude1 的 底
  • ude2 地
  • ude3 得
  • usuo 所
  • udeng 等 等等 云云
  • uyy 一样 一般 似的 般
  • udh 的话
  • uls 来讲 来说 而言 说来
  • uzhi 之
  • ulian 连 (“连小学生都会”)

叹词(1个一类)

  • e 叹词

语气词(1个一类)

  • y 语气词(delete yg)

拟声词(1个一类)

  • o 拟声词

前缀(1个一类)

  • h 前缀

后缀(1个一类)

  • k 后缀

字符串(1个一类,2个二类)

  • x 字符串
  • xx 非语素字
  • xu 网址URL

标点符号(1个一类,16个二类)

  • w 标点符号
  • wkz 左括号,全角:( 〔 [ { 《 【 〖 〈 半角:( [ { <
  • wky 右括号,全角:) 〕 ] } 》 】 〗 〉 半角: ) ] { >
  • wyz 左引号,全角:“ ‘ 『
  • wyy 右引号,全角:” ’ 』
  • wj 句号,全角:。
  • ww 问号,全角:? 半角:?
  • wt 叹号,全角:! 半角:!
  • wd 逗号,全角:, 半角:,
  • wf 分号,全角:; 半角: ;
  • wn 顿号,全角:、
  • wm 冒号,全角:: 半角: :
  • ws 省略号,全角:…… …
  • wp 破折号,全角:—— -- ——- 半角:— —-
  • wb 百分号千分号,全角:% ‰ 半角:%
  • wh 单位符号,全角:¥ $ £ ° ℃ 半角:$
     

官方文档给出的示例如下所示,通过“import jieba.posseg as pseg”语句导入扩展包,接着循环输出word(词语)和flag(词性)值。

#官方例程
#encoding=utf-8
import jieba.posseg as pseg

#词性标注
words = pseg.cut("我爱北京*")
for word, flag in words:
    print('%s %s' % (word, flag))

输出结果如图所示,其中“我”表示代词,对应“r”;“爱”对应动词,对应“v”,“北京”和“*”对应地点名词,对应“ns”。

手把手教你Python3使用Jieba工具

上面小节的示例对应的词性标注代码如下所示。

#encoding=utf-8
import jieba
import jieba.posseg
import jieba.analyse

text = "小杨在贵州财经大学工作,擅长大数据、云计算,喜欢乾清宫、黄果树瀑布等景区。"

#导入自定义词典
jieba.load_userdict("dict.txt")

#添加自定义词语
jieba.add_word("小杨")
jieba.add_word("黄果树瀑布")
#调节词频
jieba.suggest_freq('大数据', True)

#精确模式
data = jieba.cut(text, cut_all=False)
print("[原始文本]: ", text, "\n")
print("[精确模式]: ", "/".join(data), "\n")

#词性标注
sentence_seged = jieba.posseg.cut(text)
outstr = ' '
for x in sentence_seged:
    outstr += '\n'+"{}/{}  ".format(x.word, x.flag)
print('[词性标注]:', outstr)

输出结果如图所示:

手把手教你Python3使用Jieba工具手把手教你Python3使用Jieba工具

4、 关键词提取(jieba.analyse.extract_tags

关键词抽取就是从文本里面把跟这篇文档意义最相关的一些词抽取出来。这个可以追溯到文献检索初期,当时还不支持全文搜索的时候,关键词就可以作为搜索这篇论文的词语。因此,目前依然可以在论文中看到关键词这一项。

除了这些,关键词还可以在文本聚类、分类、自动摘要等领域中有着重要的作用。比如在聚类时将关键词相似的几篇文档看成一个团簇,可以大大提高聚类算法的收敛速度;从某天所有的新闻中提取出这些新闻的关键词,就可以大致了解那天发生了什么事情;或者将某段时间内几个人的微博拼成一篇长文本,然后抽取关键词就可以知道他们主要在讨论什么话题。

总之,关键词就是最能够反映出文本主题或者意思的词语。但是网络上写文章的人不会像写论文那样告诉你本文的关键词是什么,这个时候就需要利用计算机自动抽取出关键词,算法的好坏直接决定了后续步骤的效果。

关键词抽取从方法来说大致有两种:

  • 第一种是关键词分配,就是有一个给定的关键词库,然后新来一篇文档,从词库里面找出几个词语作为这篇文档的关键词;
  • 第二种是关键词抽取,就是新来一篇文档,从文档中抽取一些词语作为这篇文档的关键词;

目前大多数领域无关的关键词抽取算法(领域无关算法的意思就是无论什么主题或者领域的文本都可以抽取关键词的算法)和它对应的库都是基于后者的。从逻辑上说,后者比前着在实际使用中更有意义。

从算法的角度来看,关键词抽取算法主要有两类:

  • 有监督学习算法,将关键词抽取过程视为二分类问题,先抽取出候选词,然后对于每个候选词划定标签,要么是关键词,要么不是关键词,然后训练关键词抽取分类器。当新来一篇文档时,抽取出所有的候选词,然后利用训练好的关键词抽取分类器,对各个候选词进行分类,最终将标签为关键词的候选词作为关键词;
  • 无监督学习算法,先抽取出候选词,然后对各个候选词进行打分,然后输出topK个分值最高的候选词作为关键词。根据打分的策略不同,有不同的算法,例如TF-IDF,TextRank等算法;

jieba分词系统中实现了两种关键词抽取算法,分别是基于TF-IDF关键词抽取算法和基于TextRank关键词抽取算法,两类算法均是无监督学习的算法,下面将会通过实例讲解介绍如何使用jieba分词的关键词抽取接口以及通过源码讲解其实现的原理。

①基于TF-IDF:jieba.analyse.extract_tags(sentence, topK=20, withWeight=False, allowPOS=())
②基于TextRank:jieba.analyse.textrank(sentence, topK=20, withWeight=False, allowPOS=('ns', 'n', 'vn', 'v'))

  • sentence 为待提取的文本
  • topK 为返回几个 TF/IDF 权重最大的关键词,默认值为 20
  • withWeight 为是否一并返回关键词权重值,默认值为 False
  • allowPOS 仅包括指定词性的词,默认值为空,即不筛选

 TF-IDF算法应用到关键词抽取:

1. 预处理,首先进行分词和词性标注,将满足指定词性的词作为候选词;
2. 分别计算每个词的TF-IDF值;
3. 根据每个词的TF-IDF值降序排列,并输出指定个数的词汇作为可能的关键词;

TextRank算法应用到关键词抽取:

1. 预处理,首先进行分词和词性标注,将单个word作为结点添加到图中;
2. 设置语法过滤器,将通过语法过滤器的词汇添加到图中;出现在一个窗口中的词汇之间相互形成一条边;
3. 基于上述公式,迭代直至收敛;一般迭代20-30次,迭代阈值设置为0.0001;
4. 根据顶点的分数降序排列,并输出指定个数的词汇作为可能的关键词;
5. 后处理,如果两个词汇在文本中前后连接,那么就将这两个词汇连接在一起,作为关键短语;

 

<1>基于TF-IDF算法进行关键词抽取的示例代码如下所示,

from jieba import analyse

# 引入TF-IDF关键词抽取接口
tfidf = analyse.extract_tags

# 原始文本
text = "线程是程序执行时的最小单位,它是进程的一个执行流,\
        是CPU调度和分派的基本单位,一个进程可以由很多个线程组成,\
        线程间共享进程的所有资源,每个线程有自己的堆栈和局部变量。\
        线程由CPU独立调度执行,在多CPU环境下就允许多个线程同时运行。\
        同样多线程也可以实现并发操作,每个请求分配一个线程来处理。"

# 基于TF-IDF算法进行关键词抽取
keywords = tfidf(text,topK=20,withWeight=True)
print("keywords by tfidf:")
# 输出抽取出的关键词
for keyword in keywords:
	print(keyword[0],keyword[1])

控制台输出,

手把手教你Python3使用Jieba工具

<2>基于TextRank算法进行关键词抽取的示例代码如下所示,

from jieba import analyse

# 引入TextRank关键词抽取接口
textrank = analyse.textrank

# 原始文本
text = "线程是程序执行时的最小单位,它是进程的一个执行流,\
        是CPU调度和分派的基本单位,一个进程可以由很多个线程组成,\
        线程间共享进程的所有资源,每个线程有自己的堆栈和局部变量。\
        线程由CPU独立调度执行,在多CPU环境下就允许多个线程同时运行。\
        同样多线程也可以实现并发操作,每个请求分配一个线程来处理。"

# 基于TextRank算法进行关键词抽取
keywords = textrank(text,topK=20, withWeight=True)
print("\nkeywords by textrank:")
# 输出抽取出的关键词
for keyword in keywords:
	print(keyword[0], keyword[1])

 控制台输出,

手把手教你Python3使用Jieba工具