一、缘起
“豆豆,你看过刘慈欣写的《诗云》没有?” 马老师合上书,这时正是下午五点钟的秋天,金色的阳光洒满了房间。
“没有,我只看过《三体》” 豆豆说,“还有《球状闪电》。”
“嗯,你看的这两部都是代表作,不过《诗云》也不错的,虽然是短篇,但是大刘用他无比的想象力构建了一个亦真亦幻的诗之宇宙。有空你看看吧 ”
“好的,马老师”,豆豆说,“可是这和咱们今天上的课有关系吗?”
“有,《诗云》是神级文明用天文数量的诗构建的,我们可做不了,我们今天要做的是【词云】。”
“词云?”
“是的,就是这样的东西。” 马老师打开一张图片。
“原来是这个啊,这个我也见过,好像显示最近一段网络热词之类的就用这个显示。”
“是的,词云就是用词的显示大小来显示不同词语的热度的”,马老师说,“词云其实是数据可视化的一种形式,给出一段文本的关键词,根据关键词的出现频率而生成的一幅图像,人们只要扫一眼就能够明白文章主旨。”
“明白了马老师,咱们开始吧。”
二、基本的词云制作
要生成词云,最常用的库是wordcloud,翻译过来直接就是“词云”的意思。使用以下命令安装:
pip install wordcloud
使用VSCode新建一个Python文件,输入以下内容:
# 导入模块fromwordcloudimportWordCloud# 文本数据text="The sheep year has coming, as a child, I love the first day of the year so much, because I can get a lot of money. When I see the elder, I say some good words to them, then they will give the lucky to me money in return. I meet a lot of elder in a day, so I get much money, it is a satisfied day for me."# 词云对象wc=WordCloud()# 生成词云wc.generate(text)# 保存词云文件wc.to_file("img.jpg")
这里我们先实例化了一个WordCloud对象,然后调用其generate方法,把文本传过去就可以生成了。生成之后把它保存到文件就可以查看了。
运行程序,当前目录下会生成一个img.jpg,如下图所示:
可以看出,这张图很小,效果似乎不怎么理想,但它的确是一张货真价实的“词云图”。只是我们用于生成词云的文本太短了,而且没有对WordCloud对象的参数做更多配置,所以效果一般。WordCloud对象的参数很多,常用的有:
- font_path:设置字体,尤其是中文词云一定要支持中文的字体
- min_font_size:词云中最小的字体字号,默认4号
- max_font_size:词云中最大的字体字号,默认根据高度自动调整
- max_words:词云显示的最大词数,默认200
- stopwords:设置停用词,即不在词云中显示的词,比如我们常用的“的”、“地”、“是”这些,一般在词云中没什么用,但又出现多,所以把它屏蔽掉
- background_color:图片背景色,默认黑色
运用上面的知识,我们可以对一篇长的文本生成词云,比如我们以前下载的《西游记》文本。不过需要注意的是,wordcloud默认是为了英文文本做词云的,因为英文文章一般都是由空格分隔的单词组成,词语容易识别,而中文就不是这么简单了。同一句话要拆成词语可能有许多种不同的方式。因此,我们要制作中文词云,还需要先对中文文本进行分词。这里要用到jieba库。它的作用就是利用内置的中文词库,确定中文字符关联概率,形成分词的结果(你也可以添加自定义词语到词库中)。
可以使用以下命令安装jieba库:
pipinstalljieba
为什么一个用于分词的库要叫“结巴”呢?这是因为jieba库支持三种分词模式:
输入下面的示例代码:
importjiebatxt_1="python是一门很棒的语言,你知不知道?"res=jieba.lcut(txt_1)print("---精准模式---")print(res)res_1=jieba._lcut_for_search(txt_1)print("---搜索引擎模式---")print(res_1)
运行效果如下:
---精准模式---['python','是','一门','很棒','的','语言',',','你','知不知道','?']---搜索引擎模式---['python','是','一门','很棒','的','语言',',','你','不知','知道','知不知道','?']
第二种搜索引擎模式返回的结果是有冗余的,你会发现它很像一个“结巴”的说话方式。如果你使用的是“全模式”会发现“结巴”的程度更厉害——据说这就是库名的由来,是不是很有趣?不过,一般情况下我们只需要掌握第一种精确分词就可以了,不要冗余。
总的来说,要生成中文词云,我们需要以下三步: 1. 读取文件进行分词 2. 配置WordCloud对象参数,加载词云文本 3. 生成词云文件
有了这些知识,我们可以写出以下的代码:
# 导入模块fromwordcloudimportWordCloudimportjiebawithopen("xiyouji.txt","r",encoding="utf8")asf:text=f.read()words=jieba.lcut(text)text=" ".join(words)# 准备禁用词,需要为set类型stopwords=set(["的","你","我","道","又","他"])# 设置参数,创建WordCloud对象wc=WordCloud(font_path="msyh.ttc",# 设置字体,不设置会出现乱码width=1000,# 设置宽度height=750,# 设置高background_color="white",# 设置背景颜色为白色stopwords=stopwords,# 设置禁用词,在生成的词云中不会出现set集合中的词max_font_size=300,# 设置最大的字体大小,所有词都不会超过100pxmin_font_size=10,# 设置最小的字体大小,所有词都不会超过10pxmax_words=200,# 设置最大的单词个数scale=2,# 扩大两倍)# 根据文本数据生成词云wc.generate(text)# 保存词云文件wc.to_file("img.jpg")
运行这个程序(注意需要把xiyouji.txt这个文件放到程序所在目录下),可以得到以下的词云图:
利用WordCloud的mask参数,我们还可以传过去图片,生成带有一定形状的词云图。不过它还需要自己调用PIL库、numpy库,有点麻烦,我们来换个更简单的方法。
三、更简单的词云图
使用下面的指令安装stylecloud库,它实际上是wordcloud库的封装,只是提供了更简单的调用方法:
pipinstallstylecloud
然后编写以下代码:
importstylecloudstylecloud.gen_stylecloud(file_path="xiyouji.txt",font_path="msyh.ttc",icon_name="fas fa-apple-alt")
运行,出错了,提示信息如下:
AttributeError: 'ImageDraw' object has no attribute 'textsize'
经排查发现原因是系统中安装的图像处理库Pillow版本过高,要降低到9.5.0,解决方法是在控制台重新安装Pillow库:
pip install Pillow==9.5.0
完成之后再运行,你会发现当前目录下生成了一个stylecloud.png,如图所示:
看来,我们不仅通过文件内容生成了词云图,还是带图像蒙板的,它的外观是一个苹果的形状。这是通过icon_name来控制的。你可能会问,我可以生成哪些形状的词云呢?可以访问下面的地址:
https://fontawesome.com/search?o=r&m=free
这里显示的是免费的图标库:
你可以任意选择一个形状生成词云。例如我们要生成心形的词云图,很简单,点击心形图标,查看它的属性:
注意红色椭圆中引用名称,fa-heart就是这个图标的名称。你需要将上面的代码略作修改:
importstylecloudstylecloud.gen_stylecloud(file_path="xiyouji.txt",font_path="msyh.ttc",icon_name="fas fa-heart")
运行即可得到一个心形的词云图:
是不是很简单。当然你也可以传递更多的参数给gen_stylecloud方法:
importstylecloudstop_words=set(["的","你","我","道","又","他"])stylecloud.gen_stylecloud(file_path="xiyouji.txt",icon_name="fas fa-heart",colors="white",background_color="black",output_name="xiyouji.png",collocations=False,font_path="msyh.ttc",custom_stopwords=stop_words,)
这里我们控制了云图能使用的色彩、背景色、输出的文件名和自定义的屏蔽词列表,运行会在当前目录生成一个xiyouji.png文件,内容如下:
到这里,我想你已经基本掌握了词云图绘制的方法。那我们就结合PyQt库来制作一个通用的词云图程序吧。
四、词云生成器
新建一个Python文件,输入以下内容:
importsysimportstylecloudfromPyQt5.QtGuiimportQPixmapfromPyQt5.QtWidgetsimport(QWidget,QApplication,QVBoxLayout,QLabel,QPushButton,QFileDialog,)classImageLabel(QWidget):def__init__(self,parent=None):super().__init__(parent)self.resize(600,400)self.setWindowTitle("词云图生成器V1.0")# 标签组件self.label=QLabel(self)self.label.setScaledContents(True)# 自适应QLabel大小# 按钮组件self.pushButton=QPushButton(self)self.pushButton.setText("选择文件")self.pushButton.clicked.connect(self.showImage)# 布局layout=QVBoxLayout()layout.addWidget(self.label)layout.addWidget(self.pushButton)self.setLayout(layout)defshowImage(self):fileName,_=QFileDialog.getOpenFileName(self,"请选择图像:",".","*.txt")iffileName!="":# 生成词云图stylecloud.gen_stylecloud(file_path=fileName,icon_name="fas fa-heart",output_name="wordcloud.png",font_path="msyh.ttc",)pix=QPixmap("wordcloud.png")self.label.setPixmap(pix)if__name__=="__main__":app=QApplication(sys.argv)mainWidget=ImageLabel()mainWidget.show()sys.exit(app.exec_())
你可能会感觉奇怪,这次马老师怎么没让用QtDesigner呢?实际上,对于一些界面元素非常简单的程序,不需要使用QtDesigner也可以做出界面来。毕竟使用QtDesigner还要绘制、生成,再编写一个生成类的子类,然后写代码驱动显示界面对不对?你完全可以拿这个程序作为模板稍微改造一下就能直接运行了。前提是你要熟悉PyQt提供的各种组件和它们的属性、方法。
运行上面的程序,会显示如下窗口:
这个窗口上包含一个标签(QLabel)和一个按钮(QPushButton),刚打开时没有生成词云图,所以界面是空的。点击选择文件按钮,选择一个文本文件(如xiyouji.txt),程序会用我们前面讲的方法,把文件内容生成一个图片文件,再把这个文件显示在Label中:
这样,你可以选择任意文件生成词云图片了。
当然,你可以在此基础上对程序进行改进,比如选择词云生成的形状、设置颜色、设置自定义屏蔽词等。不过这些功能就需要你自己添加相应的组件和代码来完成了(我想这个时候你会怀念QtDesigner的,对吗?你当然可以这么做)
五、总结
本节我们使用wordcloud和stylecloud两个库学习了词云图的生成方式,中间也顺便讲解了jieba库。善用这几个库,你就掌握了一个强大的分析工具,可以对任意文本进行关键词分析,快速掌握文件内容相关的主题。
想一想,怎样把词云应用在语文和英文的阅读理解场景中?