3、Python 中文分词组件Jieba

在自然语言处理中,分词是一项最基本的技术。中文分词与英文分词有很大的不同,对英文而言,一个单词就是一个词,而汉语以字为基本书写单位,词语之间没有明显的区分标记,需要人为切分。现在开源的中文分词工具有 SnowNLP、THULAC、Jieba 和 HanLP 等,这里梳理下 Jieba 组件的内容。

一、Jieba 组件介绍

中文分词技术是中文信息处理的基础,有着极其广泛的实际应用,比如:汉语语言理解、机器翻译、语音合成、自动分类、自动摘要、数据挖掘和搜索引擎等,都需要对中文信息进行分词处理。因此,一个中文分词算法的好坏,会对其后续的应用产生极大的影响。

1、算法

Jieba 是一个立志于做最好的 Python 中文分词组件,主要涉及的算法有:

  • 基于前缀词典实现高效的词图扫描,生成句子中汉字所有可能成词情况所构成的有向无环图 (DAG);
  • 采用了动态规划查找最大概率路径, 找出基于词频的最大切分组合;
  • 对于未登录词,采用基于汉字成词能力的 HMM 模型,使用了 Viterbi 算法。

2、分词模式

Jieba 支持4种模式的分词:精准模式、全模式、搜索引擎模式及 paddle 模式,特点如下:

  • 精确模式:试图将句子最精确地切开,适合文本分析;
  • 全模式:把句子中所有的可以成词的词语都扫描出来, 速度非常快,但是不能解决歧义;
  • 搜索引擎模式:在精确模式的基础上,对长词再次切分,提高召回率,适合用于搜索引擎分词。
  • paddle模式:利用 PaddlePaddle 深度学习框架,训练序列标注(双向GRU)网络模型实现分词。同时支持词性标注。

请注意,paddle 模式使用需安装 paddlepaddle-tiny。目前 paddle 模式支持 jieba v0.40 及以上版本,如果是 jieba v0.40 以下版本,需要升级 jieba,命令如下:

# 安装paddlepaddle-tiny
pip install paddlepaddle-tiny==1.6.1

# 升级jieba
pip install jieba --upgrade

此外,Jieba 还支持中文繁体分词、自定义词典、关键词提取、词性标注、并行分词、ChineseAnalyzer for Whoosh搜索引擎等功能。

二、Jieba 安装与使用

1、安装

jieba 给出了多种的安装方式及说明,参考如下:

  我采用的是 pip 命令下载,安装的最新版本是 v-0.42.1:

pip install jieba

2、分词模式的使用

jieba 分词常用的函数,如下:

jieba.Tokenizer(dictionary=DEFAULT_DICT) 是新建自定义分词器,可用于同时使用不同词典。jieba.dt 为默认分词器,所有全局分词相关函数都是该分词器的映射,通过源码可以看到:

# default Tokenizer instance

dt = Tokenizer()

# global functions

get_FREQ = lambda k, d=None: dt.FREQ.get(k, d)
add_word = dt.add_word
calc = dt.calc
cut = dt.cut
lcut = dt.lcut
cut_for_search = dt.cut_for_search
lcut_for_search = dt.lcut_for_search
del_word = dt.del_word
get_DAG = dt.get_DAG
get_dict_file = dt.get_dict_file
initialize = dt.initialize
load_userdict = dt.load_userdict
set_dictionary = dt.set_dictionary
suggest_freq = dt.suggest_freq
tokenize = dt.tokenize
user_word_tag_tab = dt.user_word_tag_tab

下面,用前3种的分词模式为例,演示如下:

import jieba as jieba


def choice_mode(num):
    list_mode = []
    text = '灰树叶飘转在池塘,看飞机轰的一声去远乡'
    if num == "1":
        # 精准模式,cut_all默认False
        list_mode = jieba.lcut(text)
    elif num == "2":
        # 全模式
        list_mode = jieba.lcut(text, cut_all=True)
    elif num == "3":
        # 搜索引擎模式
        list_mode = jieba.lcut_for_search(text)
    return list_mode

测试1:精准模式

if __name__ == '__main__':
    # 灰/树叶/飘转/在/池塘/,/看/飞机/轰的一声/去/远乡/
    list_mode = choice_mode("1")
    for i in list_mode:
        print(i, end="/")

测试2:全模式

if __name__ == '__main__':
    # 灰/树叶/飘/转在/池塘/,/看/飞机/轰的一声/一声/去/远/乡/
    list_mode = choice_mode("2")
    for i in list_mode:
        print(i, end="/")

测试3:搜索引擎模式

if __name__ == '__main__':
    # 灰/树叶/飘转/在/池塘/,/看/飞机/一声/轰的一声/去/远乡/
    list_mode = choice_mode("3")
    for i in list_mode:
        print(i, end="/")

从上面的结果可以看出,对于文本类型,精准模式分词是最准确的

3、调整分词

有时候,我们更需要把文本里的"灰树叶"当成一个词语看待,jieba 提供了 add_word() 方法,可以实现分词的调整。新增如下代码:

jieba.add_word("灰树叶")

重新执行代码,精准模式的测试结果如下:

灰树叶/飘转/在/池塘/,/看/飞机/轰的一声/去/远乡/

4、词性分析

在汉语中,词性就是词语的分类,比如名词,形容词,动词等。前面说过 jieba 默认的分词器是 jieba.dt,即 jieba.Tokenizer(),所有全局分词相关函数都是该分词器的映射。而 jieba.posseg.dt 为默认的词性标注分词器。

我们可以通过词性标注分词器,查看词语的词性,如下:

import jieba as jieba
import jieba.posseg as posseg

text = '灰树叶飘转在池塘,看飞机轰的一声去远乡'
# jieba.add_word("灰树叶")
# jieba.add_word("看飞机")
# jieba.add_word("去远乡")
# 默认使用精准模式
cxs = posseg.lcut(text)
for i in cxs:
    print(i.word + i.flag, end='/')  # flag为词性

结果(不带分词调整):

灰n/树叶n/飘转v/在p/池塘ns/,x/看v/飞机n/轰的一声i/去v/远a/乡n/

每个词语后面的字符就是词性了,如果加上分词调整的话,对应的词性也会发生变化,如下:

灰树叶x/飘转v/在p/池塘ns/,x/看飞机x/轰的一声i/去远乡x/

jieba 默认的分词词性还是很丰富的,默认词性标注对照表,梳理如下:

标注解释标注解释标注解释
a形容词mq数量词tg时语素
ad副形词n名词u助词
ag形语素ng例:义 乳 亭ud例:得
an名形词nr人名ug例:过
b区别词nrfg人名uj例:的
c连词nrt人名ul例:了
d副词ns地名uv例:地
df例:不要nt机构团体uz例:着
dg副语素nz其他专名

v

动词
e叹词o拟声词vd副动词
f方位词p介词vg动语素
g语素q量词vi例:沉溺于 等同于
h前接成分r代词vn名动词
i成语rg例:兹vq例:去浄 去过 唸过
j简称略语rr人称代词x非语素字
k后接成分rz例:这位y语气词
l习用语s处所词z状态词
m数词t时间zg例:且 丗 丟

5、使用自定义词典

在利用 Jieba 分词时,调用的词库是它自带的一个 dict.txt 字典,使用的是默认分词器 jieba.dt,通常位于 Python 存放包文件的目录下 Lib\site-packages\jieba。

而默认的词库往往是不能满足我们的需求,分词效果也不太好,因此我们需要添加新词。开发者可以指定自己自定义的词典,以便包含 jieba 词库里没有的词,虽然 jieba 有新词识别能力,但是自行添加新词可以保证更高的正确率。

<1>. 自定义词典

第一步定义自己的词典文件,与 dict.txt 格式相同。每个单词占一行,且每行是由单词+词频+词性组成,用空格分割,顺序不能错乱,其中词频和词性是可省略的。

首先,参考 dict.txt 前几行内容,如下:

AT&T 3 nz
B超 3 n
c# 3 nz
C# 3 nz
c++ 3 nz
C++ 3 nz
T恤 4 n
A座 3 n
......

接着,找一段最近的新闻文本作为测试

9月30日,万里长征迈新步,雄关漫道不懈怠。面对错综复杂的国际环境、突飞猛进
的科技革命和产业变革,我们要以战略眼光、全局视野、系统思维,深刻认识到发展
大飞机事业的紧迫性和重要性。

最后,进行定义自己的词典 wxx_dt.txt,如下:

9月30日 300 t
战略眼光 10 nz
全局视野 10 nz
系统思维 10 nz

<2>. 使用自定义词典

通过 jieba.load_userdict(filename) 加载自定义词典,其中 filename 为词典的路径,测试如下:

import jieba as jieba

# 文本
text = '9月30日,万里长征迈新步,雄关漫道不懈怠。面对错综复杂的国际环境、突飞猛进的科技革命和产业变革,我们要以战略眼光、全局视野、系统思维,深刻认识到发展大飞机事业的紧迫性和重要性。'
# 自定义词典路径
filename = 'D:\\XXX\\wxx.txt'
# 加载自定义词典
jieba.load_userdict(filename)
# 使用自定义词典
default_rs = jieba.lcut(text)
for i in default_rs:
    print(i, end='/')

使用默认词典的效果:

/9/月/30/日/,/万里长征/迈新步/,/雄关/漫道/不/懈怠/。/面对/错综复杂/的/国际/环境/、/突飞猛进/
的/科技/革命/和/产业/变革/,/我们/要/以/战略眼光/、/全局/视野/、/系统/思维/,/深刻/认识/到
/发展/大/飞机/事业/的/紧迫性/和/重要性/。/

使用自定义词典的效果:

9月30日/,/万里长征/迈新步/,/雄关/漫道/不/懈怠/。/面对/错综复杂/的/国际/环境/、/突飞猛进/
的/科技/革命/和/产业/变革/,/我们/要/以/战略眼光/、/全局视野/、/系统思维/,/深刻/认识/到/
发展/大/飞机/事业/的/紧迫性/和/重要性/。/

<3>、调整词频词性

使用自定义词典,基本上可以将放在词典内词语进行组词,但可能会存在例外,比如曾经定义"国际环境"这个词,虽然调整了词频、词性仍然不能按照预想的结果输出/国际环境/,而输出的是/国际/环境/,此时可以通过 add_word() 调整分词,而/万里长征/ 我想拆开两个词语/万里/长征/,则可以通过 del_word() 调整分词。

词频也是影响词语的重要因素,如果不使用 add_word() 方式调整分词的话,那需要知道输出 /国际环境/ 的词频是怎样的?

我们可以使用 jieba.suggest_freq(segment, tune=True) 调节单个词语的词频,使其能(或不能)被分出来:

# 显示词频
freq = jieba.suggest_freq('国际环境', tune=True)
print(f'当前词语词频为:{freq}')  # 18
# 使用自定义词典
default_rs = jieba.lcut(text)
for i in default_rs:
    print(i, end='/')

注意:自动计算的词频在启用 HMM 新词发现功能时可能会失效,为了避免这一偶发情况,可以关闭HMM功能(默认 HMM 是开启的):

default_rs = jieba.lcut(text, HMM=False)

词典会受到分词词语,词频,词性的影响,而通过自定义词典、调整分词词语、调整词频、调整词性等方式,用户可以增强分词词语的歧义纠错功能。

三、Jieba 实战

随着信息科学技术的快速发展及互联网的普及,网络文本资源呈几何级数不断增长。面对更新日益频繁和规模庞大的文本数据,如何高效准确地实现关键词提取成为影响信息检索系统性能的关键。提取关键词是文本分类、文本聚类、信息检索等技术的基础,在NLP领域应用广泛。

jieba 提供了两种算法支持关键词的提取:一是基于 TF-IDF 算法的关键词抽取,二是基于 TextRank 算法的关键词抽取。

<1>、基于 TF-IDF 算法的关键词抽取

TF-IDF : Term Frequency-Inverse DocumentFrequency的简称,意思是词频-逆文件频率,是一种信息检索的加权算法,用于评估一个词语对于一个文件集或一个语料库中的其中一份文件的重要程度。词语的重要程度与它在文件中出现的次数成正比,与它在语料库出现的频率成反比,简单的理解就是,一个词语在一篇文章中出现次数越多,同时在所有文档中出现次数越少,越能够代表该文章了。

TF词频,表达的是一个词语在文本中出现的频率。实际情况中,一些通用的词语对主题并没有太大作用,反倒是一些出现频率较少的词语才能够表达文章的主题。因此,单纯使用TF是不合适的,需要使用加权算法的思想,即一个词预测主题的能力越强,权重越大,否则,权重越小!

IDF逆文件频率,则表达的是基于权重的一个词语在语料库中出现的频率,即语料库中出现该词语越少,IDF越大。因此,TF与IDF组合才能真正反映提取的关键词重要性。

明白了原理之后,可以实操了,实操之前了解下源码, jieba 提供的 TF-IDF 算法位于 jieba.analyse 包,看下 __init__.py 源码:

# TextRank算法与TF-IDF使用上相似
......
# 通过构造器创建TFIDF对象、TextRank对象,其中TFIDF的idf_path=None
default_tfidf = TFIDF()
default_textrank = TextRank()
# 通过TFIDF对象实例,访问extract_tags()
extract_tags = tfidf = default_tfidf.extract_tags
# 自定义设置idf文件语料库的路径
set_idf_path = default_tfidf.set_idf_path
# 通过TextRank对象实例,访问extract_tags()
textrank = default_textrank.extract_tags

# 自定义设置停用词语料库的路径
def set_stop_words(stop_words_path):
    default_tfidf.set_stop_words(stop_words_path)
    default_textrank.set_stop_words(stop_words_path)

这里,有几个概念需要区分下:

  • 语料库:汇集并存放语言材料的地方;
  • IDF语料库:体现特定词语预测主题能力的权重而设置的逆频率文件;
  • 停用词语料库:进行信息检索时而设置忽略词语的语料库,比如标点符号,拟声词,语气词等。

1.1. extract_tags() 方法

# sentence文本,withWeight权重,allowPOS词性
extract_tags(sentence, topK=20, withWeight=False, allowPOS=(), withFlag=False)

参数说明,源码里注释已经很清晰了,如下:

Parameter:    - topK: return how many top keywords. `None` for all possible words.    - withWeight: if True, return a list of (word, weight);            if False, return a list of words.    - allowPOS: the allowed POS list eg. ['ns', 'n', 'vn', 'v','nr'].            if the POS of w is not in this list,it will be filtered.    - withFlag: only work with allowPOS is not empty.            if True, return a list of pair(word, weight) like posseg.cut            if False, return a list of words

接下来,演示使用 TFIDF 算法提取关键字,测试代码如下:

import jieba.analyse as analyse

""" 使用TFIDF算法提取关键字 """
# source_path为网上找的《2021年美国侵犯人权报告》.txt
with open(source_path, mode='r', encoding='utf-8') as f:
    context = f.read()
    # 默认使用TFIDF算法,也可以使用TFIDF()
    tags = analyse.extract_tags(context, topK=10)
    
    # 显示前10
    tags1 = analyse.TFIDF().extract_tags(context, topK=10)
    print(f'tags1: {tags1}')

    # 显示前10、显示权重占比
    tags2 = analyse.TFIDF().extract_tags(context, topK=10, withWeight=True)
    print(f'tags2: {tags2}')

    # 显示前10、显示指定词性词语
    tags3 = analyse.TFIDF().extract_tags(context, topK=10, allowPOS=(['ns', 'n', 'vn', 'v', 'nr']))
    print(f'tags3: {tags3}')

1.2.自定义IDF文件语料库

jieba 官网提供了一份idf语料库可以下载使用,有两种方式可以设置:

import jieba.analyse as analyse

idf_path = 'D:\\XXX\\idf.txt.big'

""" 使用TFIDF算法提取关键字,使用自定义idf语料库 """
with open(source_path, mode='r', encoding='utf-8') as f:
    context = f.read()

    # 方式1:通过TFIDF构造器加入 idf_path
    tagsA = analyse.TFIDF(idf_path=idf_path).extract_tags(context)

    # 方式2:通过set_idf_path方法设置  idf_path
    idf = analyse.set_idf_path(idf_path)
    analyse.extract_tags(context)

1.3.自定义停用词语料库

这里,有几份不错的中文常用的停用词表,可以下载使用

# 自定义停用词: 使用百度停用词表
sw_path = 'D:\\XXX\\baidu_stopwords.txt'
sw = analyse.set_stop_words(sw_path)
analyse.extract_tags(context)

<2>、基于 TextRank 算法的关键词抽取

TextRank:是一种用于文本的基于图的排序算法。其基本思想来源于谷歌的PageRank算法,即通过把文本分割成若干组成单元(单词、句子)并建立图模型,利用投票机制对文本中的重要成分进行排序,仅利用单篇文档本身的信息即可实现关键词提取、文摘提取。和LDA、HMM等模型不同,TextRank不需要事先对多篇文档进行学习训练,因其简洁有效而得到广泛应用。

jieba.analyse.TextRank()的流程为:

  • (1)将待抽取关键词的文本进行分词;
  • (2)以固定窗口(默认为5),完成词之间的共现关系;
  • (3)计算每个顶点间的权重,完成无向带权图。

共现关系,将文本进行分词,去除停用词或词性筛选等之后,设定窗口长度为K,即最多只能出现K个词,而后进行窗口滑动,在窗口中共同出现的词之间即可建立起无向边。

TextRank算法是利用局部词汇之间关系(共现窗口)对后续关键词进行排序,直接从文本本身抽取。关键词抽取的任务,就是从一段给定的文本中自动抽取出若干有意义的词语或词组。

1.1. textrank() 方法

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

参数说明,源码里注释也已经很清晰了,如下:

Parameter:    - topK: return how many top keywords. `None` for all possible words.    - withWeight: if True, return a list of (word, weight);                if False, return a list of words.    - allowPOS: the allowed POS list eg. ['ns', 'n', 'vn', 'v'].                if the POS of w is not in this list, it will be filtered.    - withFlag: if True, return a list of pair(word, weight) like posseg.cut                if False, return a list of words

使用 TextRank 算法提取关键字,测试代码如下:

import jieba.analyse as analyse

""" 使用 TextRank 算法提取关键字 """
with open(source_path, mode='r', encoding='utf-8') as f:
    context = f.read()
    
    rank1 = analyse.textrank(context, topK=10)
    print(f'rank1: {rank1}')

    rank2 = analyse.TextRank().extract_tags(context, topK=10)
    print(f'rank2: {rank2}')

    rank3 = analyse.default_textrank.extract_tags(context, topK=10, withWeight=True)
    print(f'rank3: {rank3}')

1.2. 自定义停用词语料库

# 自定义停用词: 使用中文停用词表
sw_path = 'D:\\XXX\\cn_stopwords.txt'
sw = analyse.default_textrank.set_stop_words(sw_path)
analyse.textrank(context)

<3>、两种算法进行关键词抽取的总结

TextRank 算法提取是依据词语之间的贡献关系来构建图,计算图中节点的 Rank;而 TF-IDF 算法跟 Jieba 分词一样,首先自己有一个默认词库,内含相应的词语与词频,更多的是依据 dict.txt 来计算词频与逆向词频权重。

<4>、生成词云

上面实现了对文本文件的数据进行处理,并提取了关键词。如果把 topK 参数调节成50或者100个进行输出的话,此时借助词云则可以更直观的展示文本的内容。

首先,需要下载相关依赖:

pip install wordcloud

接着,介绍下使用词云的步骤:

  1. 文本分词处理:比如,精准模式/全模式等分词的结果,通过 TF-IDF 或 TextRank 等提取的关键词的结果等,将作为词云对象的生成器入参使用;
  2. 构造词云对象 WordCloud:通过词云对象调整参数配置;
  3. 输出显示:通过 matplotlib 的子模块 pyplot 显示词云。

请注意,根据需求调节对应的参数,词云对象 WordCloud 参数,如下:

def __init__(self, font_path=None, width=400, height=200, margin=2,
                 ranks_only=None, prefer_horizontal=.9, mask=None, scale=1,
                 color_func=None, max_words=200, min_font_size=4,
                 stopwords=None, random_state=None, background_color='black',
                 max_font_size=None, font_step=1, mode="RGB",
                 relative_scaling='auto', regexp=None, collocations=True,
                 colormap=None, normalize_plurals=True, contour_width=0,
                 contour_color='black', repeat=False,
                 include_numbers=False, min_word_length=0, collocation_threshold=30):
                 ......

接下来,以 TextRank 算法提取关键词为例,代码如下:

import jieba.analyse as analyse
import wordcloud as wc
import matplotlib
matplotlib.use('TkAgg')
import matplotlib.pyplot as plt

with open(source_path, 
          mode='r',
          encoding='utf-8'
          ) as f:
    context = f.read()
    # 显示前100
    rank1 = analyse.textrank(context, topK=100)
    print(f'rank1: {rank1}')
    # 用空格分割
    wc_text = ' '.join(rank1)
    # 构造词云对象,并调节显示词云的参数
    wc_Obj = wc.WordCloud(
        font_path=r'.\simhei.ttf',
        background_color='white',
        width=1000,
        height=900,
    ).generate(wc_text)
    # 可视化显示
    plt.imshow(wc_Obj, interpolation='bilinear')
    plt.axis('off')
    plt.show()

当然,也可以使用带有图片背景的词云(百度找一张照片即可),我们通过调节词云对象的 color_func 、mask 和 scale 等参数即可,新增如下代码:

import numpy as np
import PIL.Image as image

    # 使用地图作为词云图片
    background_img = np.array(image.open('D:\\XXX\\demoMap.jpg'))
    color_func = wc.ImageColorGenerator(background_img)
    # 调节入参:图片随机颜色color_func,背景图片mask,清晰度scale
    wc_Obj = wc.WordCloud(
        ......
        color_func=color_func,
        mask=background_img, 
        scale=18,
        ......
    ).generate(text_wc)

Python 中文分词组件 Jieba 的使用就演示到这里了。

  • 0
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值