avatar


4.jieba、wordcloud和wordninja

jieba

与英文不同,在中文中,词与词之间不以空格来隔开。所以这时候,需要进行分词。那么,jieba就是一个分词工具,而且开源。

jieba的Github地址:https://github.com/fxsjy/jieba

我们主要介绍这些内容

  1. 分词
  2. 自定义词典
  3. 关键词提取

分词

分词模式

网上很多过时的资料都是说jieba一共有三种分词模式,但其实根据官网的描述,从v0.40开始,一共有四种分词模式。

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

当然,一般常用的还是前面3种。

分词方法

我们介绍两种分词方法

  1. cut()
  2. cut_for_search()

cut

1
jieba.cut()

该方法传入四个参数:

  1. sentence: 分词句子
  2. cut_all: 是否分词所有,默认False
  3. HMM: 是否使用隐马可夫模型,默认True
  4. use_paddle: 是否使用paddle,默认False

说明:

  1. cut_allFalse的时候,就是精准模式;当cut_allTrue的时候,就是全模式。
  2. HMMTrue的时候,会添加其学习到新词;当HMMFalse的时候,不会添加其学习到新词。

示例代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import jieba

sentence = "当亚平宁的微风,吹过飘逸的长发,当地中海的湛蓝,照进深邃的眼神。"

print(sentence)

print("精确模式")
seg_list = jieba.cut(sentence, cut_all=False)
print("/ ".join(seg_list))
seg_list = jieba.cut(sentence, cut_all=False,HMM=False)
print("/ ".join(seg_list))

print("全模式")
seg_list = jieba.cut(sentence, cut_all=True)
print("/ ".join(seg_list))
seg_list = jieba.cut(sentence, cut_all=True,HMM=False)
print("/ ".join(seg_list))

print("默认模式")
seg_list = jieba.cut(sentence)
print("/ ".join(seg_list))

运行结果:

1
2
3
4
5
6
7
8
9
当亚平宁的微风,吹过飘逸的长发,当地中海的湛蓝,照进深邃的眼神。
精确模式
当/ 亚平宁/ 的/ 微风/ ,/ 吹过/ 飘逸/ 的/ 长发/ ,/ 当/ 地中海/ 的/ 湛蓝/ ,/ 照进/ 深邃/ 的/ 眼神/ 。
当/ 亚平宁/ 的/ 微风/ ,/ 吹/ 过/ 飘逸/ 的/ 长发/ ,/ 当/ 地中海/ 的/ 湛蓝/ ,/ 照进/ 深邃/ 的/ 眼神/ 。
全模式
当/ 亚平/ 亚平宁/ 的/ 微风/ ,/ 吹/ 过/ 飘逸/ 的/ 长发/ ,/ 当地/ 地中/ 地中海/ 中海/ 的/ 湛蓝/ ,/ 照进/ 进深/ 深邃/ 的/ 眼神/ 。
当/ 亚平/ 亚平宁/ 的/ 微风/ ,/ 吹/ 过/ 飘逸/ 的/ 长发/ ,/ 当地/ 地中/ 地中海/ 中海/ 的/ 湛蓝/ ,/ 照进/ 进深/ 深邃/ 的/ 眼神/ 。
默认模式
当/ 亚平宁/ 的/ 微风/ ,/ 吹过/ 飘逸/ 的/ 长发/ ,/ 当/ 地中海/ 的/ 湛蓝/ ,/ 照进/ 深邃/ 的/ 眼神/ 。
1
jieba.cut_for_search

该方法传入两个参数:

  1. sentence: 分词句子
  2. HMM: 是否使用隐马可夫模型,默认True

示例代码:

1
2
3
4
5
6
7
8
9
10
11
import jieba

sentence = "当亚平宁的微风,吹过飘逸的长发,当地中海的湛蓝,照进深邃的眼神。"

print(sentence)

print("搜索模式")
seg_list = jieba.cut_for_search(sentence)
print("/ ".join(seg_list))
seg_list = jieba.cut_for_search(sentence,HMM=False)
print("/ ".join(seg_list))

运行结果:

1
2
3
4
当亚平宁的微风,吹过飘逸的长发,当地中海的湛蓝,照进深邃的眼神。
搜索模式
当/ 亚平/ 亚平宁/ 的/ 微风/ ,/ 吹过/ 飘逸/ 的/ 长发/ ,/ 当/ 地中/ 中海/ 地中海/ 的/ 湛蓝/ ,/ 照进/ 深邃/ 的/ 眼神/ 。
当/ 亚平/ 亚平宁/ 的/ 微风/ ,/ 吹/ 过/ 飘逸/ 的/ 长发/ ,/ 当/ 地中/ 中海/ 地中海/ 的/ 湛蓝/ ,/ 照进/ 深邃/ 的/ 眼神/ 。

自定义词典

jieba有自己的词库,还可以通过HMM去学习新词。而且我们还可以新增、删除或者修改词语。

新增词语

jieba中新增词语有两种方法。

  1. add_word()
  2. load_userdict()

add_word

1
jieba.add_word()

该方法传入三个三个参数:

  1. word:需要新增的单词
  2. freq:词频(非必须)
  3. tag:词性(非必须)

示例代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import jieba

sentence = "当亚平宁的微风,吹过飘逸的长发,当地中海的湛蓝,照进深邃的眼神。"

print(sentence)

print("默认模式")
seg_list = jieba.cut(sentence)
print("/ ".join(seg_list))

print("添加词语:亚平宁的微风")
jieba.add_word('亚平宁的微风')
seg_list = jieba.cut(sentence)
print("/ ".join(seg_list))

运行结果:

1
2
3
4
5
当亚平宁的微风,吹过飘逸的长发,当地中海的湛蓝,照进深邃的眼神。
默认模式
当/ 亚平宁/ 的/ 微风/ ,/ 吹过/ 飘逸/ 的/ 长发/ ,/ 当/ 地中海/ 的/ 湛蓝/ ,/ 照进/ 深邃/ 的/ 眼神/ 。
添加词语:亚平宁的微风
当/ 亚平宁的微风/ ,/ 吹过/ 飘逸/ 的/ 长发/ ,/ 当/ 地中海/ 的/ 湛蓝/ ,/ 照进/ 深邃/ 的/ 眼神/ 。

load_userdict

1
jieba.load_userdict()

该方法传入一个参数

  1. f:自定义字典文件

一般用该方法批量添加自定义词。

其字典文件格式如下

1
2
word1 freq1 tag1
word2 freq2 tag2

一个词语一行,词语、词频和词性之间用空格隔开。同样,词频和词性非必须。

删除词语

1
jieba.del_word()

该方法传入一个参数:

  1. word:要被删除的词语

示例代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import jieba

sentence = "当亚平宁的微风,吹过飘逸的长发,当地中海的湛蓝,照进深邃的眼神。"

print(sentence)

print("默认模式")
seg_list = jieba.cut(sentence)
print("/ ".join(seg_list))

print("删除词语:微风")
jieba.del_word("微风")
seg_list = jieba.cut(sentence)
print("/ ".join(seg_list))

运行结果:

1
2
3
4
5
当亚平宁的微风,吹过飘逸的长发,当地中海的湛蓝,照进深邃的眼神。
默认模式
当/ 亚平宁/ 的/ 微风/ ,/ 吹过/ 飘逸/ 的/ 长发/ ,/ 当/ 地中海/ 的/ 湛蓝/ ,/ 照进/ 深邃/ 的/ 眼神/ 。
删除词语:微风
当/ 亚平宁/ 的/ 微/ 风/ ,/ 吹过/ 飘逸/ 的/ 长发/ ,/ 当/ 地中海/ 的/ 湛蓝/ ,/ 照进/ 深邃/ 的/ 眼神/ 。

查看和修改词频

查看词频

1
jieba.get_FREQ()

该方法有一个参数:

  1. word:词语

修改词频

1
jieba.suggest_freq()

特别注意:修改词频,只能修改大。
该方法有两个参数:

  1. segment:要被修改的词
  2. tune:是否调整词频,默认为False

示例代码:

1
2
3
4
5
6
7
import jieba

print(jieba.get_FREQ("白马"))
jieba.suggest_freq("白马",tune=True)
print(jieba.get_FREQ("白马"))
jieba.suggest_freq("白马",tune=False)
print(jieba.get_FREQ("白马"))

运行结果:

1
2
3
706
707
707

关键词提取

jieba中的关键词提取有两种方法:

  1. 基于 TF-IDF 算法的关键词抽取
  2. 基于 TextRank 算法的关键词抽取

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

1
jieba.analyse.extract_tags()

传入4个参数:

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

示例代码:

1
2
3
4
import jieba.analyse
sentence = "当亚平宁的微风,吹过飘逸的长发,当地中海的湛蓝,照进深邃的眼神。"
print(sentence)
print(jieba.analyse.extract_tags(sentence,withWeight=True))

运行结果:

1
2
当亚平宁的微风,吹过飘逸的长发,当地中海的湛蓝,照进深邃的眼神。
[('亚平宁', 1.0765183435999999), ('照进', 1.0765183435999999), ('湛蓝', 1.02117981979), ('吹过', 0.9949433933390001), ('飘逸', 0.971102290995), ('微风', 0.9237238557859999), ('长发', 0.912999302751), ('深邃', 0.897342396682), ('眼神', 0.76604018068), ('地中海', 0.732281629425)]

基于TextRank算法的关键词抽取

1
jieba.analyse.textrank()

传入4个参数:

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

wordcloud

wordcloud,顾名思义,词云。这个工具包也和jieba一样,开源。

wordcloud的GitHub地址:https://github.com/amueller/word_cloud

wordcloud的官方文档:http://amueller.github.io/word_cloud/

如图,这是金庸《射雕英雄传》的词云。

射雕英雄传

我们以这个为例。

步骤为

  1. 基于TF-IDF算法的抽取关键词
  2. 生成词云对象
  3. 根据词云对象绘图

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

示例代码:

1
2
3
4
5
6
7
8
9
10
import jieba.analyse

# 打开文件
with open('射雕英雄传.txt', 'rb') as f:
# 读取文件
data = f.read()

words = jieba.analyse.extract_tags(data,topK=100)
cuted = ' '.join(words)
print(cuted)

运行结果:

1
郭靖 黄蓉 洪七公 欧阳锋 黄药师 周伯通 甚么 黄蓉道 武功 丘处机 郭靖道 师父 欧阳克 梅超风 说道 柯镇恶 裘千仞 爹爹 两人 功夫 完颜洪烈 心中 只见 铁木真 穆念慈 杨康 咱们 心想 完颜康 当下 一声 自己 陆冠英 彭连虎 不知 杨铁心 成吉思汗 叫化 一个 梁子翁 六怪 桃花岛 拖雷 朱聪 帮主 这时 王处一 之中 左手 身子 眼见 丐帮 弟子 只是 靖哥哥 包惜弱 九阴真经 不是 华筝 黄蓉笑 韩小莹 不敢 知道 地下 原来 却是 韩宝驹 右手 侯通海 老顽童 他们 不禁 一招 沙通天 喝道 双手 众人 二人 蒙古 出来 如此 哪里 铁掌 老毒物 心下 兄弟 一阵 伸手 怎么 突然 黄老邪 郭靖心 马钰 只怕 尹志平 你们 正是 性命 傻姑 鲁有脚

生成词云对象

1
wordcloud.WordCloud()

该方法有多个参数,其中比较常用的有:

  1. font_path:字体文件路径
  2. background_color:背景颜色
  3. max_words:最大词数
  4. max_font_size:最大字体
  5. min_font_size:最小字体
  6. random_state:随机数种子
  7. width:图片的宽
  8. height:图片的高
  9. margin:图片的边距
  10. mask:遮挡

注意:wordcloud的默认字体不支持中文,所以如果需要中文,必须设置支持中文的字体文件路径。

示例代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
from wordcloud import WordCloud

fontpath = '王羲之书法字体.ttf'

wc = WordCloud(font_path=fontpath, # 设置字体
background_color="white", # 背景颜色
max_words=100, # 词云显示的最大词数
max_font_size=500, # 字体最大值
min_font_size=20, #字体最小值
random_state=42, #随机数
collocations=True, #避免重复单词
width=1600,height=1200,margin=10, #图像宽高,字间距,需要配合下面的plt.figure(dpi=xx)放缩才有效
)
wc.generate(cuted)

print(wc)

运行结果:

1
<wordcloud.wordcloud.WordCloud object at 0x04257590>

根据词云对象绘图

我们调用matplotlib根据词云对象进行绘图。
示例代码:

1
2
3
4
5
6
from matplotlib import pyplot as plt

plt.figure(dpi=100) #通过这里可以放大或缩小
plt.imshow(wc, interpolation='catrom',vmax=1000)
plt.axis("off") #隐藏坐标
plt.show()

运行结果:
射雕英雄传

完整的代码已经PUSH到了我的GitHub上
https://github.com/KakaWanYifan/SheDiaoYingXiongZhuan-JiebaWordcloud

wordninja

连续英文字符串的分割

如果是用下划线_来拼接的话,那么非常简单。
例如user_nameprice_earnings_ratiohtml_a_content,我们通过下划线_分割,然后从第二个项开始,首字母大写。

示例代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
l = ['user_name', 'price_earnings_ratio', 'html_a_content']

for src in l:
sl = src.split('_')
des = ''
index = 0
for sl_item in sl:
if index == 0 or len(sl_item) == 1:
des = des + sl_item
else:
des = des + sl_item.title()
index = index + 1

print(src)
print(des)
print()

运行结果:

1
2
3
4
5
6
7
8
user_name
userName

price_earnings_ratio
priceEarningsRatio

html_a_content
htmlaContent

解释说明:

  • .title():首字母大写。

分词

但,如果是连续的呢?
例如,usernamepriceearningsratiohtmlacontent
这个时候,就需要借助第三方的包wordninja
分词的方法为:wordninja.split(被分词的对象)

示例代码:

1
2
3
import wordninja
s = 'ilovechina'
print(wordninja.split(s))

运行结果:

1
['i', 'love', 'china']

小驼峰

将连续的英文字符串转成小驼峰(Python),示例代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import wordninja

l = ['username', 'priceearningsratio', 'htmlacontent']

for src in l:
sl = wordninja.split(src)
des = ''
index = 0
for sl_item in sl:
if index == 0 or len(sl_item) == 1:
des = des + sl_item
else:
des = des + sl_item.title()

index = index + 1

print(src)
print(des)
print()

运行结果:

1
2
3
4
5
6
7
8
username
username

priceearningsratio
priceEarningsRatio

htmlacontent
htmlaContent

修改词库

我们看到username,结果依旧是username
wordninja是基于维基百科语料的频率来进行分词的,如果想对特有名词进行正确分割,需要修改词库,将特有名词加入词库中。
我们可以通过如下的地址 https://github.com/keredson/wordninja/ ,找到词库,在wordninja目录下,wordninja_words.txt.gz
解压后,我们添加单词user,并删去username,然后重新打成.gz包,再使用LanguageModel加载。

示例代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import wordninja

l = ['username', 'priceearningsratio', 'htmlacontent']

for src in l:
myw = wordninja.LanguageModel('wordninja_words.txt.gz')
sl = myw.split(src)
des = ''
index = 0
for sl_item in sl:
if index == 0 or len(sl_item) == 1:
des = des + sl_item
else:
des = des + sl_item.title()

index = index + 1

print(src)
print(des)
print()

运行结果:

1
2
3
4
5
6
7
8
username
userName

priceearningsratio
priceEarningsRatio

htmlacontent
htmlaContent

关于打成.gz包:

文章作者: Kaka Wan Yifan
文章链接: https://kakawanyifan.com/10304
版权声明: 本博客所有文章版权为文章作者所有,未经书面许可,任何机构和个人不得以任何形式转载、摘编或复制。

评论区