本次案例教大家怎么进行文本的TF-idf值的计算,并且使用这个相应的词向量进行LDA文本主题模型的构建,然后画出每个主题的重要词汇的词云图。

任何文本数据,只要是很多条文本,都能进行上面的建模操作。这一套流程对于文本大数据分析是非常实用的。

(部分图片打了马赛克是因为应该有敏感词汇不让显示.....)

需要这代码演示数据的同学可以参考:数据


文本读取 分词

导入包,读取停用词

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
plt.rcParams['font.sans-serif'] = ['KaiTi']  #指定默认字体 SimHei黑体
plt.rcParams['axes.unicode_minus'] = False   #解决保存图像是负号'
import jieba
stop_list  = pd.read_csv("停用词.txt",index_col=False,quoting=3,sep="\t",names=['stopword'], encoding='utf-8')

对我们的本文数据进行读取,然后使用jieba库进行分词操作

#Jieba分词函数
def txt_cut(juzi):
    lis=[w for w in jieba.lcut(juzi) if w not in stop_list.values]
    return (" ").join(lis)
df=pd.read_excel('2022新闻.xlsx')
df['cutword']=df['content'].astype('str').apply(txt_cut)

查看我们的数据前五行现在的样子:

df.head()

 我使用的数据是2022年所有的央视新闻的文本,day是日期,前五条都是2022年1月1日的,title是这个新闻的标题,content是新闻文本内容,cutword就是进行停用词去除,分词后的词汇。

可以看到分词后,每个词语中间都是空白连接,标点符号都去了,这样方便后面进行文本的词向量化。


jieba分析

首先使用jieba库统计一下,2022年所有新闻文本的词汇重要性排序。

import jieba.analyse
jieba.analyse.set_stop_words('停用词.txt')
#合并一起
text = ''
for i in range(len(df['cutword'])):
    text += df['cutword'][i]+'\n'
jieba.analyse.extract_tags(text,topK=20,withWeight=True)

 

我这里只输出了前20个最重要的词汇。既然是央视的新闻,那么央视网,新闻联播这些词显然都是出现得最多的。

发展,中国,国家,这些也都是新闻联播常见的用词了。

病例,新冠,疫情,在2022年,新闻对于这些东西也是播报频率很高的。


Tf-IDF分析

上面的词频统计(TF)分析其实都是新闻联播常用的词汇,那么经过逆词频(idf)计算后,真实的词语重要性排序是什么呢,下面进行TF-IDF计算,词向量化。

from sklearn.feature_extraction.text import  CountVectorizer,TfidfVectorizer
from sklearn.decomposition import LatentDirichletAllocation
tf_vectorizer = TfidfVectorizer()
#tf_vectorizer = TfidfVectorizer(ngram_range=(2,2)) #2元词袋
X = tf_vectorizer.fit_transform(df.cutword)
#print(tf_vectorizer.get_feature_names_out())
print(X.shape)

可以看到,这里将分词好了的文本变为了48265列数值型的特征变量X。这样就方便模型计算。

查看TF-IDF值排序

data1 = {'word': tf_vectorizer.get_feature_names_out(),
        'tfidf': X.toarray().sum(axis=0).tolist()}
df1 = pd.DataFrame(data1).sort_values(by="tfidf" ,ascending=False,ignore_index=True) 
df1.head(20)

 

 TF-IDF值最高的前20个词汇排序如图,说明真实的最重要的词汇大概是:病例,发展,中国,m国,这些词汇。

像央视网,新闻联播这些几乎每个新闻都有的词汇就排名往下掉了。


LDA建模

LDA模型可以说类似于聚类模型,是一种无监督的算法,就是把文本数据自动划分为几类几类话题,然后每类话题都有一些高频词汇可以输出出来。

说白了就是一种专门针对文本数据的聚类方法。

由于是无监督,所以聚类效果也不好评价。聚类个数也不知道咋选.....

本文主观的将聚类个数定为10,即将文本数据划分为10个主题类别。

n_topics = 10  #分为10类
lda = LatentDirichletAllocation(n_components=n_topics, max_iter=100,
                                learning_method='batch',
                                learning_offset=100,
#                                 doc_topic_prior=0.1,
#                                 topic_word_prior=0.01,
                               random_state=0)
lda.fit(X)

 模型拟合好后,查看结果前先定义一个函数,让结果输出更好看一下。

def print_top_words(model, feature_names, n_top_words):
    tword = []
    tword2 = []
    tword3=[]
    for topic_idx, topic in enumerate(model.components_):
        print("Topic #%d:" % topic_idx)
        topic_w = [feature_names[i] for i in topic.argsort()[:-n_top_words - 1:-1]]
        topic_pro=[str(round(topic[i],3)) for i in topic.argsort()[:-n_top_words - 1:-1]]  #(round(topic[i],3))
        tword.append(topic_w) 
        tword2.append(topic_pro)
        print(" ".join(topic_w))
        print(" ".join(topic_pro))
        print(' ')
        word_pro=dict(zip(topic_w,topic_pro))
        tword3.append(word_pro)
    return tword3

选择每个主题输出前20个重要词汇;

##输出每个主题对应词语和概率
n_top_words = 20
feature_names = tf_vectorizer.get_feature_names_out()
word_pro = print_top_words(lda, feature_names, n_top_words)

可以看到,输出了10个主题,每个主题对应输出20个重要词汇和他们的重要性数值。

那么每条新闻属于哪类话题,可以通过下面代码得到每篇文章对应主题

#输出每篇文章对应主题
topics=lda.transform(X)
topic=np.argmax(topics,axis=1)
df['topic']=topic
#df.to_excel("data_topic.xlsx",index=False)
print(topics.shape)
print(topics[0])
topic[0]

 如图预测的类别是一个(5337,10)的数据,5337是样本个数,即5337条新闻,10是分为10类,每一类的概率值。

我们查看第一条数据的10的类别概率值,发现它是第0类话题的概率是0.0213,第1类话题的概率是0.1518,第2类话题的概率是0.52......以此类推。

由于它是第2类话题的概率0.52最大,所以第一条新闻被认为是第2类话题。


词云图

打印出来每个话题关键词不够直观,画出每类话题的词云图看。

先定义一个随机颜色的函数。能随机返回颜色。

import random   #定义随机生成颜色函数
def randomcolor():
    colorArr = ['1','2','3','4','5','6','7','8','9','A','B','C','D','E','F']
    color ="#"+''.join([random.choice(colorArr) for i in range(6)])
    return color
[randomcolor() for i in range(3)]

 词语图设置

from collections import Counter
from wordcloud import WordCloud
from matplotlib import colors
#from imageio import imread    #形状设置
#mask = imread('爱心.png')  

def generate_wordcloud(tup):
    color_list=[randomcolor() for i in range(10)]  #随机生成10个颜色
    wordcloud = WordCloud(background_color='white',font_path='simhei.ttf',#mask = mask, #形状设置
                          max_words=20, max_font_size=50,random_state=42,
                          colormap=colors.ListedColormap(color_list)       #颜色
                          ).generate(str(tup))
    return wordcloud

画多子图

dis_cols = 4                  #一行几个
dis_rows = 3
dis_wordnum=20
plt.figure(figsize=(5 * dis_cols, 5 * dis_rows),dpi=128)
kind=len(df['topic'].unique())

for i in range(kind):
    ax=plt.subplot(dis_rows,dis_cols,i+1)
    most10 = [ (k,float(v)) for k,v in word_pro[i].items()][:dis_wordnum]  #高频词
    ax.imshow(generate_wordcloud(most10), interpolation="bilinear")
    ax.axis('off')
    ax.set_title("第{}类话题 前{}词汇".format(i,dis_wordnum), fontsize=30)
plt.tight_layout()
plt.show()

 可以看到每一类话题的重要性词汇都画出来了,词语越大说明这个词越重要。

可以看到LDA模型效果还是不错的,比如第2类话题出现了很多中国,合作,发展,人民,全面等词汇,说明第2类话题就是那些新闻联播里面老生常谈的些描述国家发展的新闻。

第7类话题出现了很多病例,输入,确诊,新增,本土,新冠等这些词汇,说明第7类话题就是那些天天报道新冠疫情情况的新闻。

第4类话题出现了很多冬奥会,运动员,滑雪,选手,比赛等这些词汇,说明第4类话题就是描述冬奥会比赛情况的新闻。

其他话题也有各自的主题和道理。

这是2022的央视网新闻,换成任何一个其他的文本都可以进行上述的分析,比如可以分析股吧评论,电影标语,微博热搜等等。最终可以得到每个文本的类别和词云图。


创作不易,看官觉得写得还不错的话点个关注和赞吧,本人会持续更新python数据分析领域的代码文章~(需要定制代码可私信)

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐