
简介本资源为基于Python与深度学习的中文情感分析系统毕业设计完整项目包面向计算机相关专业需要完成毕业设计的学生及希望学习Flask Web开发与文本分类的开发者。项目采用Flask框架搭配MySQL数据库实现用户注册登录、后台数据统计首页以及文本情感分析等核心模块登录注册环节包含密码重复确认与手机号绑定后台首页通过柱状图与饼图多维度汇总数据文本分析模块可将输入文本划分为正面或负面评价。压缩包共378个文件涵盖52个js、18个css、12个html等前端资源20个py后端脚本以及gif、png、jpg等界面截图与演示素材另含sql数据库文件、npy与pkl模型数据、pb模型文件及mp4演示视频整体约97.54MB。目前已有217人学习下载适合作为毕业设计参考模板帮助读者快速理解情感分析系统的整体架构、前后端交互流程与模型调用方式。1. 中文情感分析系统从数据清洗到Flask接口的完整落地路径电商评论、课程评价、客服对话里藏着大量中文短文本人工逐条判断正负面既慢又容易疲劳。基于Python和深度学习的中文情感分析系统核心目标就是把这些非结构化文本自动映射为「正面/负面」标签再用Flask暴露成HTTP接口让前端页面或第三方系统直接调用。这个标题对应的不是单一脚本而是一条完整链路中文分词与清洗、词向量或预训练表示、深度模型训练、模型持久化、Flask路由封装、数据库落库。适合正在做计算机毕业设计、需要交付可运行系统的同学也适合想快速搭一个文本分类原型的开发者。下面按「先跑通再调优」的顺序拆开讲。2. 中文情感分析的技术选型为什么是深度学习而不是传统机器学习2.1 中文短文本的三个特殊难点中文和英文在情感分析上的差异不是简单换个分词工具就能抹平的。第一中文没有天然空格分隔分词粒度直接影响特征质量「不喜欢」切成「不/喜欢」和「不喜欢」语义完全相反。第二中文短文本普遍存在省略主语、反讽、网络新词的现象比如「这波操作我给满分」表面正面实则负面传统词袋模型几乎无法处理。第三情感极性往往由少数关键词决定但关键词可能出现在任意位置长距离依赖需要模型有全局视野。传统机器学习方案TF-IDF 朴素贝叶斯 / SVM在标注数据充足、文本较长的场景下仍有性价比但在中文短文本上特征稀疏和语序丢失是两个硬伤。深度学习方案通过词嵌入和序列建模能把「不」和「喜欢」的交互关系学到这是选它的核心理由。2.2 三条主流技术路线的取舍当前做中文情感分析常见做法有三条路线代表模型数据需求训练成本适用场景词向量 循环网络Word2Vec BiLSTM中等中等毕业设计、教学演示预训练微调BERT-base-chinese较少较高追求精度、有GPU轻量卷积TextCNN中等低快速原型、CPU环境我一般会建议毕业设计场景选 BiLSTM Attention 或 TextCNN原因是训练可在普通笔记本CPU上完成代码量可控答辩时能讲清楚每一层在做什么。BERT 精度更高但显存和训练时间对没有GPU的同学不友好而且微调过程容易被追问细节。如果时间充裕且实验室有显卡用 BERT 做对比实验是加分项。2.3 环境搭建的最小命令集先确认Python版本建议3.8到3.10太新的版本某些深度学习库轮子还没跟上。python --version pip install torch numpy pandas jieba flask flask-sqlalchemy scikit-learn如果要用BERT再加pip install transformers逻辑说明torch是深度学习框架jieba负责中文分词flask和flask-sqlalchemy负责Web层和数据库scikit-learn用于划分数据集和算指标。参数说明不需要指定版本号时pip会拉最新但生产环境建议用requirements.txt锁版本避免换机器后跑不起来。提示Windows下如果torch安装报错先去PyTorch官网用它的命令生成器选对应CUDA版本没有GPU就选CPU版。3. 数据准备与中文预处理把脏文本变成模型能吃的格式3.1 数据集来源与标注格式毕业设计常用的中文情感数据集有两类一是公开的酒店评论、商品评论数据集通常已经标好正负面二是自己爬取后人工标注。不管哪种统一成两列text和labellabel用0/1表示负面/正面。数据量建议至少5000条低于这个数模型容易过拟合答辩时被问泛化能力会很难受。import pandas as pd df pd.read_csv(sentiment_data.csv, encodingutf-8) df df.dropna(subset[text, label]) df df[df[text].str.len() 3] print(df[label].value_counts())逻辑说明先去掉空文本和过短文本再检查标签分布。参数说明str.len() 3这个阈值不是固定的中文短文本如果只有两三个字情感信息往往不完整但也要根据实际数据调整别一刀切掉有效样本。3.2 中文分词与停用词处理import jieba import re stopwords set(open(stopwords.txt, encodingutf-8).read().split()) def clean_text(text): text re.sub(r[^\u4e00-\u9fa5a-zA-Z0-9], , text) words jieba.lcut(text) words [w for w in words if w not in stopwords and len(w) 1] return .join(words) df[clean] df[text].apply(clean_text)逻辑说明正则只保留中文、字母和数字去掉标点和特殊符号jieba分词后过滤停用词和单字。参数说明len(w) 1会过滤掉「不」「很」这类单字但「不」在情感分析里恰恰是关键否定词所以更稳妥的做法是保留否定词白名单而不是无脑过滤单字。注意停用词表不要直接用网上的通用表里面往往包含「不」「没」等情感关键否定词用之前手动检查一遍这是血泪经验。3.3 构建词表与序列填充from collections import Counter from torch.utils.data import Dataset import torch all_words [w for text in df[clean] for w in text.split()] vocab {w: i2 for i, (w, _) in enumerate(Counter(all_words).most_common(20000))} vocab[PAD] 0 vocab[UNK] 1 MAX_LEN 64 def encode(text): ids [vocab.get(w, 1) for w in text.split()][:MAX_LEN] ids [0] * (MAX_LEN - len(ids)) return ids逻辑说明按词频取前20000个词建词表0给填充1给未知词。参数说明MAX_LEN64 覆盖大多数中文评论长度太长会增加计算量太短会截断信息可以用df[clean].str.split().str.len().describe()看分位数再定。4. 深度学习模型搭建与训练BiLSTM加Attention的最小实现4.1 模型结构设计import torch.nn as nn class SentimentModel(nn.Module): def __init__(self, vocab_size, embed_dim128, hidden_dim128): super().__init__() self.embedding nn.Embedding(vocab_size, embed_dim, padding_idx0) self.lstm nn.LSTM(embed_dim, hidden_dim, batch_firstTrue, bidirectionalTrue) self.attention nn.Linear(hidden_dim * 2, 1) self.fc nn.Linear(hidden_dim * 2, 2) def forward(self, x): emb self.embedding(x) out, _ self.lstm(emb) attn torch.softmax(self.attention(out), dim1) context torch.sum(attn * out, dim1) return self.fc(context)逻辑说明Embedding把词ID转成向量BiLSTM双向建模上下文Attention给每个时间步算权重后加权求和最后全连接分类。参数说明embed_dim128 和 hidden_dim128 是常见起点数据量小可以降到64数据量大可以升到256。padding_idx0 保证填充位不参与梯度更新。4.2 训练循环与关键参数from torch.utils.data import DataLoader from sklearn.model_selection import train_test_split train_df, val_df train_test_split(df, test_size0.2, random_state42) class SentimentDataset(Dataset): def __init__(self, dataframe): self.texts [torch.tensor(encode(t)) for t in dataframe[clean]] self.labels [torch.tensor(l) for l in dataframe[label]] def __len__(self): return len(self.labels) def __getitem__(self, idx): return self.texts[idx], self.labels[idx] train_loader DataLoader(SentimentDataset(train_df), batch_size32, shuffleTrue) val_loader DataLoader(SentimentDataset(val_df), batch_size32) model SentimentModel(len(vocab)) optimizer torch.optim.Adam(model.parameters(), lr1e-3) criterion nn.CrossEntropyLoss() for epoch in range(10): model.train() for x, y in train_loader: optimizer.zero_grad() loss criterion(model(x), y) loss.backward() optimizer.step()逻辑说明标准训练循环每轮打乱训练集验证集不打乱。参数说明batch_size32 是显存和梯度稳定性的折中lr1e-3 是Adam的常用起点epoch10 需要看验证集loss是否还在下降早停比固定轮数更靠谱。4.3 模型保存与加载torch.save({model: model.state_dict(), vocab: vocab}, sentiment.pth) checkpoint torch.load(sentiment.pth, map_locationcpu) model.load_state_dict(checkpoint[model]) vocab checkpoint[vocab]逻辑说明把词表和权重一起存避免推理时词表对不上。参数说明map_locationcpu 保证在无GPU机器上也能加载部署到服务器时尤其重要。5. Flask接口封装与数据库落库让模型变成可调用的服务5.1 Flask路由与模型加载from flask import Flask, request, jsonify import torch app Flask(__name__) checkpoint torch.load(sentiment.pth, map_locationcpu) model SentimentModel(len(checkpoint[vocab])) model.load_state_dict(checkpoint[model]) model.eval() vocab checkpoint[vocab] app.route(/predict, methods[POST]) def predict(): text request.json.get(text, ) if not text: return jsonify({error: empty text}), 400 ids torch.tensor([encode(text)]) with torch.no_grad(): logits model(ids) pred torch.argmax(logits, dim1).item() return jsonify({label: pred, text: text})逻辑说明启动时加载一次模型请求时只做前向推理。参数说明model.eval()关闭dropouttorch.no_grad()省显存。request.json要求客户端发JSONContent-Type设为application/json。5.2 数据库表设计与写入from flask_sqlalchemy import SQLAlchemy app.config[SQLALCHEMY_DATABASE_URI] sqlite:///sentiment.db db SQLAlchemy(app) class Record(db.Model): id db.Column(db.Integer, primary_keyTrue) text db.Column(db.String(500)) label db.Column(db.Integer) created_at db.Column(db.DateTime, defaultdb.func.now()) with app.app_context(): db.create_all()逻辑说明每条预测结果落库方便后续做统计和回溯。参数说明SQLite适合毕业设计演示生产环境换成MySQL只需改URI。String(500) 对超长文本会截断需要根据业务调整。5.3 前端页面调用示例fetch(/predict, { method: POST, headers: {Content-Type: application/json}, body: JSON.stringify({text: 这个课程讲得很清楚}) }) .then(res res.json()) .then(data console.log(data.label));逻辑说明前端用fetch发POST请求拿到label后渲染结果。参数说明headers必须带Content-Type否则Flask的request.json会返回None。6. 避坑与排查中文情感分析系统最常见的五个翻车点现象一训练loss下降但验证准确率不动。原因通常是数据泄露或标签错位比如清洗时把label列也做了处理或者train_test_split之前就做了全局词表统计。解决先打印几条样本和标签对照确认encode后的ID和label一一对应词表只在训练集上统计。现象二推理时预测结果全是同一类。原因可能是模型没加载成功或者词表对不上导致所有词都变成UNK。解决加载后先拿训练集里的句子测一遍如果训练集也预测错说明保存加载环节有问题如果训练集对但新句子错说明过拟合或词表覆盖不够。现象三Flask启动后请求超时。原因通常是模型在每次请求时重复加载或者torch线程数设置不合理。解决模型在应用启动时加载一次全局复用在CPU环境下设置torch.set_num_threads(1)避免多线程争抢。现象四中文分词后关键词被切碎。比如「性价比高」被切成「性/价/比/高」模型学不到整体语义。解决加入自定义词典jieba.load_userdict(userdict.txt)把领域高频词提前加进去这是最容易被忽略但效果最明显的一步。现象五数据库写入报编码错误。原因多是SQLite默认编码和中文不兼容或者字段长度不够。解决连接串加?charsetutf8mb4字段用Text类型替代String写入前统一encode成utf-8。7. 进阶技巧用置信度阈值和错误分析把系统从能用推到好用模型跑通只是起点真正让系统在答辩或实际使用中站得住靠的是对错误样本的处理。我一般会在推理接口里加一个置信度输出把softmax后的最大概率一并返回probs torch.softmax(logits, dim1) conf, pred torch.max(probs, dim1) return jsonify({label: pred.item(), confidence: round(conf.item(), 4)})逻辑说明置信度低于0.6的样本单独标记人工复核后决定是否加入训练集。参数说明0.6这个阈值不是固定的可以用验证集画一条置信度-准确率曲线找到准确率骤降的拐点。更进一步的做法是错误分析。把验证集里预测错的样本导出来按错误类型分组否定词漏判、反讽误判、领域词不认识。每组挑10条看往往能发现数据清洗或词表的问题。比如「不推荐」被预测成正面大概率是「不」被停用词表过滤了「价格美丽」被预测成负面说明模型没见过这种网络表达需要补充训练数据。错误类型典型样本优先处理方式否定词漏判不推荐、没效果检查停用词表保留否定词反讽误判这质量真是绝了补充反讽标注数据领域词不认识续航拉胯加自定义词典 增量训练标签噪声明显正面标成负面人工复核清洗标签部署层面如果要在服务器上长期跑建议用gunicorn加nginxFlask自带的开发服务器只适合本地调试。启动命令gunicorn -w 2 -b 0.0.0.0:5000 app:app逻辑说明-w 2 表示两个worker进程CPU核多可以加。参数说明模型加载放在app模块顶层gunicorn的preload模式可以让每个worker共享模型内存避免重复加载。我自己踩过最深的坑是花了两天调模型结构最后发现准确率上不去的原因是停用词表把「不」过滤了。后来养成习惯每次清洗完先手动看20条样本比看loss曲线管用得多。希望帮到你。本文还有配套的精品资源点击获取