文章目录
- 词云制作
- 英文文本
- 中文文本
- jieba库
- 概述
- 安装
- 使用
- 词云制作
- wordcloud库
- 概述
- 安装
- 使用
- 示例
- 英文文本:以 hamlet 为例
- 中文文本:以《三国演义》为例
文中所涉及的文本及图片资源可通过下列链接获取:
链接:
https://pan.baidu.com/s/1Kf_bC5mRq3qBs7Oi3QNdQQ
提取码:rf5h
词云制作
相信大家近些年一定解除了很多形形色色的词云,那么那些亮眼的词云是如何制作的呢?我们是不是也可以用 Python 制作一个呢?
俗话说,知其所往方可往(我瞎编的ヽ(・ω・´メ))。我们首先要明白其原理,知晓其流程,才能达到我们的目的。
显然,词云是以文本里的某一词汇的出现频率为依据,将词汇用不同大小的字体展现出来的一个文本处理过程,最后以一定的形态输出,我们称其为图像处理过程。那么,我们就知道了其分为两步:
- 文本分割,按照词汇出现频率高低进行统计排序
- 图像显示,将词汇以不同的形态输出
按照语言类型的不同,我们将其分类为拼音类文本(以英文文本为代表)和象形类文本(以中文文本为代表)。两者的文本分割处理略有不同,在此分类讨论。
英文文本
对于英文文本来说,其文本的分割大致可分为以下几个步骤:
- 首先,我们要统一英文的大小写。虽然我们知道某一单词无论其大写还是小写都表示相同语义,但是由于Python对大小写敏感,所以我们首先要统一单词的大小写。
- 然后,我们要去掉特殊的符号。这里所说的符号在英文中指那些特殊字符和标点符号。
- 最后,对每个单词进行词频统计。我们常用字典类型进行统计,键可以表示为单词,而值表示为频数。
中文文本
由于中文文本中的单词不是通过空格或者标点符号进行分割,因此中文及其类似语言存在一个重要的分词问题,即如何正确地划分一段文本所出现的词汇。
例如最出名的一段话下雨天留客天留我不留,你会如何划分呢???
jieba库
概述
- jieba 是 Python 中一个常用的第三方中文分词函数库,能够将一段中文文本分割成中文词语的序列。
- jieba 的分词原理是利用一个中文词库,将待分词的内容与分词词库进行对比,通过图结构和动态规划方法找到最大概率的词组。除此之外,jieba 还提供增加自定义中文单词的功能。
- jieba 支持三种分词模式:精确模式—将句子最精确地切开,适合文本分析;全模式—把句子中所有可以成词的词语都扫描出来,速度快但不能解决歧义;搜索引擎模式—在精确模式基础上,对长词再次切分,提高召回率,适合用于搜索引擎分词。
安装
在系统命令行输入pip install jieba
即可
使用
jieba 库包含的主要函数如下:
-
jieba.lcut(s)
:精确模式,返回一个列表类型 -
jieba.lcut(s,cut_all=True)
:全模式,返回一个列表类型 -
jieba.lcut_for_search(s)
:搜索引擎模式,返回一个列表类型 jieba.add_word(w)
:向分词词典中添加新词 w
既然中文分词存在三种方法,那么我们该用哪种方法呢?
(我有选择困难症唉,怎么po[・_・?])
答案是——看需求:- 明确模式:希望对文本准确分词,不产生冗余
- 全模式:希望对文本分词更准确,不漏掉任何可能的分词结果
- 搜索引擎模式:没想好怎么用,想看看文本大致构造
词云制作
数据展示方式多样,传统的统计图表虽然科学但略显古板。尤其对于文本来说,直观简单又充满艺术感的设计效果给人带来的不仅是文本的分析结果,更是美的享受。
词云以词语为基本单元,根据其在文本中出现的频率设计不同大小以形成视觉上的不同效果,形成“关键词云层”,从而使读者对文本主旨一目了然。
wordcloud库
概述
wordcloud 库是专门用于根据文本生成词云的 Python 第三方库,常用且有趣。
安装
在系统命令行中输入pip install wordcloud
即可
使用
- 在生成词云时,wordcloud 默认会以空格或标点为分隔符对目标文本进行分词处理。
- 对于中文文本,分词处理需要由用户来完成:一般是先将文本分词处理,然后以空格连接,再调用 wordcloud 库函数。此外,还需指定中文字体,将该字体文件与代码存放在同一目录下或在字体文件名前增加完整路径。
wordcloud 库的核心是 WordCloud 类,所有的功能都封装在其中。
使用时需要实例化一个 WordCloud 类的对象,并调用其 generate(text) 方法将 text 文本转化为词云。WordCloud 类在创建时有一系列可选参数,用于配置词云图。其常用参数如下所示:
WordCloud 对象创建常用参数
-
font_path
:指定字体文件及其路径,默认为系统字体库 C:\Windows\Fonts -
width
:图片宽度,默认400像素 -
height
:图片高度,默认200像素 -
mask
:词云形状,默认为方形图 -
min_font_size
:词云中最小字体号,默认4号 -
font_step
:字号步进间隔,默认为5 -
max_font_size
:词云中最大字体号,默认自动调节 -
max_words
:词云图中最大词数,默认200 -
stopwords
:被排除词列表,词云不予显示 -
background_color
:图片背景颜色,默认黑色
WordCloud 类常用方法
-
generate(txt)
:由 txt 文本生成词云 -
to_file(filename)
:将词云图保存为名为 filename 的图片,路径可自行设置
示例
英文文本:以 hamlet 为例
wordcloud 库 默认以空格或标点为分隔符对目标文件进行处理,因此特别适合直接处理英文文本。代码如下:
# -*-coding:utf-8-*-
from wordcloud import WordCloud
txt = open("C:/Users/SHOHOKU/Desktop/hamlet.txt","r").read()
wordcloud = WordCloud(font_path="AdobeKaitiStd-Regular.otf",width=911,height=305,max_words=36).generate(txt)
wordcloud.to_file("C:/Users/SHOHOKU/Desktop/hamlet.png")
效果如图所示:
当然,你既然读到这里了,我这么一个好心的人肯定会送你一份礼物。想了想,送你一份英文文本分割的程序吧,相信以后会用的到:
# -*-coding:utf-8-*-
# 文本预处理
def gettext():
txt = open("C:/Users/SHOHOKU/Desktop/hamlet.txt","r").read() #读取文本
txt = txt.lower() #统一大小写
symbol = [",",".","?","/","<",">",'''""''',"''",\
":",";","]","[]","{}","","+","=","-","_","()",\
"*","&","^","%","$","#","@","!","~","`"]
for s in symbol:
txt = txt.replace(s,"") #以空格代替特殊符号
return txt
# 文本处理
text = gettext() #加载文本
words = text.split() #以空格切分文章
# 词频统计
counts = {} #创建字典类型用来统计词汇及其频数
for word in words:
counts[word] = counts.get(word,0) + 1 #对于已有词汇,返回其序数并+1;对于新词汇,返回0并+1
# 结果展示
items = list(counts.items()) #将字典类型转换为列表类型,便于展示结果
items.sort(key=lambda x:x[1],reverse = True) #按照第二列对结果进行降序排序
for i in range(10): #展示出现次数最高的前10个单词
word,count = items[i]
print("{:<10}{}".format(word,count))
中文文本:以《三国演义》为例
需求:统计三国演义中出现频率前10的人物,并生成相应词云。
第一步:人物出场频率统计
# -*-coding:utf-8-*-
# 文本预处理
def gettext():
txt = open("C:/Users/SHOHOKU/Desktop/threekingdoms.txt","r",encoding="utf-8").read()
return txt
# 文本分割
import jieba
text = gettext()
words = jieba.lcut(text)
# 词频统计
counts = {}
for word in words:
if len(word)==1: #姓名通常不为一字,故做简化处理
continue
else:
counts[word] = counts.get(word,0) + 1
# 结果展示
items = list(counts.items())
items.sort(key = lambda x:x[1],reverse=True)
for i in range(25):
word,count = items[i]
print("{:<10}{}".format(word,count))
结果如图所示:
我们发现,结果中存在着一些问题:有的和人名并无关系,将军这类词很模糊,而且像玄德曰,玄德,刘备其实是同一人物等。这是中文所特有的多语义性造成的。所以我们进行中文文本词频统计时,要适当地扩大探索范围,观察其展示结果的不足并加以改进,像DNA分子一样螺旋上升,才可以到达希望的顶峰。
我们试着改进其文本,以便能更好地满足我们的需求,经过不断尝试,我们可以获得一个大致结果:
# -*-coding:utf-8-*-
# 文本预处理
def gettext():
txt = open("C:/Users/SHOHOKU/Desktop/threekingdoms.txt","r",encoding="utf-8").read()
return txt
excludes = ["将军","荆州","却说","二人","不可","不能","如此",\
"商议","如何","军士","主公","军马","左右","次日","大喜","引兵","天下","于是","东吴","今日","魏兵",\
"不敢","陛下","一人","人马","不知","都督"]
# 文本分割
import jieba
text = gettext()
words = jieba.lcut(text)
# 词频统计
counts = {}
for word in words:
if len(word) == 1: #姓名不可能为一个字,舍弃之
continue
if word=="丞相" or word=="孟德":
rword="曹操"
if word=="诸葛亮" or word=="孔明曰":
rword = "孔明"
if word=="关公" or word=="云长":
rword = "关羽"
if word=="玄德" or word=="玄德曰":
rword = "刘备"
if word=="翼德":
rword = "张飞"
if word=="子龙":
rword = "赵云"
else:
rword = word
counts[rword] = counts.get(rword,0)+1
for word in excludes:
del counts[word]
# 结果展示
items = list(counts.items())
items.sort(key = lambda x:x[1],reverse=True)
for i in range(25):
word,count = items[i]
print("{:<10}{}".format(word,count))
结果如图所示:
我们发现改进过后的代码已经可以大致达到我们的目的,但通过去除词来重新分割文本的方法耗时费力,并不怎么提倡。如果有更好的方法,欢迎与笔者交流。
第二步:在文本分割的基础上利用空格分割文本,然后利用 wordcloud 库输出即可
# -*-coding:utf-8-*-
import jieba
from wordcloud import WordCloud
from scipy.misc import imread
img = imread("c:/Users/SHOHOKU/Desktop/chinamap.jpg")
excludes = ["将军","荆州","却说","二人","不可","不能","如此",\
"商议","如何","军士","主公","军马","左右","次日","大喜","引兵","天下","于是","东吴","今日","魏兵",\
"不敢","陛下","一人","人马","不知"]
def gettext():
f = open("C:/Users/SHOHOKU/Desktop/threekingdoms.txt","r",encoding="utf-8").read()
words = jieba.lcut(f)
ls = []
for i in words:
if len(i)==1 or i in excludes:
continue
elif i in ["丞相","孟德"]:
ls.append("曹操")
elif i in ["孔明曰","孔明"]:
ls.append("诸葛亮")
elif i in ["玄德曰","玄德"]:
ls.append("刘备")
elif i in ["关公","云长"]:
ls.append("关羽")
elif i in ["翼德"]:
ls.append("张飞")
elif i in ["子龙"]:
ls.append("赵云")
elif i in ["都督"]:
ls.append("周瑜")
else:
ls.append(i)
return " ".join(ls)
txt = gettext()
w = WordCloud(font_path="STXINGKA.TTF",width=911,height=305,mask=img,max_words=10,background_color="white").generate(txt)
w.to_file("c:/Users/SHOHOKU/Desktop/April.png")
效果如图所示: