Python:基于词频、TF-IDF 生成词云图


现有一份介绍某地点的 txt 文件,需要编写 Python 程序制作介绍文档的词云图。

读取数据#

数据预处理#

文本中可能存在着许多特殊符号,这些符号中不蕴含有效信息,且会影响分词效果,所以需要去除。对于空格、换行、制表符等停顿的符号,也需要统一换成中文逗号。由于本次处理的是中文文本,所以文本的某些无意义的英文字母同样也要进行去除。部分评论文本中还存在着部分网站,图片链接,日期,该部分内容穿插在文本中,影响文本处理。
编写 data_process() 函数进行数据预处理,包括删除各种不想要的字符和英文日期等功能,主要是基于正则表达式实现的。其中 str_data 待预处理的字符串,返回值类型为 string,是预处理后的单个句子。

Copy Highlighter-hljs
import re def data_process(str_data): # 去除换行、空格、网址、参考文献 data_after_process = re.sub(r'\n+', '', str_data) data_after_process = re.sub(r'\s+', '', data_after_process) data_after_process = re.sub(r'[a-zA-z]+://[^\s]*', '', data_after_process) data_after_process = re.sub(r'\[([^\[\]]+)\]', '', data_after_process) # 删除日期:YY/MM/DD YY-MM-DD YY年MM月DD日 data_after_process = re.sub(r'\d{4}-\d{1,2}-\d{1,2}','',data_after_process) data_after_process = re.sub(r'\d{4}[-/]\d{2}[-/]\d{2}', '', data_after_process) # 删除标点符号 punctuation = """"!!??#$%&'()()*+-/:;<=>@[\]^_`●{|}~⦅⦆「」、、〃》「」『』【】〔〕〖〗〘〙〚〛*°▽〜〝〞〟〰〾〿–—‘'‛“”„‟…‧﹏""" re_punctuation = "[{}]+".format(punctuation) data_after_process = re.sub(re_punctuation, '', data_after_process) return data_after_process

读取文件#

例如将厦门的百度百科词条保存在 txt 文件中,需要将文件内容读入内存。

读取 txt 文件的数据后进行数据预处理,接着以句号划分句子,返回由句子组成的 list。编写 getText() 函数,参数 filename 为读取的 txt 文件,返回值类型为 list 为划分且预处理过后的句子列表。

Copy Highlighter-hljs
def getText(filename): fp = open(r'./' + filename, 'r', encoding='utf-8') sentences = fp.readlines() fp.close() for i in range(len(sentences)): sentences[i] = data_process(sentences[i]) sentences = " ".join(sentences).split('。') return sentences

词频统计#

jieba 分词库#

分词是自然语言处理的重要步骤,英文以空格作为天然的分割符,利用空格进行分割就能简单的提取出较有完整含义的单词。而现代汉语中,一条语句中没有任何的分割符,只有标点符号用于进行语句的划分,无法简单的提取出单个具有完整含义的词。而如果按标点符号进行划分,句子中承载的信息太多,很难复用分析。词的长度不像句子那么长,但是承载的信息量也比字多,且能够表达完整含义,故以词为单位进行分割是最合适的。

Jieba 分词器属于概率语言模型分词,基于前缀词典实现高效的词图扫描,生成句子中汉字所有可能成词情况构建成有向无环图,然后采用动态规划寻找最大概率路径,找出基于词频的最大切分组合。对于不存在与前缀词典中的词,采用了汉字成词能力的 HMM 模型,使用了 Viterbi 算法。Jieba 的切分模式有全模式、精确模式、搜索引擎模式,更多详细信息可以查看 github 仓库

函数编写#

编写 getWordFrequency() 函数对传入的句子列表统计词频,其中参数 sentences 为存储多个句子的列表,应当已经过预处理,返回值 words_dict 是以 dict 存储的词频。使用 psg.cut() 函数分词之后转换为 list,然后使用 dict 对词进行计数即可。

Copy Highlighter-hljs
import jieba.posseg as psg def getWordFrequency(sentences): words_dict = {} for text in sentences: # 去掉标点 text = re.sub("[\s+\.\!\/_,$%^*(+\"\']+|[+——!,。?、~@#¥%……&*()]+", "",text) # 结巴分词 wordGen = psg.cut(text) # 结巴分词的输出结果为一个生成器,把生成器转换为 list for word, attr in wordGen: if attr in ['n', 'nr', 'nz']: if word in words_dict.keys(): words_dict[word] += 1 else: words_dict[word] = 1 return words_dict

TF-IDF 方法#

TF-IDF#

TF-IDF 是一种用于信息检索与数据挖掘的常用加权技术,可以评估一个单词对于语料库的重要程度,并给出合适的权重。
其中TF 为词频,为某一单词在语料库中出现的次数,设单词 Ti、在文本 Dj 总次数为 ni、j 和 K 表示该文本单词的个数,计算公式为:

IDF 是逆文档频率,用于描述单词在语料库中的普遍重要性,设 |D| 表示整个语料库,|{j:ti∈dj}| 表示包含单词 ti,在所有文本中的总出现次数,计算公式为:

TF-IDF 可以给出特征词的权重,公式为如下。利用 TF-IDF 核心思想是字词的重要性随着它在文件中出现的次数成正比增加,但同时会随着它在语料库中出现的频率成反比下降。一个词语在一篇文章中出现次数越多,同时在所有文档中出现次数越少,越能够代表该文章,越能与其它文章区分开来。

函数编写#

编写 getTFIDF() 函数对传入的句子列表计算 TF-IDF,其中 sentences 为存储多个句子的列表,应当已经过预处理,返回的 words_dict 是以 dict 存储的 TF-IDF。计算 TF-IDF 时可以将每个句子当做一篇小短文,然后使用 jieba 进行分词,使用 sklearn 的 TfidfTransformer 和 CountVectorizer 进行计算得出。
CountVectorizer 是一个特征数值计算类,能将文本中的词语转换为词频矩阵,通过 fit_transform 函数计算各个词语出现的次数。TfidfTransformer 可以根据输入的词频输出它们的 TF-IDF,更多介绍可以看文末的参考资料。

Copy Highlighter-hljs
from sklearn.feature_extraction.text import TfidfTransformer from sklearn.feature_extraction.text import CountVectorizer def getTFIDF(sentences): corpus = [] for text in sentences: # 去掉标点 text = re.sub("[\s+\.\!\/_,$%^*(+\"\']+|[+——!,。?、~@#¥%……&*()]+", "",text) # 结巴分词 wordGen = psg.cut(text) # 结巴分词的输出结果为一个生成器,把生成器转换为list cut_list = [] for word, attr in wordGen: if attr in ['n', 'nr', 'nz']: cut_list.append(word) corpus.append(" ".join(cut_list)) words_dict = {} # 将文本中的词语转换为词频矩阵,矩阵元素a[i][j] 表示j词在i类文本下的词频 vectorizer = CountVectorizer() # 计算每个词语的tf-idf权值 transformer = TfidfTransformer() # 将文本转为词频矩阵 matrix = vectorizer.fit_transform(corpus) # 计算tf-idf tfidf = transformer.fit_transform(matrix) # 获取词袋模型中的所有词语 word = vectorizer.get_feature_names() # 将tf-idf矩阵抽取出来,元素a[i][j]表示j词在i类文本中的tf-idf权重 weight = tfidf.toarray() # 打印每类文本的tf-idf词语权重,第一个for遍历所有文本,第二个for遍历某一类文本下的词语权重 for i in range(len(weight)): for j in range(len(word)): if word[j] in words_dict: words_dict[word[j]] += weight[i][j] else: words_dict[word[j]] = weight[i][j] return words_dict

生成词云图#

wordCloud 库#

Python 可以使用 wordCloud库生成词云图,安装的 pip 命令如下:

Copy Highlighter-hljs
pip install wordcloud

wordCloud 库的特点是可以填充所有可用空间、能够使用任意掩码、简单易用,主要的 API 如下:

函数 功能
WordCloud([font_path, width, height, ...]) 用于生成和绘制的词云对象
ImageColorGenerator(image[, default_color]) 基于彩色图像的颜色生成器
random_color_func([word,font_size,...]) 生成随机色调的颜色
get_single_color_func(color) 函数返回单个色调和饱和度

函数编写#

首先需要先选择一张用于生成词云图的图片,ImageColorGenerator 将根据图片的形状和颜色进行填充,例如选择皮卡丘的图片。

基于 wordCloud 库编写 showCloud() 函数,对传入的词频生成词云图。其中传入的参数 wordDict 是以 dict 格式存储的词频,filename 是生成的图片的文件名。需要先用 WordCloud() 函数根据词频生成词云图对象,然后用 ImageColorGenerator() 提供颜色和形状,最后保存为图片。

Copy Highlighter-hljs
from PIL import Image, ImageSequence import numpy as np import pandas as pd import matplotlib.pyplot as plt from wordcloud import WordCloud, ImageColorGenerator def showCloud(wordDict, filename): # 根据图片创建 graph 为 nd-array 类型 image = Image.open("./pikachu.jpg") graph = np.array(image) # 创建 wordcloud 对象,背景图片为 graph,背景色为白色 wc = WordCloud(mask = graph, background_color = 'white', font_path='STXINWEI.TTF') # 生成词云 wc.generate_from_frequencies(wordDict) # 根据 graph 生成颜色 image_color = ImageColorGenerator(graph) plt.imshow(wc.recolor(color_func=image_color)) #对词云重新着色 plt.axis('off') # 显示词云图,并保存为 jpg 文件 #plt.show() wc.to_file(filename + ".jpg") plt.clf()

词云图生成效果#

调用上述函数:

Copy Highlighter-hljs
showCloud(getWordFrequency(getTest('厦门.txt')), "xiamen") showCloud(getTFIDF(getTest('厦门.txt')), "xiamen_tfidf")

基于词频的词云图效果如下:

基于 TF-IDF 的词云图,可以明显地看出基于 TF-IDF 生成的词云图更能凸显出文本的关键信息。

参考资料#

github jieba
WordCloud for Python documentation
sklearn——CountVectorizer详解
TfidfVectorizer、CountVectorizer 和TfidfTransformer

posted @   乌漆WhiteMoon  阅读(1762)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)
点击右上角即可分享
微信分享提示
CONTENTS