python实现LDA主题建模
本文详细介绍了如何使用Python实现LDA主题建模。LDA是一种用于主题建模的概率图模型,其基本思想是:每个文档是由一组主题混合而成的,每个主题又由一组词汇构成,而LDA试图找到最佳的主题和词汇组合,以解释给定的文本数据。
前言
本文详细介绍了如何使用Python实现LDA主题建模。LDA是一种用于主题建模的概率图模型,其基本思想是:每个文档是由一组主题混合而成的,每个主题又由一组词汇构成,而LDA试图找到最佳的主题和词汇组合,以解释给定的文本数据。
具体操作步骤
一、环境配置与数据准备
1.1 安装依赖库
首先,确保已经安装了所需的库:
pip install pandas matplotlib gensim scikit-learn jieba
1.2 导入模块
接着,导入我们所需要用到的库及模块:
import os # 导入 os 模块,用于与操作系统进行交互
import pandas as pd # 导入 pandas 库,用于数据处理和分析
import matplotlib.pyplot as plt # 导入 matplotlib 库的 pyplot 模块,用于绘制图表
from gensim.corpora import Dictionary # 从 gensim 库的 corpora 模块中导入 Dictionary 类,用于创建词典
from gensim.models import LdaModel # 从 gensim 库的 models 模块中导入 LdaModel 类,用于实现潜在狄利克雷分配(LDA)模型
from gensim.models.coherencemodel import CoherenceModel # 从 gensim 库的 models 模块中导入 CoherenceModel 类,用于计算主题模型的一致性
import jieba # 导入 jieba 库,用于中文分词
1.3 设置Matplotlib参数
设置Matplotlib参数,以便在绘制图像时能够正确显示中文字符,解决负号显示问题:
plt.rcParams['font.sans-serif'] = ['SimHei'] # 使用黑体字体
plt.rcParams['axes.unicode_minus'] = False # 解决负号显示问题
1.4 加载停用词表
with open('cn_stopwords.txt', 'r', encoding='utf-8') as f:
stop_words = set(f.read().splitlines()) # 读取停用词文件并转换为集合
二、数据加载与处理
2.1 文本预处理
由于存在一些纯数字的无效评论,因此会先将这类评论筛掉,然后再使用jieba进行中文分词,并通过停用词表进行去停用词操作,最后将单个字评论以及空评论数据过滤,因为这些数据并无意义,单个字无法表达含义。
def preprocess_text(text):
if not isinstance(text, str): # 检查输入是否为字符串
return [] # 如果不是字符串,返回空列表
words = list(jieba.cut(text)) # 使用jieba进行分词
filtered_words = [word for word in words if word not in stop_words and len(word) > 1] # 过滤掉停用词和长度小于等于1的单词
return filtered_words
2.2 计算不同主题数量下的Coherence值
在应用LDA模型之前,我们需要确定合适的主题数量,这里我们选择一致性Coherence指标来进行衡量,一致性能够评估主题模型的语义质量,值越高,说明主题内部的词语在语义上越相关,反映出主题的可解释性越强。
def compute_coherence_values(dictionary, corpus, texts, limit=20, start=1, step=1):
coherence_values = [] # 初始化Coherence值列表
for num_topics in range(start, limit + 1, step): # 遍历不同的主题数量
model = LdaModel(corpus=corpus, id2word=dictionary, num_topics=num_topics, random_state=42, passes=10) # 训练LDA模型
coherencemodel = CoherenceModel(model=model, texts=texts, dictionary=dictionary, coherence='c_v') # 计算Coherence模型
coherence_values.append(coherencemodel.get_coherence()) # 获取并存储Coherence值
return coherence_values
2.3 绘制主题数量与Coherence得分的关系图
使用计算得到的Coherence值以及对应的主题数,绘制它们之间的关系图,从而找到最佳主题数。
def plot_graph(coherence_values, title, output_folder):
x = range(1, len(coherence_values) + 1) # X轴表示主题数量
plt.figure() # 创建一个新的图形
plt.plot(x, coherence_values, marker='o') # 绘制Coherence值曲线
plt.xlabel("Num Topics") # 设置X轴标签
plt.ylabel("Coherence Score") # 设置Y轴标签
plt.title(title) # 设置图形标题
output_path = os.path.join(output_folder, f'{title.replace(" ", "_")}.png') # 构建输出文件路径
plt.savefig(output_path) # 保存图形
plt.close() # 关闭图形
print(f'Saved coherence plot for {title} to {output_path}') # 打印保存信息
图像如下所示,横坐标为主题数,纵坐标为对应的Coherence得分。在图像中,寻找最高拐点,该拐点对应的主题数量即为最佳主题数量。原因是在这个主题数量下,一致性值达到较高水平,若继续增加主题数量,对一致性的提升效果开始减弱。选择这样的主题数量,既能保持模型性能,又能避免模型过于复杂,同时主题具有较好的可解释性。
2.4 数据处理及生成Coherence图
在该函数中,首先对评论数据进行基本的去重和去缺失值操作,接着调用preprocess_text()进行分词、去停用词、去短词等进一步的数据处理操作,然后再使用tolist()函数提取预处理后的评论转换为 Python 列表;使用Dictionary()函数创建一个词典,将每个唯一的词映射到一个整数 ID;使用doc2bow()函数将每个文档转换为稀疏向量表示,其中每个元素是一个元组 (word_id, count),表示词的 ID 及其在文档中的出现次数,从而构建LDA模型所需的语料库。接着计算不同主题数量下的Coherence值,并绘制主题数量与Coherence得分的关系图,帮助确定最佳主题数。(这里先对整体评论进行上述操作,然后再分别对不同类别商品评论进行上述操作)
def process_data(df, sentiment, output_folder):
df.dropna(subset=['comment'], inplace=True) # 去除评论列中的缺失值
df.drop_duplicates(subset=['comment'], inplace=True) # 去除评论列中的重复项
df['comment_cleaned'] = df['comment'].apply(preprocess_text) # 对评论进行预处理
texts = df['comment_cleaned'].tolist() # 提取预处理后的评论
dictionary = Dictionary(texts) # 创建字典
corpus = [dictionary.doc2bow(text) for text in texts] # 创建语料库
# 计算Coherence值并绘图
coherence_values = compute_coherence_values(dictionary, corpus, texts)
plot_graph(coherence_values, f"Coherence Score vs Number of Topics - {sentiment}", output_folder)
# 对每个类别重复上述过程
categories = df['catagory'].unique() # 获取所有类别
for cat in categories:
cat_texts = df[df['catagory'] == cat]['comment_cleaned'].tolist() # 获取某一类别的评论
cat_dictionary = Dictionary(cat_texts) # 创建该类别的字典
cat_corpus = [cat_dictionary.doc2bow(text) for text in cat_texts] # 创建该类别的语料库
cat_coherence_values = compute_coherence_values(cat_dictionary, cat_corpus, cat_texts)
plot_graph(cat_coherence_values, f"Coherence Score vs Number of Topics - {cat} ({sentiment})", output_folder)
# 保存预处理后的数据到Excel文件
preprocessed_output_path = os.path.join(output_folder, f'preprocessed_{sentiment}.xlsx')
df.to_excel(preprocessed_output_path, index=False)
print(f'Saved preprocessed data for {sentiment} to {preprocessed_output_path}')
预处理后的数据保存到coherence_plots文件夹中。
2.5 主程序
在主程序中,首先定义输入和输出路径,若输出目录不存在,则创建输出目录。接着分别读取需要进行主题建模的两类情感类别评论数据,然后分别调用数据处理及生成Coherence图的函数,进行后续操作。
if __name__ == "__main__":
# 文件路径和输出文件夹
file_path = "韩束sentiment.xlsx"
output_folder = 'coherence_plots'
os.makedirs(output_folder, exist_ok=True) # 创建输出文件夹(如果不存在)
# 读取Excel文件
like_df = pd.read_excel(file_path, sheet_name='特别喜欢')
dislike_df = pd.read_excel(file_path, sheet_name='不喜欢')
# 处理“特别喜欢”和“不喜欢”数据
process_data(like_df, 'Like', output_folder)
process_data(dislike_df, 'Dislike', output_folder)
三、提取主题及可视化
3.1 安装并导入依赖库
首先,确保已经安装了所需的库:
pip install pandas gensim pyLDAvis
然后导入所需要的库及模块:
import pandas as pd # 导入pandas库用于数据处理
from gensim import corpora, models # 导入gensim库中的corpora和models模块用于主题建模
import pyLDAvis # 导入pyLDAvis库用于主题模型的可视化
import pyLDAvis.gensim_models as gensimvis # 导入pyLDAvis.gensim_models模块以支持gensim模型
3.2 定义最佳主题数
根据前面绘制的主题数量与Coherence得分关系图得到的最佳主题数。
# 定义每个情感评论对应的最佳主题数量(整体)
topics_per_sentiment_overall = {
'特别喜欢': 15 # 对于“特别喜欢”情感,整体使用15个主题
}
# 定义每个情感评论在不同类别中的最佳主题数量
topics_per_sentiment_category = {
'特别喜欢': {'洁面': 17, '精华水': 12, '精华液': 10, '乳液': 16} # 对于“特别喜欢”情感,在不同类别中使用的主题数量
}
3.3 读取Excel数据
在前面的操作中,预处理后的数据保存到了coherence_plots文件夹中,这里需要把路径替换为文件夹中的Excel路径。(本文只对特别喜欢类别的评论数据进行了主题提取)
# Excel文件路径
excel_file_path = r"D:\xxx\xxx\coherence_plots\preprocessed_Like.xlsx"
# 创建一个空的DataFrame列表用于后续合并
dfs_for_excel = []
# 读取Excel文件中的特定工作表
df = pd.read_excel(excel_file_path)
3.4 comment_cleaned字段处理
comment_cleaned字段记录了分词等预处理后的评论数据,需要先转换成单词列表:
def split_to_tokens(text):
if isinstance(text, str): # 检查输入是否为字符串
# 去掉方括号和引号
text = text.strip('[]').replace("'", "") # 去除字符串两端的方括号和单引号
# 去掉逗号
text = text.replace(',', '') # 去除字符串中的逗号
return text.split() # 将字符串按空格分割成单词列表
else:
return [] # 如果输入不是字符串,返回空列表
3.5 主题提取与可视化
对评论数据进行 LDA 主题建模分析。首先对整体评论数据进行主题建模,生成可视化的 HTML 文件;然后按商品类别细分数据,对每个类别分别构建 LDA 模型并生成可视化结果;最后将每个类别下的主题特征词及其权重保存到 DataFrame 中,收集到 dfs_for_excel 列表以便后续导出到 Excel 文件。具体包括Gensim 词典构建、词袋模型转换、LDA 模型训练、pyLDAvis 可视化这几个关键步骤。
# 分别对每个情感的整体数据进行LDA主题分析
for sentiment in ['特别喜欢']: # 遍历情感类型
num_topics_overall = topics_per_sentiment_overall[sentiment] # 获取该情感的整体主题数量
# 填充可能存在的NaN值,并应用split_to_tokens函数
df.loc[:, 'comment_cleaned'] = df['comment_cleaned'].fillna('') # 将'comment_cleaned'列中的NaN值填充为空字符串
df.loc[:, 'tokens'] = df['comment_cleaned'].apply(split_to_tokens) # 应用split_to_tokens函数将评论转换为词列表
# 构建主题模型
dictionary = corpora.Dictionary(df['tokens']) # 创建Gensim字典对象
corpus = [dictionary.doc2bow(text) for text in df['tokens']] # 将文档转换为词袋表示
lda_model = models.LdaModel(corpus, num_topics=num_topics_overall, id2word=dictionary, passes=15) # 训练LDA模型
# 使用 pyLDAvis 可视化整体数据
vis_data = gensimvis.prepare(lda_model, corpus, dictionary) # 准备可视化数据
pyLDAvis.save_html(vis_data, f'{sentiment}_overall_visualization.html') # 保存可视化结果为HTML文件
# 根据类别细分数据并进行LDA主题分析
categories = df['catagory'].unique() # 获取所有唯一的类别
for category in categories: # 遍历每个类别
category_df = df[df['catagory'] == category].copy() # 过滤出当前类别的数据并复制
num_topics_category = topics_per_sentiment_category[sentiment].get(category, 1) # 获取该类别下的主题数量,默认为1
# 填充可能存在的NaN值,并应用split_to_tokens函数
category_df.loc[:, 'comment_cleaned'] = category_df['comment_cleaned'].fillna('') # 将'comment_cleaned'列中的NaN值填充为空字符串
category_df.loc[:, 'tokens'] = category_df['comment_cleaned'].apply(split_to_tokens) # 应用split_to_tokens函数将评论转换为词列表
# 构建主题模型
dictionary = corpora.Dictionary(category_df['tokens']) # 创建Gensim字典对象
corpus = [dictionary.doc2bow(text) for text in category_df['tokens']] # 将文档转换为词袋表示
lda_model = models.LdaModel(corpus, num_topics=num_topics_category, id2word=dictionary, passes=15) # 训练LDA模型
# 使用 pyLDAvis 可视化分类数据
vis_data = gensimvis.prepare(lda_model, corpus, dictionary) # 准备可视化数据
pyLDAvis.save_html(vis_data, f'{category}_{sentiment}_visualization.html') # 保存可视化结果为HTML文件
# 创建一个新的DataFrame来保存主题模型的结果
topic_results = []
for i in range(num_topics_category): # 遍历每个主题
topic_details = lda_model.print_topic(i) # 获取主题的特征词及其权重
topic_results.append({'所属主题': f'topic {i}', '特征词及其权重': topic_details}) # 将结果添加到列表中
result_df = pd.DataFrame(topic_results) # 将结果列表转换为DataFrame
# 如果结果不为空,则添加到dfs_for_excel列表中
if not result_df.empty: # 检查DataFrame是否为空
sheet_name = f'{category}_{sentiment}' # 设置Sheet名称
result_df.index.name = sheet_name # 设置DataFrame索引名称
dfs_for_excel.append((sheet_name, result_df)) # 将结果添加到列表中
LDA 主题模型的可视化结果如下所示,主要包含两部分核心内容:左侧是主题距离图,通过多维缩放展示主题间的语义距离,主题圆圈的位置越近,代表主题内容越相关,圆圈大小反映主题在整体数据中的占比,这里主题2、3、4内容较相关;右侧是主题词分布,展示当前选中主题(主题 6)的核心词汇,横轴表示词汇的相关度量,红色条(主题内词频)越长,说明该词对主题 6 的代表性越强,例如 “购买”“满意”“很多” 等词在主题 6 中高频出现,表明主题 6 主要围绕 “购买体验、满意评价” 方面。
3.6 结果保存
将主题提取结果保存到新Excel:
# 将结果写入新的Excel文件
if dfs_for_excel: # 检查是否有结果需要写入
with pd.ExcelWriter('主题.xlsx', engine='openpyxl') as writer: # 创建Excel写入器
for sheet_name, df in dfs_for_excel: # 遍历每个结果
df.to_excel(writer, sheet_name=sheet_name, index=False) # 将DataFrame写入指定Sheet
else:
print("没有数据可写入Excel文件。") # 如果没有结果,打印提示信息
所属主题列是不同的主题编号(如 topic 0、topic 1 ),每个编号代表一个通过 LDA 模型挖掘出的潜在主题;特征词及其权重是每个主题下列出与之关联的特征词及对应权重,权重体现词在该主题中的重要性,权重越高,词对主题的代表性越强。topic 13中 “物美价廉”“值得”“购买”权重较高,说明该主题与 “产品性价比及购买推荐” 相关。
结语
如果大家觉得有帮助,请多多点赞收藏支持一下,谢谢大家。如果遇到什么问题,也非常欢迎大家私信。

GitCode 天启AI是一款由 GitCode 团队打造的智能助手,基于先进的LLM(大语言模型)与多智能体 Agent 技术构建,致力于为用户提供高效、智能、多模态的创作与开发支持。它不仅支持自然语言对话,还具备处理文件、生成 PPT、撰写分析报告、开发 Web 应用等多项能力,真正做到“一句话,让 Al帮你完成复杂任务”。
更多推荐
所有评论(0)