利用jieba分词,构建词云图

注:参考文档

一、在线词云图工具#

(1)、使用###

在正式使用jieba分词之前,首先尝试用在线分词工具来将自己采集的结果可视化,选择的是BlueMC在线词云工具,其数据源有粘贴文本、上传excel等格式,我粘贴了一位老师的简历内容进行分析。文本即:

男,1976年出生,湖南平江人。中山大学哲学系哲学博士,四川大学哲学系副教授。以先秦、两汉儒家为主要研究方向,承担儒家哲学相关的教学与科研工作,目前开设的课程有中国哲学史(先秦两汉经学部分)、中国哲学名著研读(《周易》)、古代汉语、中华文化课(哲学篇)等.

通过调整其词语显示,其分词结果如下:

在线分词效果

(2)、总结###

通过这里使用在线的词云工具,可以知道制作词云图首先需要将句段内容拆分,然后调整词语的显示级别。

二、使用jieba制作词云图#

(1)有关的基本知识###

Jieba是python比较好用的分词模块,可用于中文句子/词性分割、词性标注、未登录词识别,支持用户词典等功能。能较好实现中文分词,同时支持繁体分词。
jieba.cut()提供了三种分词模式,比较如下:

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

(2)安装jieba###

安装相应的包:通过指令语句安装jieba分词包,代码:

pip install jieba

顺便将“pip”版本较低,顺便一起更新了。安装成功结果显示:

安装jieba分词包

(3)、使用jieba###

  • 分词

在root/venv下新建jieba文件夹,然后在其中新建一个python文件test.py。

# encoding=utf-8

import jieba
seg_list = jieba.cut("我是成都四川大学的江苏人", cut_all=True)
print "Full Mode:", "/ ".join(seg_list)  # 全模式
seg_list = jieba.cut("我是成都四川大学的江苏人", cut_all=False)
print "Default Mode:", "/ ".join(seg_list)  # 精确模式
seg_list = jieba.cut("他去了神州天网易云音乐")  # 默认是精确模式
print ", ".join(seg_list)
seg_list = jieba.cut_for_search("蔡某硕士毕业于江苏大学研究院,然后在清华北京大学深造")  # 搜索引擎模式
print ", ".join(seg_list)

执行这个文件,可以得到三种模式下的结果:


jieba三种分词模式的测试结果

然后在同一目录新建一个test1.py文件,待分词的内容是采集回来的教师信息一位的成果文本内容:

# encoding=utf-8

import jieba
seg_list = jieba.cut("主要学术兴趣方向为德法现象学和康德哲学。个人专著为《胡塞尔直观概念的起源:以意向性为线索的早期文本研究》(江苏人民出版社,2009)。论文译文多篇,代表性论文有《胡塞尔、海德格尔和康德的第一版先验演绎》(载于《斯人在思——叶秀山先生七十华诞纪念文集》,江苏人民出版社,2006,第440-462页),《胡塞尔〈逻辑研究〉的直观与意义》(载于《哲学研究》,3(2007):68-75)等。", cut_all=True)
print "Full Mode:", "/ ".join(seg_list)  # 全模式

执行这个文件,得到分词结果如下:

公管一位教师的成果内容分词结果
  • 自定义词典

在jieba文件夹中新建一个userdict.txt文件,在这个文件中自定义词汇,以包含jieba词库中没有的词,比如这里可以将网络爆发词定义,以便准确分词。
按照自定义词典文档词典导入文档可知:
1.词典格式和 dict.txt 一样,一个词占一行;每一行分三部分:词语、词频(可省略)、词性(可省略),用空格隔开,顺序不可颠倒。
2.用法: jieba.load_userdict(file_name) # file_name 为文件类对象或自定义词典的路径
3.词频省略时使用自动计算的能保证分出该词的词频。

以下为我定义的新词(没有设置词频,也没有设置其格式):

蓝瘦
香菇
很傻很天真
我的小伙伴们
何弃疗
累觉不爱
吓死宝宝

然后在jieba文件夹中新建test_userdict.py文件,内容如下:

# encoding=utf-8

from __future__ import print_function, unicode_literals
import sys
sys.path.append("../")
import jieba
jieba.load_userdict("userdict.txt")
import jieba.posseg as pseg

jieba.add_word('蓝瘦')
jieba.add_word('香菇')
jieba.del_word('累觉不爱')
jieba.del_word('很傻很天真')
jieba.del_word('我的小伙伴们')
jieba.del_word('何弃疗')
jieba.del_word('友谊的小船')
jieba.del_word('说翻就翻')
jieba.del_word('吓死宝宝')
jieba.add_word('我好方')
jieba.add_word('倒数第一')

test_sent = (
"今天去食堂吃饭没有肉了,蓝瘦香菇\n"
"前天去爬山的时候脚崴了,结果还得继续出去工作,累觉不爱\n"
"你不是真的关心我,咱们俩友谊的小船说翻就翻\n"
"你真的是很傻很天真,我的小伙伴们都觉得你好傻\n"
"一不小心得了个全班倒数第一,我好方"
)
words = jieba.cut(test_sent)
print('/'.join(words))
自定义词典之后的结果

以“蓝瘦香菇”为例,自定义词典之前并不会分出蓝瘦与香菇:

自定义词典之前分词效果

对于新的词汇,可以通过自定义词典进行定义,还可以在python文件中即时进行修改,通过add_word(word, freq=None, tag=None) 和 del_word(word)的方式。
同时,还可以使用suggest_freq(segment, tune=True) 来调节单个词语的词频,使其能(或不能)被分出来。
如在我新建的test_userdict.py文件中加上以下语句:

print('/'.join(jieba.cut('如果你永远不会抛弃我。', HMM=False)))
jieba.suggest_freq(('不', '会'), True)
print('/'.join(jieba.cut('如果你永远不会抛弃我。', HMM=False)))

执行该文件后,可以将“不”与“会”拆开为单个词语。

调整单个词语的显示
  • 关键词抽取###

关键词能够反映文本主题或思想,关键词抽取就是从文本中抽取跟这篇文档意义最相关一些词。
关键词抽取从方法来说大致有两种:
1.关键词分配,给定的关键词库,从词库里面找出几个词语作为这篇文档的关键词;
2.关键词抽取,从文档中抽取一些词语作为这篇文档的关键词;

从算法的角度来看,关键词抽取算法主要有两类:
1.有监督学习算法,将关键词抽取过程视为二分类问题,先抽取出候选词,然后对于每个候选词划定标签,要么是关键词,要么不是关键词,然后训练关键词抽取分类器。当新来一篇文档时,抽取出所有的候选词,然后利用训练好的关键词抽取分类器,对各个候选词进行分类,最终将标签为关键词的候选词作为关键词;
2.无监督学习算法,先抽取出候选词,然后对各个候选词进行打分,然后输出topK个分值最高的候选词作为关键词。根据打分的策略不同,有不同的算法,例如TF-IDF,TextRank等算法;
(以上关于关键词的总结来源于网络博客

对于jieba而言,其分词系统基于TF-IDF关键词抽取算法和基于TextRank关键词抽取算法。

以下是两种算法介绍:

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

引入关键词抽取关键代码是:

import jieba.analyse

TF-IDF即是Term Frequency - Inverse Document Frequency的简称,是数值统计。其主要思想是:某词在文档中出现频率高,即TF高;并且在语料库中其他文档中很少出现,则DF的低,即IDF高,这时认为这个词具有很好的类别区分能力。

TF-IDF在实际中主要是将二者相乘,也即TF * IDF,TF为词频(Term Frequency),表示词t在文档d中出现的频率;IDF为反文档频率(Inverse Document Frequency),表示语料库中包含词t的文档的数目的倒数。

TF计算公式为:

TF=count(t)count(di)TF=count(t)count(di)。

count(t)表示文档di中包含词t的个数;count(di)表示文档di的词的总数;

IDF计算公式为:

IDF=num(corpus)num(t)+1IDF=num(corpus)num(t)+1。

num(corpus)表示语料库corpus中文档的总数;num(t)表示语料库corpus中包含t的文档的数目;

接下来在#venv/jieba下新建文件extract_tags.py,代码如下:

# -*- coding: utf-8 -*-
import sys
sys.path.append('../')

import jieba
from jieba import analyse
from optparse import OptionParser

tfidf = analyse.extract_tags
text = "当你快乐的时候,生活是美好的,当有人因你而快乐的时候,生活才是最美好的。\
        难过时,吃一粒糖,告诉自己生活是甜的!\
        如果你的生活已处于低谷,那就,大胆走,因为你怎样走都是在向上。\
        通往光明的道路是平坦的,为了成功,为了奋斗的渴望,我们不得不努力。\
        一个人至少拥有一个梦想,有一个理由去坚强。心若没有栖息的地方,到哪里都是在流浪。"
keywords = tfidf(text)
print "keywords by tfidf:"

for keyword in keywords:
    print keyword + "/",

这里一定注意导入“analyse”,并且要在首行写明编码方式。
执行该文件,可以得到:

TF-IDF关键词抽取

同时:关键词提取所使用逆向文件频率(IDF)文本语料库可以换成自定义语料库。文件内容格式大致如下:

IDF自定义语料库格式

使用时需要在python文件中加上:

jieba.analyse.set_idf_path("../******");
其中“******”代表的是自己新建的逆向文件频率语料文件。

停止词(Stop Words)文本语料库也可以换成自定义语料库。文件格式大致如下:


停用词自定义语料库格式

使用时需在python文件中加上:

jieba.analyse.set_stop_words("../******")
其中“******”代表的是自己新建的停用词语料文件。

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

思想与PageRank类似,将文本中的语法单元视作图中的节点,如果两个语法单元存在一定语法关系(例如共现),则这两个语法单元在图中就会有一条边相互连接,通过一定的迭代次数,最终不同的节点会有不同的权重,权重高的语法单元可以作为关键词。

节点的权重不仅依赖于它的入度结点,还依赖于这些入度结点的权重,入度结点越多,入度结点的权重越大,说明这个结点的权重越高;

TextRank迭代计算公式为:

WS(Vi)=(1−d)+d∗∑Vj∈In(Vi)wji∑Vk∈Out(Vj)wjk∗WS(Vj)WS(Vi)=(1−d)+d∗∑Vj∈In(Vi)wji∑Vk∈Out(Vj)wjk∗WS(Vj)

节点i的权重取决于节点i的邻居节点中i-j这条边的权重 / j的所有出度的边的权重 * 节点j的权重,将这些邻居节点计算的权重相加,再乘上一定的阻尼系数,就是节点i的权重;阻尼系数 d 一般取0.85;

在#venv/jieba文件夹之下新建textrank.py文件,其代码如下:

# -*- coding: utf-8 -*-
import sys
sys.path.append('../')

import jieba
from jieba import analyse
textrank = analyse.textrank
from optparse import OptionParser

text = "当你快乐的时候,生活是美好的,当有人因你而快乐的时候,生活才是最美好的。\
        难过时,吃一粒糖,告诉自己生活是甜的!\
        如果你的生活已处于低谷,那就,大胆走,因为你怎样走都是在向上。\
        通往光明的道路是平坦的,为了成功,为了奋斗的渴望,我们不得不努力。\
        一个人至少拥有一个梦想,有一个理由去坚强。心若没有栖息的地方,到哪里都是在流浪。"
keywords = textrank(text)
print "keywords extracted by TextRank:"

for keyword in keywords:
    print keyword + "/",

执行该python文件,得到结果如下:

textrank的关键词抽取
  • 词性标注###

在#venv/jieba问价夹下新建postag.py文件,代码如下:

# -*- coding: utf-8 -*-
import jieba
jieba.load_userdict("userdict.txt")
import jieba.posseg as pseg
words = pseg.cut("我爱四川大学中快食堂的饭菜")
for word, flag in words:
    print('%s %s' % (word, flag))

其中词性标准默认的词性标注分词器。将“中快”纳入自定义词典。

词性标注

不过目前不太明白其工作机制,以及词性含义。

  • (其他)Tokenize:返回词语在原文的起止位置###

在#venv/jieba文件夹下新建other.py文件。代码如下:

# -*- coding: utf-8 -*-
import jieba
jieba.load_userdict("userdict.txt")
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]))
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]))

结果如下:


tokenize的两种模式结果对照
  • (其他)命令行分词###

语句:

python -m jieba infos.txt >result.txt

infos.csv未处理,就是采集下来的文件。(后续需清理之后再执行这个操作)


命令行分词结果

分词结果是:

命令行结果

推荐阅读更多精彩内容