用python实现词频分析+词云
2021.02.17更新:
1.百度网盘链接
2.部分知友反应,用文章给出的代码分析文档的时候,有时会遇到如下的问题:
“ValueError: 'zg' is not in list”
这是因为“ zg”这个词性没有添加到#英文词性转中文词性字典这里面。程序发现分析文档中存在词性属于zg的词,但是我在程序里列出的字典中缺少这个词性的转换,所以就出问题了。
解决方法: 在代码的#英文词性转中文词性字典里面添加上zg对应的转换就行,具体zg是什么百度一下就可。小花当时是把能查到的都写进去了,但是难免有几个词性查不到,谅解一下哈~如果出现类似的问题(比如“ValueError: 'xxh' is not in list”),也是把相应的词(如xxh)添加进去就行。
2020.05.13更新:大家点个赞再收藏吧(点赞后观看,养成好习惯)TAT
如你所见。文章标题图是以 周杰伦的百度百科 词条为分析文档,以 周杰伦超话第一的那张图+PPT删除背景底色 为词频背景进行制作的(PPT真是个巨强的软件!我以后有时间一定会和大家分享的!)。这种词频分析、尤其是这种词云图,在这两年流行了起来。
但大家在制作的过程中可能总会这样或那样的问题:配色单调、收费、对中文的适配很差等等。而若我说,我可以免费给你一个软件,让你可以很方便地实现词频分析+词云生成(并且支持自定义);或者说,我可以免费教你自己写python来实现这些看起来很高大上的功能呢?
前几天总结2019年日记的时候,本想用一些词频统计软件/网站分析一下自己的2019年度关键词,结果发现能翻到的软件/网站要么只支持5w/10w字符以内文档的分析,要么就得乖乖掏钱才能进行无限制字数的分析……(是的我去年日记写了14w+字……)勤(jia)劳(jing)节(pin)俭(han)的我怎么可能就此认输!于是花了些时间自学python、写出了这个程序。在此分享给大家~ヾ(•ω•`)o
废话不多说,先上程序:程序理论支持无上限的字数分析(应该吧)。在运行程序后,会生成最高频的前100个字/词,并生成词云。分析文档、词云背景等都是支持用户自定义的,在文档“使用说明”中有更详细的介绍,这里就不再赘述。
放上百度云盘的链接,以飨读者。
这篇文章主要是想分享一下自己所写的代码,毕竟程序是死的,代码是活的。大家若是学会了自己写或改代码,那就相当于拥有了更多自定义的权力。(python真的比C、C#等语言要好学呜呜呜QAQ,而且网上好多好多教程的)
在开始分享之前,我可以向大家保证,在网上真的很难找到比我的功能更完善、同时代码更美观且注释详细、同时还不收费的教程/软件了(要是找到了当我没说略略略)。开讲!
以下代码都是基于 python3.7 进行开发的。
首先, 安装所需的库 。(当然,记得先安好python)
可以直接在cmd中(按下win+R,输入 cmd 后点确定)分别输入以下代码进行安装(部分可能已系统内置),也可以用其他方式进行安装。不过个人比较推荐通过cmd进行安装,毕竟cmd安装方便,不费事儿。
pip install re
pip install jieba
pip install collections
pip install numpy
pip install PIL
pip install wordcloud
pip install matplotlib.pyplot
安装完成后,就可以开心的敲代码啦~
在代码的开头,先进行一些 定义 。
在程序的开头进行定义,是为了以后修改代码更加方便。当然,在凭空开始写程序的时候,可能自己也不清楚自己之后都需要定义哪些东西,所以这一步可以在边写代码时边在程序开头进行修改。
另外,在运行程序的时候,记得 把程序运行所需文件放在程序的运行目录下 。
# 主要功能自定义设置
Analysis_text = '分析文档.txt' # 分析文档
userdict = '用户词典.txt' # 用户词典
StopWords = '停用词库.txt' # 停用词库
number = 100 # 统计个数
Output = '词频.txt' # 输出文件
background = '词频背景.jpg' # 词频背景
然后是 导入相关的库 。
这个没什么好说的,代码的注释中已经解释的很详细了。(我是按用到的库的先后顺序对安装库和导入库的顺序进行排序的哦,这样也许会更好理解一些)
# 导入扩展库
import re # 正则表达式库
import jieba # 结巴分词
import jieba.posseg # 词性获取
import collections # 词频统计库
import numpy # numpy数据处理库
from PIL import Image # 图像处理库
import wordcloud # 词云展示库
import matplotlib.pyplot as plt # 图像展示库(这里以plt代表库的全称)
在导入扩展库后,才是程序正文的开始。
工作的开头,当然是 对所需分析文档进行读取 。
读取方式有很多种,这里选择用open这一种比较简洁的方式;在读取完成后,不要忘记close哦,这是一个好————————习惯!(或者用with语句)这里读取的文件“Analysis_text”是前文定义的“Analysis_text = '分析文档.txt'”。
# 读取文件
fn = open(Analysis_text,'r',encoding = 'UTF-8') # 打开文件
string_data = fn.read() # 读出整个文件
fn.close() # 关闭文件
读取完成后,对文本进行一些 预处理 。
# 文本预处理
pattern = re.compile(u'\t|\n|\.|-|:|;|\)|\(|\?|"') # 定义正则表达式匹配模式(空格等)
string_data = re.sub(pattern, '', string_data) # 将符合模式的字符去除
添加 动态调整词典 和 用户词典 功能。这两个功能并不是必须的,大家可以根据个人需求决定是否使用。变量“userdict”是开头定义的“userdict = '用户词典.txt'”。
这两个功能的用处,是在自带词库的基础上、 根据动态调整词典/用户词典中的字/词对文档内容进行分词统计。若对程序自带词库的分词效果不尽满意, 可以在动态调整词典/用户词典中单独加入想要统计的词汇,以提高个别词汇识别成功率。格式为每行一个字/词。 比如 :想统计“小小花”这个词的出现次数,但程序可能会将其分为“小小”“ 花”这两个词语分别进行统计;或是将“小小花”与前后文字/词一同进行统计,如“小小花朵”。 这时就可以在动态调整词典/用户词典中加入“小小花”一词,以提高识别成功率。
# 动态调整词典
jieba.suggest_freq('小小花', True) #True表示该词不能被分割,False表示该词能被分割
# 添加用户词典
jieba.load_userdict(userdict)
进行分词 。
利用jieba词库进行分词。jieba词库在汉语语义分析中运用的十分广泛,上手也相对容易一点。更详细的相关介绍大家可以千度一下,我就不占地儿了。这里采用的是精确模式分词+使用HMM模型,可以将字/词划分的更加准确。
# 文本分词
seg_list_exact = jieba.cut(string_data, cut_all=False, HMM=True) # 精确模式分词+HMM
object_list = []
去除停用词 。
对于停用词库中出现的词汇,程序不会进行统计。这个功能也不是必须的,大家可以根据个人需求决定是否使用。这里给出的停用词库是前面定义的“StopWords = '停用词库.txt'”,用的是常见的“Chinese stopwords”词库。这个词库在网上不太难找,懒得找的话也可以在我上面给出的链接中进行下载。
# 去除停用词(去掉一些意义不大的词,如标点符号、嗯、啊等)
with open(StopWords, 'r', encoding='UTF-8') as meaninglessFile:
stopwords = set(meaninglessFile.read().split('\n'))
stopwords.add(' ')
for word in seg_list_exact: # 循环读出每个分词
if word not in stopwords: # 如果不在去除词库中
object_list.append(word) # 分词追加到列表
进行 词频统计 。
这里的“number”是前面定义的“number = 100”,具体数值大家也可以自己更改。词频统计也有很多种写法,但个人认为使用Couter进行统计更加简洁。
# 词频统计
word_counts = collections.Counter(object_list) # 对分词做词频统计
word_counts_top = word_counts.most_common(number) # 获取前number个最高频的词
然后是 添加“英文词性转中文词性字典” 。
我在这个程序中加入了词性分析的功能,即识别当前字/词是形容词、动词还是名词等等。但jieba自带的词性分析输出结果为英文(a/v/n等),不便于用户直接阅读;因此我就在网上搜罗了一圈,自己花了点时间整理出来了这两个对照词典。
词典分为简洁版和详细版两个版本,大家按需所取。一般来说简洁版的就够用了,所以我在我的程序中使用的也是简洁版的转换。
# 英文词性转中文词性字典:简洁版
En2Cn = {
'a' : '形容词',
'ad' : '形容词',
'ag' : '形容词',
'al' : '形容词',
'an' : '形容词',
'b' : '区别词',
'bl' : '区别词',
'c' : '连词',
'cc' : '连词',
'd' : '副词',
'e' : '叹词',
'eng' : '英文',
'f' : '方位词',
'g' : '语素',
'h' : '前缀',
'i' : '成语',
'j' : '简称略语',
'k' : '后缀',
'l' : '习用语',
'm' : '数词',
'mq' : '数量词',
'n' : '名词',
'ng' : '名词',
'nl' : '名词',
'nr' : '名词',
'nr1' : '名词',
'nr2' : '名词',
'nrf' : '名词',
'nrfg' : '名词',
'nrj' : '名词',
'ns' : '名词',
'nsf' : '名词',
'nt' : '名词',
'nz' : '名词',
'o' : '拟声词',
'p' : '介词',
'pba' : '介词',
'pbei' : '介词',
'q' : '量词',
'qt' : '量词',
'qv' : '量词',
'r' : '代词',
'rg' : '代词',
'rr' : '代词',
'rz' : '代词',
'rzs' : '代词',
'rzt' : '代词',
'rzv' : '代词',
'ry' : '代词',
'rys' : '代词',
'ryt' : '代词',
'ryv' : '代词',
's' : '处所词',
't' : '时间词',
'tg' : '时间词',
'u' : '助词',
'ude1' : '助词',
'ude2' : '助词',
'ude3' : '助词',
'udeng': '助词',
'udh' : '助词',
'uguo' : '助词',
'ule' : '助词',
'ulian': '助词',
'uls' : '助词',
'usuo' : '助词',
'uyy' : '助词',
'uzhe' : '助词',
'uzhi' : '助词',
'v' : '动词',
'vd' : '动词',
'vf' : '动词',
'vg' : '动词',
'vi' : '动词',
'vl' : '动词',
'vn' : '动词',
'vshi' : '动词',
'vx' : '动词',
'vyou' : '动词',
'w' : '标点符号',
'wb' : '标点符号',
'wd' : '标点符号',
'wf' : '标点符号',
'wj' : '标点符号',
'wh' : '标点符号',
'wkz' : '标点符号',
'wky' : '标点符号',
'wm' : '标点符号',
'wn' : '标点符号',
'wp' : '标点符号',
'ws' : '标点符号',
'wt' : '标点符号',
'ww' : '标点符号',
'wyz' : '标点符号',
'wyy' : '标点符号',
'x' : '字符串',
'xu' : '字符串',
'xx' : '字符串',
'y' : '语气词',
'z' : '状态词',
'un' : '未知词',
}
# 英文词性转中文词性字典:详细版
En2Cn_Pro = {
'a' : '形容词',
'ad' : '形容词-副形词',
'ag' : '形容词-形容词性语素',
'al' : '形容词-形容词性惯用语',
'an' : '形容词-名形词',
'b' : '区别词',
'bl' : '区别词-区别词性惯用语',
'c' : '连词',
'cc' : '连词-并列连词',
'd' : '副词',
'e' : '叹词',
'eng' : '英文',
'f' : '方位词',
'g' : '语素',
'h' : '前缀',
'i' : '成语',
'j' : '简称略语',
'k' : '后缀',
'l' : '习用语',
'm' : '数词',
'mq' : '数量词',
'n' : '名词',
'ng' : '名词-名词性语素',
'nl' : '名词-名词性惯用语',
'nr' : '名词-人名',
'nr1' : '名词-汉语姓氏',
'nr2' : '名词-汉语名字',
'nrf' : '名词-音译人名',
'nrfg' : '名词-人名',
'nrj' : '名词-日语人名',
'ns' : '名词-地名',
'nsf' : '名词-音译地名',
'nt' : '名词-机构团体名',
'nz' : '名词-其他专名',
'o' : '拟声词',
'p' : '介词',
'pba' : '介词-“把”',
'pbei' : '介词-“被”',
'q' : '量词',
'qt' : '量词-动量词',
'qv' : '量词-时量词',
'r' : '代词',
'rg' : '代词-代词性语素',
'rr' : '代词-人称代词',
'rz' : '代词-指示代词',
'rzs' : '代词-处所指示代词',
'rzt' : '代词-时间指示代词',
'rzv' : '代词-谓词性指示代词',
'ry' : '代词-疑问代词',
'rys' : '代词-处所疑问代词',
'ryt' : '代词-时间疑问代词',
'ryv' : '代词-谓词性疑问代词',
's' : '处所词',
't' : '时间词',
'tg' : '时间词-时间词性语素',
'u' : '助词',
'ude1' : '助词-“的”“底”',
'ude2' : '助词-“地”',
'ude3' : '助词-“得”',
'udeng': '助词-“等”“等等”“云云”',
'udh' : '助词-“的话”',
'uguo' : '助词-“过”',
'ule' : '助词-“了”“喽”',
'ulian': '助词-“连”',
'uls' : '助词-“来讲”“来说”“而言”“说来”',
'usuo' : '助词-“所”',
'uyy' : '助词-“一样”“一般”“似的”“般”',
'uzhe' : '助词-“着”',
'uzhi' : '助词-“之”',
'v' : '动词',
'vd' : '动词-副动词',
'vf' : '动词-趋向动词',
'vg' : '动词-动词性语素',
'vi' : '动词-不及物动词(内动词)',
'vl' : '动词-动词性惯用语',
'vn' : '动词-名动词',
'vshi' : '动词-“是”',
'vx' : '动词-形式动词',
'vyou' : '动词-“有”',
'w' : '标点符号',
'wb' : '标点符号-百分号千分号,全角:% ‰ 半角:%',
'wd' : '标点符号-逗号,全角:, 半角:,',
'wf' : '标点符号-分号,全角:; 半角: ; ',
'wj' : '标点符号-句号,全角:。',
'wh' : '标点符号-单位符号,全角:¥ $ £ ° ℃ 半角 $',
'wkz' : '标点符号-左括号,全角:( 〔 [ { 《 【 〖 〈 半角:( [ { <',
'wky' : '标点符号-右括号,全角:) 〕 ] } 》 】 〗 〉 半角: ) ] { >',
'wm' : '标点符号-冒号,全角:: 半角: :',
'wn' : '标点符号-顿号,全角:、',
'wp' : '标点符号-破折号,全角:—— -- ——- 半角:—',
'ws' : '标点符号-省略号,全角:…… …',
'wt' : '标点符号-叹号,全角:! 半角:!',
'ww' : '标点符号-问号,全角:? 半角:?',
'wyz' : '标点符号-左引号,全角:“ ‘ 『',
'wyy' : '标点符号-右引号,全角:” ’ 』',
'x' : '字符串',
'xu' : '字符串-网址URL',
'xx' : '字符串-非语素字',
'y' : '语气词',
'z' : '状态词',
'un' : '未知词',
}
接下来的这一步最为关键,是 把词频分析结果输出至工作台,并导出“词频.txt”文件 。
为使分析结果便于理解,首先输出/写入“\n词语\t词频\t词性”,并用破折号作为分割线进行划分。利用count计数,进行双重for循环:第一重for循环是获取前number个词语与其词频,第二重for循环是获取前number个词语的词性;若count≠number,则依次输出/写入词语、词频、词性,并将count+1;直到count=number,终止循环。
另外,输出文件“Output”是前文定义的“Output = '词频.txt'”,程序会在运行目录下创建文本文件并进行写入。
# 输出至工作台,并导出“词频.txt”文件
print ('\n词语\t词频\t词性')
print ('——————————')
fileOut = open(Output,'w',encoding='UTF-8') # 创建文本文件;若已存在,则进行覆盖
fileOut.write('词语\t词频\t词性\n')
fileOut.write('——————————\n')
count = 0
for TopWord,Frequency in word_counts_top: # 获取词语和词频
for POS in jieba.posseg.cut(TopWord): # 获取词性
if count == number:
break
print(TopWord + '\t',str(Frequency) + '\t',list(En2Cn.values())[list(En2Cn.keys()).index(POS.flag)]) # 逐行输出数据
fileOut.write(TopWord + '\t' + str(Frequency) + '\t' + list(En2Cn.values())[list(En2Cn.keys()).index(POS.flag)] + '\n') # 逐行写入str格式数据
count += 1
fileOut.close() # 关闭文件
其实若能实现上面所给出的所有代码,那就已经是一个较为完善的词频分析软件了。但是我觉得还不够,还要再做点什么。
于是加入了 制作词云 这一功能。
首先,输出“开始制作词云……”,提示用户系统当前运行状态。定义词频的背景,这里的“background”是前面定义的“background = '词频背景.jpg'”。调用wordcloud函数,对部分参数进行调整。最后利用plt函数进行词云的展示。
# 词频展示
print ('\n开始制作词云……') # 提示当前状态
mask = numpy.array(Image.open(background)) # 定义词频背景
wc = wordcloud.WordCloud(
font_path = 'C:/Windows/Fonts/simfang.ttf', # 设置字体(这里选择“仿宋”)
background_color='white', # 背景颜色
mask = mask, # 文字颜色+形状(有mask参数再设定宽高是无效的)
max_words = number, # 显示词数
max_font_size = 150 # 最大字号
wc.generate_from_frequencies(word_counts) # 从字典生成词云
wc.recolor(color_func=wordcloud.ImageColorGenerator(mask)) # 将词云颜色设置为背景图方案
plt.figure('词云') # 弹框名称与大小
plt.subplots_adjust(top=0.99,bottom=0.01,right=0.99,left=0.01,hspace=0,wspace=0) # 调整边距
plt.imshow(wc, cmap=plt.cm.gray, interpolation='bilinear') # 处理词云