一句话概括
本文通过实战围绕介绍使用jieba库进行中文分词,并使用collections模块进行分词的次数统计,介绍了wordcloud词云库的使用方式;
前言
爬虫获取数据后,就需要数据分析了,那数据怎么处理?用到什么数据?一起来看看吧~
最近又重新看回了全职高手这部小说及动漫,犹记得当时被刘老师安利,说这小说很好看,后来腾讯买了版权,出了动画,虽然有删减,但依然有空看几遍;
但有时候也在想,为什么自己那么沉迷这小说,除了里面写的游戏基本跟读书时玩的DNF一样外,应该没其他特别的;
既然如何?有没有办法把小说里的内容进行提取关键字,然后再弄个词云?
这不就找到了jieba&wordcloud库吗?
1 数据准备:
直接网上找全职高手txt下载,一大堆,解压后获取到txt文件;
全职高手txt小说下载地址
1.2 读取全职高手文本
with open("quanzhigaoshou.txt") as f:
qzgs_text = f.read()
print(len(qzgs_text))
复制代码
结果直接执行,报错了
这是不是就准备好了呢?
答案是NO,因为文本内容是这样的:
从上图可以看出,文本里面会有各种符号跟广告,目前这步,要做的就是把各种标点符号干掉先;
with open("quanzhigaoshou.txt",encoding='utf-8') as f:
qzgs_text = f.read()
pattern = re.compile('[\s+\.\!\/_,$%^*(+\"\']+|[+——!,。?“”、~@#¥%……&*()(\d+)]+')
new_qzgs_text = pattern.sub("",qzgs_text)
print(new_qzgs_text)
复制代码
到此,字符串搞定啦~
1.3 jieba中文分词库
因为我们的样例都是中文,因此就选用据说是最好的python中文分词库:jieba
- GitHub仓库:https://github.com/fxsjy/jieba
- 官方文档:https://pypi.org/project/jieba/
- 一个比较详细的教程:https://blog.csdn.net/fontthrone/article/details/72782499
二话不说,直接安装一波先:
pip install jieba
复制代码
安装过程没什么好说的;目前暂未遇到问题
官方提供的特点:
- 支持三种分词模式:
- 精确模式,试图将句子最精确地切开,适合文本分析;
- 全模式,把句子中所有的可以成词的词语都扫描出来,速度非常快,但是不能解决歧义;
- 搜索引擎模式,在精确模式的基础上,对长词再次切分,提高召回率,适合用于搜索引擎分词。
这里贴一个官方的例子:
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_for_search("小明硕士毕业于中国科学院计算所,后在日本京都大学深造") # 搜索引擎模式
print(", ".join(seg_list))
复制代码
输出的结果:
【全模式】: 我/ 来到/ 北京/ 清华/ 清华大学/ 华大/ 大学
【精确模式/默认模式】: 我/ 来到/ 北京/ 清华大学
【搜索引擎模式】:小明, 硕士, 毕业, 于, 中国, 科学, 学院, 科学院, 中国科学院, 计算, 计算所, ,, 后, 在, 日本, 京都, 大学, 日本京都大学, 深造
复制代码
从官网的例子可以看到,就一个cut参数,里面放需要分词的字符串跟cu_all参数,是否打开全模式;
比如大傻叉,默认模式/精准模式,就是会辨识到大,傻,叉;
而全模式,则会变成大傻,傻叉,大傻叉这样
当然,这个结果是想象出来的,实际并非这样,具体原因未明,可能是没有入词库导致?
ok,了解到jieba如何使用,就来试试把:
qzgs_word = [word for word in jieba.cut(new_qzgs_text,cut_all=False) if len(word)>2]
#这看上去很长,但很好理解,获取分词,然后长度大于2个才算一个词;在遍历下,就能
复制代码
写个for把分词遍历下:
没毛病,继续;
接下来就是统计同词词频,一般来说,会统计词出现的次数,也叫频次;
这块,有collections模块的Counter来实现;
Counter类的目的是用来跟踪值出现的次数。
它是一个无序的容器类型,以字典的键值对形式存储,其中元素作为key,其计数作为value。
这里介绍下Counter类的一些方法:
1)创建:
c = Counter() # 创建一个空的Counter类
c = Counter('gallahad') # 从一个可iterable对象(list、tuple、dict、字符串等)创建
c = Counter({'a': 4, 'b': 2}) # 从一个字典对象创建
c = Counter(a=4, b=2) # 从一组键值对创建
复制代码
2)计数值的访问与缺失的键 当访问的健不存在时,返回0,否则就返回它的计数
c= Counter("abcdefgab")
print(c["a"])
print(c["c"])
print(c["h"])
输出的结果:
2
1
0
复制代码
3)计算器的更新(update和subtract) 可以使用一个iterable对象或者另一个Counter对象来更新键值。
计数器的更新包括增加和减少两种。其中,增加使用update()**方法:
c= Counter("which")
c.update("witch")
print(c["h"])
d = Counter("watch")
c.update(d)
print(c["h"])
输出的结果:
3
4
复制代码
减少则使用**subtract()**方法:
c= Counter("which")
c.subtract("witch")
print(c["h"])
d = Counter("watch")
c.subtract(d)
print(c["a"])
输出的结果:
1
-1
复制代码
4)键的删除: 当计数值为0时,并不意味着元素被删除,删除元素应当使用del。
c= Counter("abcdcba")
print(c)
c["b"]=0
print(c)
del c["a"]
print(c)
输出的结果:
Counter({'a': 2, 'b': 2, 'c': 2, 'd': 1})
Counter({'a': 2, 'c': 2, 'd': 1, 'b': 0})
Counter({'c': 2, 'd': 1, 'b': 0})
复制代码
5)elements(): 返回一个迭代器。元素被重复了多少次,在该迭代器中就包含多少个该元素。元素排列无确定顺序,个数小于1的元素不被包含。
c = Counter(a=4, b=2, c=0, d=-2)
print(list(c.elements()))
输出的结果:
['a', 'a', 'a', 'a', 'b', 'b']
复制代码
6)most_common(): 返回一个TopN列表。如果n没有被指定,则返回所有元素。当多个元素计数值相同时,排列是无确定顺序的。
c= Counter("abracadabra")
print(c.most_common())
print(c.most_common(3))
输出的结果:
[('a', 5), ('b', 2), ('r', 2), ('c', 1), ('d', 1)]
[('a', 5), ('b', 2), ('r', 2)]
复制代码
还有copy跟集合算术操作,这里就不说明了,很简单;
扯远了,我们的目的是跟踪值出现的次数,根据上面的介绍,发现most_common()这个方法能符号要求;
根据上面most_common的介绍,会返回2个参数,一个是词,一个是次数,因此只需要把这两个玩意输出即可: c = Counter(qzgs_words) for word in c.most_common(50): word,freq = word print(word,freq) #50代表取的TOP50 输出的结果:
嗯,想要的数据拿到了,但是这内容,是不是很奇怪?wwwmianhuatangla这玩意都出现了,还有小说网,看起来,是不是这种,是没有任何意义的,那我们还需要对数据进行处理,也叫数据清洗,就是定义一个过滤列表,把想过滤的词都扔进去,分词遍历后,把符合的元素进行移除即可:
invalid_words = ["所有人","看起来","小说网","wwwmianhuatangla","是不是","为什么","没什么","其他人","未完待续",
"事实上","一时间","是因为","一瞬间","只不过","差不多","不至于","这时候","越来越","没想到","可不是","不得不","接下来",
"魄之力","俱乐部"]
for word in qzgs_words:
if word in invalid_words:
qzgs_words.remove(word)
复制代码
输出是这样的:
关于频次的讲解,大致就到这里;
接下来是介绍频率的统计,就是百分比,这个是通过jieba库里的analyse模块解决,支持直接读取文件过滤,即把不想要的分词丢在一个文件里,然后会自动过滤,函数是:extract_tags
jieba.analyse.extract_tags(sentence, topK=20, withWeight=False, allowPOS=())
-
sentence 为待提取的文本
-
topK 为返回几个 TF/IDF 权重最大的关键词,默认值为 20,简单理解就是提取多少个
-
withWeight 为是否一并返回关键词权重值,默认值为 False
-
allowPOS 仅包括指定词性的词,默认值为空,即不筛选
invalid_words_file = "invalidwords.txt"
#设置停用词 jieba.analyse.set_stop_words(invalid_words_file)
#获取关键词频率 tags = jieba.analyse.extract_tags(qzgs_text,topK=100,withWeight=True) for tag in tags: print(tag) 输出的结果:
到这里,分词跟词频都了解到了,接下来,看词云吧~
2 词云
网上找了下词云的库,基本都用wordcloud,那我们也跟着用这个吧;
- GitHub仓库:https://github.com/amueller/word_cloud
- 官方文档:https://amueller.github.io/word_cloud/
- 一个比较详细的教程:https://blog.csdn.net/fontthrone/article/details/72775865
pip安装一波:
pip install wordcloud
复制代码
但是JB在安装的时候报错了;
然后改用另外一种解决方案了,打开下面的链接:
http://www.lfd.uci.edu/~gohlke/pythonlibs/#wordcloud 直接搜索wordcloud,JB用的是Windows系统,所以选择下载这个: wordcloud-1.4.1-cp36-cp36m-win_amd64.whl
下载后,直接运行,问题解决;(折腾一个小时了,坑~)
pip install wordcloud-1.4.1-cp36-cp36m-win_amd64.whl
复制代码
这个库的使用,关键在于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=.5, regexp=None, collocations=True,
colormap=None, normalize_plurals=True):
复制代码
参数讲解:
- font_path:字体路径,就是绘制词云用的字体,比如monaco.ttf
- width:输出的画布宽度,默认400像素
- height:输出的画布宽度,默认200像素
- margin:画布偏移,默认2像素
- prefer_horizontal : 词语水平方向排版出现的频率,默认0.9,垂直方向出现概率0.1
- mask:如果参数为空,则使用二维遮罩绘制词云。如果 mask 非空,设置的宽高值将 被忽略,遮罩形状被 mask,除全白(#FFFFFF)的部分将不会绘制,其余部分会用于绘制词云。 如:bg_pic = imread('读取一张图片.png'),背景图片的画布一定要设置为白色(#FFFFFF), 然后显示的形状为不是白色的其他颜色。可以用ps工具将自己要显示的形状复制到一个纯白色 的画布上再保存,就ok了。
- scale:按照比例进行放大画布,如设置为1.5,则长和宽都是原来画布的1.5倍
- color_func:生成新颜色的函数,如果为空,则使用 self.color_func
- max_words:显示的词的最大个数
- min_font_size:显示的最小字体大小
- stopwords:需要屏蔽的词(字符串集合),为空使用内置STOPWORDS
- random_state:如果给出了一个随机对象,用作生成一个随机数
- background_color:背景颜色,默认为黑色
- max_font_size:显示的最大的字体大小
- font_step:字体步长,如果步长大于1,会加快运算但是可能导致结果出现较大的误差
- mode:当参数为"RGBA",并且background_color不为空时,背景为透明。默认RGB
- relative_scaling:词频和字体大小的关联性,默认5
- regexp:使用正则表达式分隔输入的文本
- collocations:是否包括两个词的搭配
- colormap:给每个单词随机分配颜色,若指定color_func,则忽略该方法
- normalize_plurals:是否删除尾随的词语
常用的方法:
- fit_words(frequencies) //根据词频生成词云
- generate(text) //根据文本生成词云
- generate_from_frequencies(frequencies[, ...]) #根据词频生成词云
- generate_from_text(text) #根据文本生成词云
- process_text(text) #将长文本分词并去除屏蔽词 (此处指英语,中文分词还是需要自己用别的库先行实现,使用上面的 fit_words(frequencies) )
- recolor([random_state, color_func, colormap]) #对现有输出重新着色。重新上色会比重新生成整个词云快很多。
- to_array() #转化为 numpy array
- to_file(filename) #输出到文件
看完后贼难受的,而且真没多少记得,懵逼吧,先从简单的例子入手吧:
from wordcloud import WordCloud
data = "所有人,看起来,说网,不是,什么"
wc= WordCloud(background_color="white")
wc = wc.generate(data)
wc.to_file("111.jpg")
复制代码
代码能执行,执行的效果是这样的:
看上去,好像是没有字体导致的,加个字体试试,因为JB是用WINDOWS,直接那系统的字体了;
data = "所有人,看起来,说网,不是,什么"
wc= WordCloud(background_color="white",font_path="C:/Windows/Fonts/STFANGSO.ttf")
wc = wc.generate(data)
wc.to_file("111.jpg")
复制代码
ok,现在可以了~
有个效率的问题,现在是每次保存到111.jpg,然后手动打开,这个过程虽然不麻烦,但是次数一到就觉得厌倦了,那能否自动弹出图片?答案是有的,需要matplotlib.pyplot这个库:
from wordcloud import WordCloud,
import matplotlib.pyplot as plt
data = "所有人,看起来,说网,不是,什么"
wc= WordCloud(background_color="white",font_path="C:/Windows/Fonts/STFANGSO.ttf")
wc = wc.generate(data)
#显示词云图片
plt.imshow(wc)
plt.show()
#保存图片
wc.to_file("111.jpg")
复制代码
修改成这样后,执行后就自动弹出图片了,图片长这样的:
居然带有坐标,这多丑啊,怎么去除?
#显示词云图片
plt.imshow(wc)
plt.axis("off")
#axis函数接收一个list,设定横纵坐标尺度,list各个参数分别代表[X初始刻度,X终止刻度,Y起始刻度,Y终止,off就是不显示坐标尺寸
plt.show()
复制代码
只需要加上plt.axis("off")即可:
但是网上看到别人的是这样的,为啥我们的差距那么大?
那我们也来找一张图片,如下(正经图正经图):
然后改一波代码把:
#data自己定义哈,为了显示效果,用尽可能多的数据了
#字体路径
path = "C:/Windows/Fonts/STFANGSO.ttf"
#读入背景图片,就是上面那张图片
bg_pic = imread("11.jpg")
wc= WordCloud(background_color="white",font_path=path,mask=bg_pic)
wc = wc.generate(data)
#显示词云图片
plt.imshow(wc)
plt.axis("off")
#axis函数接收一个list,设定横纵坐标尺度,list各个参数分别代表[X初始刻度,X终止刻度,Y起始刻度,Y终止,off就是不显示坐标尺寸
plt.show()
#保存图片
wc.to_file("111.jpg")
复制代码
效果如下:
整体效果出来了,这字体颜色貌似是随机的,要不让字体跟随着图片颜色变化?
#读入背景图片
bg_pic = imread("11.jpg")
#从背景图片生成颜色值
image_colors = ImageColorGenerator(bg_pic)
wc= WordCloud(background_color="black",font_path=path,mask=bg_pic,color_func=image_colors)
复制代码
结果是这样的:
尼玛,忘记图片大部分是白色的。。那把背景改黑色吧:
剩下的,就是怎选图跟选用字体以后一些参数细节,这块不打算详细说了,也不想纠结了,大致知道用法即可;
把整体代码封装下,最后代码如下:
import re
import jieba.analyse
from collections import Counter
from wordcloud import WordCloud, ImageColorGenerator,STOPWORDS
import matplotlib.pyplot as plt
from scipy.misc import imread
#这个文件是统计频率时,把需要过滤的词放到这个文件里面
#invalid_words_file = "invalidwords.txt"
def get_Words():
#读取TXT文件获取文本里的内容
with open("quanzhigaoshou.txt", encoding='utf-8') as f:
qzgs_text = f.read()
#制定正则规则,把各种符号去掉,最后生成没有各种符号的字符串
pattern = re.compile('[\s+\.\!\/_,$%^*(+\"\']+|[+——!,。?“”、~@#¥%……&*()(\d+)]+')
new_qzgs_text = pattern.sub("", qzgs_text)
#获取分词
qzgs_words = [word for word in jieba.cut(new_qzgs_text, cut_all=False) if len(word) > 2]
# #设置停用词
# jieba.analyse.set_stop_words(invalid_words_file)
#
# #获取关键词频率
# tags = jieba.analyse.extract_tags(qzgs_text,topK=100,withWeight=True)
# for tag in tags:
# print(tag)
#制定需要过滤的词
invalid_words_zh = ["所有人", "看起来", "小说网", "是不是", "为什么", "没什么", "其他人", "未完待续",
"事实上", "一时间", "是因为", "一瞬间", "只不过", "差不多", "不至于", "这时候", "越来越", "没想到", "可不是", "不得不", "接下来",
"魄之力", "俱乐部", "挑战赛", "全明星", "擂台赛", "季后赛","boss", "wwwmianhuatangla"]
#进行过滤操作
for word in qzgs_words:
if word in invalid_words_zh:
qzgs_words.remove(word)
# 获取分词频数
# c = Counter(qzgs_words)
# for word in c.most_common(50):
# word,freq = word
# print(word,freq)
#空格分隔下
data = r" ".join(qzgs_words)
return data
def generate_wc(data):
# 字体路径
path = "C:/Windows/Fonts/STFANGSO.ttf"
# 读入背景图片
bg_pic = imread("bjt.jpg")
# 从背景图片生成颜色值
image_colors = ImageColorGenerator(bg_pic)
# 生成词云,后面的generate是根据文本生成词云
wc = WordCloud(background_color="black", font_path=path, mask=bg_pic, color_func=image_colors)
wc = wc.generate(data)
# 显示词云图片
plt.imshow(wc)
plt.axis("off")
# axis函数接收一个list,设定横纵坐标尺度,list各个参数分别代表[X初始刻度,X终止刻度,Y起始刻度,Y终止,off就是不显示坐标尺寸
plt.show()
# 保存图片
wc.to_file("result.jpg")
if __name__ =="__main__":
data=get_Words()
generate_wc(data)
复制代码
底图一换,就成这样:
挑个好字体跟好颜色,估计更好看,这字体太模糊了=。=
小结
虽然做的比较丑,但算是达到目的了,折腾了不少时间,主要还是在环境搭建那块,当然看资料也算,虽然网上很多教程,但大部分都是直接扔一堆代码过来的,连注释都比较少,对于新同学不是很友好;
本文通过实战围绕介绍使用jieba库进行中文分词,并使用collections模块进行分词的次数统计,介绍了wordcloud词云库的使用方式;
杂七杂八
中文分词,用jieba,那英文分词呢?
有NLTK,基本逻辑跟中文分词类似:
- 读取文件->过滤特殊符号->分词->词形还原->统计词频->词云
词形还原什么鬼,简单看了下,没太懂,大致有个库能通过是过去式还是进行时来还原部分词,大致是这样;
好了,本章介绍了,下章会结合爬取拉钩等招聘网站,来介绍numpy,pandas和matplotlib进行数据分析;
谢谢大家!~