目录
项目背景
项目步骤
一、评论数据准备
二、使用步骤
1.将评论以日为单位合并
2.导包
3.TF-IDF提取关键词
4.Word2Vec词向量训练
5.LDA模型评估指标与最佳主题数的选取
三、结果可视化和分析
在2021年7月,一起“鸿星尔克捐款5000万”的事件引发了网友们的强烈反响。年轻一代网友,即所谓的“Z世代”,涌入直播间,进行了所谓的“野性消费”,即疯狂地超额抢购产品,导致销量暴涨。为了探究这种“野性消费”对国产品牌带来的影响和引起的思考,本项目对该时间段关于鸿星尔克的微博评论进行了基于LDA模型的主题特征分析
利用已经分词和清洗过后的评论数据作为项目数据来源,共有3500条评论。
drop_duplicates()
方法获得数据中的所有唯一时间戳。time
,使用 datas[datas["time"]==time]["tokenization_filtered"]
筛选出该时间段内的所有文档,然后使用 join()
方法将它们合并成一个字符串,并用空格分隔单词。同时,将合并后的字符串转化为单词列表(即按照空格切割)并存入 word_list
中,将字符串直接存入 comments_list
中。代码如下:
import pandas as pd
from pandas import DataFrame
from pandas import Series
datas = pd.read_csv("data_selected.csv", encoding='gbk', dtype={'tokenization_filtered': str, 'time': str})
word_list = []
comments_list = []
unique_time=datas["time"].drop_duplicates()
# 按时间段分组,将评论内容合并成一个长字符串,并转换为分词后的单词列表
for time, group in datas.groupby('time'):
comments = group['tokenization_filtered'].str.cat(sep=' ')
word_list.append(comments.split())
comments_list.append(comments)
代码如下:
import gensim
from gensim import corpora
import matplotlib.pyplot as plt
import matplotlib
import numpy as np
import warnings
warnings.filterwarnings('ignore') # To ignore all warnings that arise here to enhance clarity
from gensim.models.coherencemodel import CoherenceModel
from gensim.models.ldamodel import LdaModel
from gensim import models
from gensim.models import Word2Vec
from gensim.models.word2vec import LineSentence
plt.rcParams['font.family'] = 'SimHei' # 设置字体为中文宋体
TF-IDF(term frequency–inverse document frequency,词频-逆向文件频率)是一种用于信息检索(information retrieval)与文本挖掘(text mining)的常用加权技术。它由两部分组成,TF和IDF。TF-IDF是一种统计方法,用以评估一字词对于一个文件集或一个语料库中的其中一份文件的重要程度。字词的重要性随着它在文件中出现的次数成正比增加,但同时会随着它在语料库中出现的频率成反比下降。本文通过TF-IDF算法提取出鸿星尔克7月3日到9月1日每天的微博评论词语的权重比和最关键的三个词语。其中7月4日博文词语权重见表2-1,7月4日至7月5日最关键Top3见表2-2
代码如下:
from sklearn.feature_extraction.text import TfidfTransformer
from sklearn.feature_extraction.text import CountVectorizer
time_list=list(unique_time)
# 示例文本集合
corpus = comments_list
# 将文本转化为词频矩阵
vectorizer = CountVectorizer()
X = vectorizer.fit_transform(corpus)
# 计算tf-idf
transformer = TfidfTransformer()
tfidf = transformer.fit_transform(X)
# 输出每个词语对应的tf-idf值(该词重要程度)
feature_names = vectorizer.get_feature_names()
for i in range(tfidf.shape[0]):
print(time_list[i])
for j in tfidf[i].nonzero()[1]:
print(" {} : {:.2f}".format(feature_names[j], tfidf[i, j]))
# 输出每个文档中前n个tf-idf值最大的词语
n = 3
for i in range(tfidf.shape[0]):
print(time_list[i])
top_n = sorted(zip(feature_names, tfidf[i].toarray()[0]), key=lambda x: -x[1])[:n]
for word, score in top_n:
print(" {}: {:.2f}".format(word, score))
在原始的LDA模型中,对文本建模的方式采用的词袋模型,而词袋模型存在一个严重的问题就行,常用词的词频往往很高,专有名词的词频很低,这种建模方式存在一定的不合理性。TF-IDF 相对于词袋模型的优势在于,它可以更准确地体现出文档中关键词的重要性。词袋模型只考虑了每个单词在文档中的出现频率,而没有考虑到该单词在整个文集中的重要性。相比之下,TF-IDF 还考虑了文集中某个词的普遍重要程度。
代码如下:
# 根据文本列表创建一个语料库,每个词与一个整型索引值对应
word_dict = corpora.Dictionary(word_list)
# 词频统计,转化成空间向量格式
corpus_list = [word_dict.doc2bow(text) for text in word_list]
tfidf = models.TfidfModel(corpus_list)
corpus_tfidf = tfidf[corpus_list]
利用Word2Vec构建词向量相对于词袋模型的优势在于:
因此,利用Word2Vec构建词向量相对于词袋模型具有更好的表征能力、更高的泛化能力以及更高的处理效率。
代码如下:
import gensim
from gensim import corpora
import matplotlib.pyplot as plt
import matplotlib
import numpy as np
import warnings
warnings.filterwarnings('ignore') # To ignore all warnings that arise here to enhance clarity
from gensim.models.coherencemodel import CoherenceModel
from gensim.models.ldamodel import LdaModel
from gensim import models
from gensim.models import Word2Vec
from gensim.models.word2vec import LineSentence
plt.rcParams['font.family'] = 'SimHei' # 设置字体为中文宋体
主题一致性是指主题内部单词之间的联系程度,也被称为主题连贯度。在大多数关于主题建模的文章中,常用主题连贯度或主题连贯度指标来表示整体主题的可解释性,用于评估主题的质量。通常情况下,主题一致性越高,表示主题的连贯性越好,主题的可解释性也更高。
困惑度是衡量语言模型好坏的指标,也可以用于评估主题模型的质量。它反映了模型对新样本的泛化能力。困惑度越小,意味着模型对新样本的预测效果越好。在LDA中,可以通过计算每个主题下的单词概率来计算困惑度。
总的来说,主题一致性和困惑度是两种常用的评估LDA模型质量的指标。主题一致性主要关注主题内部单词之间的联系程度,而困惑度则更关注模型的泛化能力。
在项目中采用主题一致性来评估模型性能,本文采用TF-IDF和word2vec对文本建模,并绘制主题——一致性曲线来确定最佳主题个数,从而判断TF-IDF和word2vec是否对主题建模质量有所提高。并通过matplotlib绘制“主题-coherence”曲线来确定最优主题数。具体来说,首先在不同主题数下构建LDA模型,然后计算每个主题的一致性得分,最后将得分平均作为整个模型的一致性得分。通过不断改变主题数并计算一致性得分,得到一系列主题-coherence数据点,根据曲线的趋势选择最优主题数,从而确定模型的最佳主题数为7,且TF-IDF 主题建模的质量更好。
代码如下:
#计算困惑度
def perplexity(num_topics):
"""
计算主题数为num_topics时的困惑度
参数:
num_topics: int,主题数目
返回:
ldamodel.log_perplexity(corpus): float,困惑度大小
"""
ldamodel = LdaModel(corpus_list, num_topics=num_topics, id2word=word_dict, passes=30)
return ldamodel.log_perplexity(corpus_list)
#计算coherence
def coherence(num_topics):
"""
计算主题数为num_topics时的一致性(coherence)
参数:
num_topics: int,主题数目
返回:
ldacm.get_coherence(): float,一致性大小
"""
ldamodel = LdaModel(corpus_list, num_topics=num_topics, id2word=word_dict, passes=30, random_state=1)
ldacm = CoherenceModel(model=ldamodel, texts=word_list, dictionary=word_dict, coherence='c_v')
return ldacm.get_coherence()
def coherence_tfidf(num_topics):
ldamodel = LdaModel(corpus_tfidf, num_topics=num_topics, id2word=word_dict, passes=30, random_state=1)
ldacm = CoherenceModel(model=ldamodel, texts=word_list, dictionary=word_dict, coherence='c_v')
return ldacm.get_coherence()
def coherence_word2vec(num_topics):
ldamodel = LdaModel(corpus_vec, num_topics=num_topics, id2word=dictionary_vec, passes=30, random_state=1)
ldacm = CoherenceModel(model=ldamodel, texts=word_list, dictionary=dictionary_vec, coherence='c_v')
return ldacm.get_coherence()
x = range(1,13)
y = []
y_tfidf = []
y_word2vec = []
for i in x:
y.append(coherence(i))
y_tfidf.append(coherence_tfidf(i))
y_word2vec.append(coherence_word2vec(i))
# 创建画布
fig, ax = plt.subplots(figsize=(8,8))
ax.plot(x, y, color='b', label='coherence')
ax.plot(x, y_tfidf, color='g', label='tfidf coherence')
ax.plot(x, y_word2vec, color='r', label='word2vec coherence')
# 设置轮廓线和图例
for spine in ['left','bottom']:
ax.spines[spine].set_linewidth(1.5)
for spine in ['top','right']:
ax.spines[spine].set_visible(False)
ax.legend()
ax.set_title('主题-coherence变化情况')
ax.set_xlabel('主题数目')
ax.set_ylabel('coherence大小')
plt.show()
选择TF-IDF作为构建词向量的方法,输出每天最有可能的主题,结果如下
代码如下:
#设定主题数为7,并输出每个文档最有可能对应的主题
lda = LdaModel(corpus=corpus_tfidf, id2word=word_dict, num_topics=7, passes = 30,random_state=1)
topic_list=lda.print_topics()
for i in lda.get_document_topics(corpus_list)[:]:
listj=[]
for j in i:
listj.append(j[1])
bz=listj.index(max(listj))
print("主题{}".format(i[bz][0]+1),end=" ")
pyLDAvis库是一个用于对LDA模型结果进行可视化的Python库,可以通过交互式的方式呈现主题模型的结果,pyLDAvis生成的LDA可视化结果图可以帮助我们直观地理解主题之间的相似度和每个主题的重要性。在这个图中,每个圆圈代表一个主题,圆圈的面积表示该主题在整个文集中占比大小,而圆圈之间的距离表示主题之间的距离,距离越近表示它们之间的关联程度越高。从每个圆圈的中心可以看到该主题的具体词频排名,这些词是该主题区别于其他主题的特征性词汇。
本项目基于词此库对LDA模型结果进行可视化。作者分别对TF-IDF、word2vec,和词袋模型训练的LDA模型进行可视化,对可视化结果和各个主题下特征词进行分析,TF-IDF训练的LDA模型结果不同主题特征词差异性良好,一定程度上可以说明主题分类效果较好,但是结果主要集中在某个特定主题,其他主题圆圈非常小,很难区分不同的主题。可能是因为采集的是某个事件下的评论数据,导致评论数据主题过于接近,word2vec训练的LDA模型的三个主题具有包含关系,说明它们之间的相关性和相似性过高。词袋模型训练的LDA模型结果较为分散,但是通过人为分析每个主题下的特征词,发现不同主题特征词相似性和重复率很高,一定程度上说明主题区分度不是很高。
TF-IDF word2vec 词袋代码如下:
import pyLDAvis.gensim_models
from gensim import corpora, models
# 最终模型
## corpus: 文档词频矩阵
## num_topics:主题数目
## passes:训练伦次
lda = models.LdaModel(corpus = corpus_tfidf, id2word = word_dict, random_state = 1, num_topics = 7 , passes = 30, alpha='auto')# 结果展示
## lda: 训练好的模型
d = pyLDAvis.gensim_models.prepare(lda, corpus_tfidf, word_dict, mds = 'pcoa', sort_topics = True)
pyLDAvis.save_html(d, 'lda_show.html') # 将结果保存为html文件
# 展示在notebook的output cell中
pyLDAvis.enable_notebook()
vis = pyLDAvis.gensim_models.prepare(lda, corpus_list, word_dict)
vis