☰
基于Python的CNN/LSTM中文情感分析:酒店评论舆情系统实战
2026/10/12 11:41:01 网站建设 项目流程

简介:基于Python的网络舆情分析系统毕业设计资源包,面向计算机相关专业在校学生与初级开发者,适合用于毕业设计、课程设计、期末大作业或项目立项演示。资源内含完整可运行的Python源码、中文情感分析模型、酒店评论数据集以及配套说明文档,涵盖CNN与LSTM等典型算法的实现与调用方式,代码带有注释,部署调试后即可直接使用。压缩包共三十五个文件,包括十三个Python脚本、十份文本数据或说明、两个PB模型文件、两个分片数据、两张示例图片及Markdown说明等,整体大小约七十三兆字节,目录结构清晰,便于按模块检索。目前已有二百零四人学习下载,项目经过严格调试,并曾获导师认可与答辩高分,运行稳定,可作为毕业设计或课程设计的可靠参考,也适合在此基础上二次扩展。

1. 基于 Python 的网络舆情分析系统:从酒店评论语料到 CNN/LSTM 情感判别

很多人听到“网络舆情分析系统”,第一反应是爬虫、实时大屏、热词云和舆论走势图。但真正把毕业设计做下来你会发现,这些外围功能再花哨,最核心、最容易被答辩老师追问的,还是“你怎么判断一条文本是正面还是负面”。这个基于 Python 的毕业设计网络舆情分析项目,核心就是一套完整的中文情感分析源码:自带酒店评论数据集,用 CNN 和 LSTM 两种模型做情感分类,并通过 score_report.py 输出可量化评估报告。源码带详细注释,适合计算机相关专业学生做毕设、课设或课程大作业。对新手来说,它能让你绕开“从零搭模型”的弯路,直接看到数据怎么清洗、特征怎么编码、深度学习模型怎么训练和评估;对熟手来说,它的价值在于两个模型并存、评估脚本完整,可以直接替换数据源做二次开发。

2. 先看懂代码结构再动手:chinese_sentimentmaster 的项目骨架与数据流

2.1 拿到压缩包先梳理文件层级:data、model、score_report 各自承担的任务

解压之后,先别急着跑代码。我一般会先花五分钟把目录结构捋一遍,确认哪部分是数据、哪部分是模型、哪部分是评估入口,这样后面报错了也知道去哪查。这个项目的顶层内容主要是 data、model 两个目录,外加 score_report.py、README.md 和 .gitignore,整体结构非常符合“数据 + 模型 + 评估”三段式。

路径类型实际作用对应毕设章节
data/hotel_comment数据目录存放酒店评论语料,通常是有标签的中文文本数据集与实验设计
model/cnn模型目录CNN 情感分类模型的实现或训练产物模型设计与实现
model/lstm模型目录LSTM 情感分类模型的实现或训练产物模型设计与实现
score_report.py评估脚本对训练好的模型做预测并输出准确率、F1 等指标实验与结果分析
README.md说明文档记录环境依赖、运行步骤、注意事项项目运行说明

数据流是单向的:原始评论文本进入预处理流程,分词后转成词向量序列,分别喂给 CNN 和 LSTM 两个模型,训练完成后由 score_report.py 统一在测试集上打分。这个设计的好处是,模型对比实验完全站在同一份数据、同一个评估口径下,不会出现“A 模型用了这份数据、B 模型用了另一份数据”的硬伤。

从毕业设计写作角度来说,这三块正好对应“数据集介绍—算法模型—实验结果”三个章节。你不需要再额外翻资料补结构,代码本身就是最好的素材。我建议你先打开 README.md 看一眼有没有写死的依赖版本,再打开 data 目录里的一行样本数据,确认标签格式,最后再打开 score_report.py 看评估入口读的是哪个文件——顺序走一遍,整套代码的脉络就清楚了。

2.2 舆情分析与情感分类的关系:边界决定你要改哪几处

做毕设写绪论的时候,很多同学会把“舆情分析”这个概念写得很大,好像系统能自动抓全网数据并给出舆论研判。实际上,这个项目里真正实现、也最值得写进论文的,是舆情分析链路中最核心的“情感倾向判别”环节。一条完整的网络舆情分析链路通常长这样:数据采集 → 数据清洗 → 文本预处理 → 情感分类 → 结果统计与可视化。这个压缩包覆盖的,是清洗完成后的文本分类部分,并且自带 hotel_comment 语料,所以你不需要联网去爬数据。

“边界清楚”意味着你要知道改哪里。如果你的毕设需要展示自己的数据:常见做法是写一个爬虫脚本,把采集到的评论文本存成和 hotel_comment 相同的格式,然后在预处理环节替换数据路径即可。如果你需要做前端展示:可以在这个分类核心外面套一层 Flask 或 Django,把模型预测结果通过接口返回给页面。模型本身不需要动。最怕的是你一边想换数据、一边想换模型、一边还想改评估标准,三处同时动,出了问题都不知道该查哪。

所以我的建议是:先把这个项目默认的酒店评论数据完整跑一遍,确认模型能训练、报告能生成,再决定是否加入爬虫和 Web 展示。默认流程跑通,说明代码本身没有硬伤,后续修改才有参照基线。

2.3 环境安装:先固定 Python 版本再装依赖,顺序不要乱

深度学习项目最典型的环境问题,就是 TensorFlow 和 Python 版本打架。这个项目的模型目录是 cnn 和 lstm,运行核心依赖大概率是 TensorFlow + Keras;中文预处理需要 jieba;评估部分需要 scikit-learn。一种稳妥的常见做法是,用 Python 3.8 配合 TensorFlow 2.10 左右版本,这个组合在 Windows 和 Linux 下都比较稳定。

# 推荐用虚拟环境隔离,避免污染机器上其他 Python 项目 conda create -n sentiment python=3.8 conda activate sentiment # 如果 README 里给了 requirements.txt,优先用文件安装;没有则按下面装 pip install tensorflow==2.10.0 pip install keras==2.10.0 pip install jieba scikit-learn pandas numpy

说明一下版本选择逻辑:Python 3.8 对 TensorFlow 2.10 的支持最成熟,安装后基本不会出现“找不到 DLL”或“ABI 不兼容”这类问题。jieba 负责中文分词,scikit-learn 负责生成评估指标。pandas 和 numpy 是数据处理的基本依赖。装完依赖后,先跑一条最小验证命令,确认 TensorFlow 能正常加载:

python -c "import tensorflow as tf; print(tf.__version__)"

如果你看到的是类似2.10.0的版本号,说明环境没问题。如果这里报错,后面训练、评估全都跑不起来,所以这一条值得先做。

提示:如果 README.md 或 requirements.txt 里写定了精确版本,以文件为准,不要盲目装最新版。深度学习框架的大版本升级通常意味着 API 变动。

3. 怎么把原始评论变成模型输入:文本预处理、词向量与数据集划分

3.1 原始评论格式判断、去噪与分词

打开 data/hotel_comment 之后,第一步是确认原始文本的格式。常见的酒店评论情感数据集有两种组织形式:一种是每一行一条评论,文件开头用特定标记注明正负样本;另一种是 CSV 或表格文件,包含评论文本和标签列。你要做的第一件事,是把样本读出来打印前几行,确认分隔符和编码方式,再写预处理函数。下面的代码是常用处理手法,把数字噪声去掉、压缩空白、再用 jieba 分词。

import re import jieba def clean_text(raw_line: str) -> str: """ 清洗单条评论并完成分词。 注意:不要在这里把所有停用词删光,因为“但是”“不太”等词对情感判别很关键。 """ text = re.sub(r'\d+', '', raw_line) # 去掉评论里的数字噪声 text = re.sub(r'\s+', ' ', text).strip() # 压缩多余空白 words = [w for w in jieba.cut(text) if w.strip()] return ' '.join(words) # 示例:单条评论清洗后的效果 sample = "酒店位置很好,但是隔音效果太差,晚上吵得睡不着" print(clean_text(sample))

这段代码的核心逻辑是:先通过正则表达式去除纯数字,避免模型把“2023”这种无关字符当成特征;然后用 jieba 按中文词典切词;“位置 很好 但是 隔音 效果 太差 晚上 吵得 睡不着”这种形式就是模型的输入了。我要特别提醒一点:情感分类场景下不要一刀切删除所有停用词。像“但是”“不太”“很”这些词本身承载着转折和程度信息,删掉之后“虽然环境好但服务差”这类句子会丢失关键语义。

3.2 构建词典与序列化:padding 到 max_len 为什么是 50

分词之后,文本还是变长字符串,深度学习模型吃不了。常见做法是用 Tokenizer 把每个词映射成整数 ID,再把每条评论 padding 成相同长度。这里有两个核心参数:VOCAB_SIZE 决定模型记住多少词,MAX_LEN 决定每条评论保留多长。

from tensorflow.keras.preprocessing.text import Tokenizer from tensorflow.keras.preprocessing.sequence import pad_sequences MAX_LEN = 50 VOCAB_SIZE = 8000 # num_words 限制词典规模,oov_token 把未登录词统一映射为 <UNK> tokenizer = Tokenizer(num_words=VOCAB_SIZE, lower=False, oov_token='<UNK>') tokenizer.fit_on_texts(train_texts) train_seq = pad_sequences( tokenizer.texts_to_sequences(train_texts), maxlen=MAX_LEN, padding='post', # 超过长度时从尾部截断 truncating='post' ) test_seq = pad_sequences( tokenizer.texts_to_sequences(test_texts), maxlen=MAX_LEN, padding='post', truncating='post' ) print("训练集张量形状:", train_seq.shape) # 期望看到 (样本数, 50)

参数选择方面,50 这个长度对酒店评论来说是够用的,绝大多数中文短评论在 30 个字以内;即使遇到长评,也不需要把 MAX_LEN 拉满到 200,因为多出来的大量 padding 只会增加计算量。VOCAB_SIZE 设为 8000 左右,是考虑了 jieba 分词后常见词的规模,模型不需要记住每一个低频词。padding='post' 表示在句子后面补零,truncating='post' 表示从尾部截断,这两项是情感分类任务里的主流配置。

参数常用取值范围调大后的影响调小后的影响
MAX_LEN30~100保留更多上下文,但计算量增大可能丢失尾部关键信息
VOCAB_SIZE5000~20000覆盖更多低频词,但参数变多未登录词比例上升
embedding_dim64~300词向量表达更细腻,训练更慢特征表达不足

3.3 数据集划分不要用默认 shuffle 盲拆:stratify 参数很重要

不少初学者习惯直接train_test_split一把梭,结果就是正面样本和负面样本在不同集合里的比例完全失衡。比如原数据里 80% 是正面评论,你随机拆完,可能测试集里正面占 90%,模型什么都不学也能在测试集上拿高分,但这毫无意义。正确做法是在切分时指定 stratify,让训练集和验证集保持和原始数据一致的类别比例。

from sklearn.model_selection import train_test_split # test_size=0.2 表示把 20% 的数据留作测试集 train_data, val_data, train_label, val_label = train_test_split( train_seq, labels, test_size=0.2, random_state=42, stratify=labels )

其中 random_state=42 是固定随机种子,保证每次运行切分结果一致,方便复现实验。stratify=labels 会按照标签分布进行分层抽样,这是文本分类任务里最容易忽略、也最影响实验结果可信度的一步。如果你后面要用爬虫采集自己的舆情数据,原始数据可能更不均衡,比如负面评论只占 5%,这时候还要考虑用 class_weight 给少数类别加权,否则模型会倾向把所有样本都预测为多数类,后面第 5 章我会专门讲这个坑。

4. 模型训练与评估:把 score_report.py 用起来,CNN 和 LSTM 两条路线对比

4.1 为什么选 CNN 和 LSTM:从文本分类的两种特征视角看

这个项目在同一个数据集上实现了 CNN 和 LSTM 两个模型,这是很聪明的毕设设计。它们代表了两种不同的文本特征提取思路。CNN 通过卷积核在词向量序列上滑动,相当于每次看一个固定窗口内的词组合,能捕捉“服务很差”“房间干净”这类局部短语特征,训练速度快,参数少,在普通 CPU 上也能跑完。LSTM 则通过门控机制记住序列中的历史信息,更适合捕捉“虽然位置好,但是隔音差”这类前后对照的长距离依赖,缺点是训练慢,数据量不足时容易过拟合。

对比维度CNNLSTM
特征提取方式卷积核抓取局部 n-gram 特征循环结构建模序列依赖
训练速度快,CPU 可接受慢,建议 GPU 或缩短序列
参数量较少较多
适合场景短文本、关键词主导的情感长文本、转折与递进关系多
答辩印象结构直观,好讲原理“高级”感更强,但解释难度更大

我在看这个资源时最欣赏的一点,就是它保留了这两种模型的对照实验结构。毕业答辩时你可以直接给出结论:在酒店评论这种短文本场景下,CNN 的准确率与 LSTM 接近,但训练时间明显更短,因此实际部署中更倾向于 CNN。这个结论比只做一个模型有说服力得多。

4.2 训练脚本骨架:Embedding + 卷积池化 / LSTM 的简洁实现

如果你需要在源码基础上改模型结构,下面这两个是常见的 Keras 实现骨架。CNN 版本的核心是 Conv1D 加 GlobalMaxPooling1D,把卷积提取到的特征压缩成一个向量:

from tensorflow.keras.models import Sequential from tensorflow.keras.layers import Embedding, Conv1D, GlobalMaxPooling1D, Dense, Dropout def build_cnn(vocab_size: int, max_len: int, embedding_dim: int = 128): model = Sequential([ Embedding(vocab_size, embedding_dim, input_length=max_len), Conv1D(filters=128, kernel_size=3, activation='relu'), GlobalMaxPooling1D(), Dense(64, activation='relu'), Dropout(0.5), Dense(1, activation='sigmoid') ]) model.compile(optimizer='adam', loss='binary_crossentropy', metrics=['accuracy']) return model

这里 kernel_size=3 相当于每次看三个连续词的组合,也就是 trigram 特征;filters=128 表示有 128 个不同的卷积核,每个卷积核学习一种局部模式。GlobalMaxPooling1D 的作用是从卷积结果中挑出每个特征最强的信号,减少参数。Dropout(0.5) 在训练时随机丢弃一半神经元,防止过拟合。LSTM 版本则把卷积池化层替换成 LSTM 层:

from tensorflow.keras.layers import LSTM def build_lstm(vocab_size: int, max_len: int, embedding_dim: int = 128): model = Sequential([ Embedding(vocab_size, embedding_dim, input_length=max_len), LSTM(units=64, dropout=0.3, return_sequences=False), Dense(32, activation='relu'), Dropout(0.5), Dense(1, activation='sigmoid') ]) model.compile(optimizer='adam', loss='binary_crossentropy', metrics=['accuracy']) return model

LSTM 的 units=64 表示隐状态维度为 64,这个量级对情感分类任务足够了,盲目加大到 256 并不会带来明显提升,反而会让训练时间成倍增加。两个模型都使用 sigmoid 输出加 binary_crossentropy 损失,适用于正负二分类。如果你的数据是“正面/中性/负面”三分类,需要把最后一层改成 Dense(3, activation='softmax'),损失函数换成 categorical_crossentropy。

4.3 读懂 score_report.py 的评估输出:准确率不是唯一指标

score_report.py 是这个资源里最实用的文件。它会把测试集上的预测结果和真实标签做对比,输出一组评估指标。常见逻辑类似下面的代码:

from sklearn.metrics import classification_report, accuracy_score # pred 是模型在测试集上的概率预测,>0.5 判为正面 pred_proba = model.predict(test_seq) pred = (pred_proba > 0.5).astype(int) print(classification_report(test_label, pred, target_names=['negative', 'positive']))

输出会包含每个类别的 precision、recall、f1-score 以及总体 accuracy。很多同学只看 accuracy,这是不够的。在舆情分析场景里,如果负面评论被误判为正面,那系统就失去了预警价值,这时候 precision 和 recall 能告诉你问题出在哪。precision 是“模型判为负面的样本里,有多少真的是负面”;recall 是“所有真实负面样本里,模型找回了多少”。一个高准确率但低负面 recall 的模型,在舆情监控里是危险的。

指标含义毕业答辩时怎么说
accuracy全部预测中正确的比例模型整体判断水平
precision预测为某类的样本中实际属于该类的比例误报率控制能力
recall实际为该类的样本被正确找出的比例漏报率控制能力
F1-scoreprecision 与 recall 的调和平均综合平衡指标

训练参数方面,常用设置是 epochs 5~10、batch_size 32、学习率默认 1e-3。数据集不大的情况下,epochs 超过 10 后验证集指标不会再明显提升,反而可能过拟合。如果你发现 loss 曲线剧烈震荡,把学习率降到 5e-4 再看。训练完成后,模型权重一般会保存到 model/cnn、model/lstm 目录,score_report.py 再把这些权重加载回来做测试集评估。

5. 常见问题排查与避坑:从环境搭建到中文数据预处理

5.1 TensorFlow 版本与 Python 版本不匹配

现象:安装完依赖后运行代码,报错ModuleNotFoundError: No module named 'tensorflow.contrib',或者提示找不到某个 keras 接口。原因:TensorFlow 2.x 已经把大量 1.x 的接口移除了,网上很多教程代码是老的,直接在 2.x 下跑必然报错。解决:固定使用 TensorFlow 2.10 搭配 Python 3.8;如果代码里用了tf.contrib这类历史接口,需要把它替换成新版 API。这是环境类问题里最普遍的一个。

5.2 读取中文评论时 UnicodeDecodeError

现象:用 pandas 或 open 读取 data/hotel_comment 时,报错UnicodeDecodeError: 'gbk' codec can't decode byte。原因:Windows 下默认编码是 GBK,而数据文件大概率是 UTF-8。解决:读取时显式指定编码encoding='utf-8'。如果你在 Windows 上手动编辑过数据文件并另存为 GBK,那就要反过来。我的习惯是统一把数据文件保存为 UTF-8,并且在所有读取入口都写死编码参数。

with open('data/hotel_comment/raw_data.txt', 'r', encoding='utf-8') as f: lines = f.readlines()

5.3 训练集准确率很高,但测试集或新数据预测一边倒

现象:训练时准确率冲到 95% 以上,测试集也好看,但你抽几条真实的新评论去预测,几乎全部判成同一个类别。原因:一是类别严重不均衡,二是数据划分时没有做 stratify,或者原始数据在切分前已经被混洗,导致同一个来源的样本同时出现在训练集和测试集。解决:按第 3 章的写法使用 stratify 重新划分,并且把验证集单独留出一部分,不要参与训练。如果新数据里负面样本极少,考虑用 class_weight 给少数类加权,或者用欠采样/过采样平衡数据。

5.4 CPU 机器上 LSTM 训练慢得离谱

现象:LSTM 一个 epoch 要跑十几分钟,CNN 几分钟就结束。原因:LSTM 是循环结构,必须按时间步展开,计算量远大于卷积。解决:先把 MAX_LEN 从 100 以上降到 50,embedding_dim 从 256 降到 128,batch_size 设 32;如果还慢,就先用 CNN 验证整体流程,最后再训练 LSTM 作为对比实验。这是很现实的时间管理技巧,毕设不一定有那么多时间等模型跑完。

5.5 分出来的词大量变成 \uFEFF 或异常字符

现象:打印分词结果时,第一个词带\ufeff前缀,或者出现大量\u3000空格。原因:BOM 头没有被正确去除,中文全角空格混在文本里。解决:读文件时用utf-8-sig编码,它会自动剥离 BOM;清洗函数里加上text.replace('\u3000', '')。

def clean_text(raw_line: str) -> str: text = raw_line.replace('\ufeff', '').replace('\u3000', '') # 后续分词逻辑保持不变

这类问题看起来小,但会影响词典构建质量和最终准确率。如果你发现同一个词被分成两个 ID,先检查是不是不可见字符闹的。

6. 给毕业设计答辩加分的验证技巧:用混淆矩阵定位误判方向

如果你想让答辩老师觉得你真的吃透了这个项目,不要只贴一个准确率数字。建议在 score_report.py 之外,额外生成一张混淆矩阵图,从误判方向去分析模型短板。这比“准确率 92%”这种一句话结论有分量得多。

import matplotlib.pyplot as plt from sklearn.metrics import confusion_matrix cm = confusion_matrix(test_label, pred) # 行是真实标签,列是预测标签;对角线是预测正确的数量 print(cm) # 可视化展示,答辩 PPT 里可以直接用 plt.figure(figsize=(5, 4)) plt.imshow(cm, cmap='Blues') plt.colorbar() plt.xticks([0, 1], ['negative', 'positive']) plt.yticks([0, 1], ['negative', 'positive']) plt.xlabel('predicted label') plt.ylabel('true label') plt.show()

在舆情分析场景里,最要命的是“把负面误判为正面”。如果混淆矩阵显示右下角数值明显偏大,说明模型对负面文本不敏感,很可能与训练样本不均衡有关。你可以针对这个问题,在论文里给出具体改进方案,比如补充更多负面样本,或者调整分类阈值。这个分析思路本身就是毕业设计“实验分析”章节最好的素材。

这个资源给出的数据是酒店评论,但换到你自己要分析的网络舆情场景,操作路径是一样的:把新语料整理成“文本 + 标签”的格式,替换 data/hotel_comment 的数据文件,重跑预处理和训练脚本,然后再看 score_report.py 的评估结果。如果只做无监督的舆情趋势分析,也可以直接用训练好的模型对未标注文本做预测,统计正面占比随时间的变化。

我第一次做类似项目时,只把训练集上的准确率截图放进报告,答辩现场被老师用几条测试数据当场问住了。从那以后,我每次都强制走一遍完整流程:留出独立测试集、生成混淆矩阵、打印 classification_report,确认每个类别的 precision 和 recall 都有交代,才敢说模型有效。希望帮到你。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询