每年到毕业季,总有不少同学围着“选题”打转。如果你正在电商、数据或者 Web 开发方向徘徊,“基于 Django 和机器学习的电商评论情感分析”是一个性价比很高的选择。它不是一个只调库的玩具项目,而是一个从数据处理、模型训练到 Web 展示的完整闭环,能一次性讲清楚后端框架、机器学习算法和自然语言处理三件事。
这个题目好在哪里?适合计算机专业、软件工程、电子商务和数据科学相关方向的学生拿来做毕业设计。哪怕你是刚接触 Python 不久的人,只要愿意按步骤把整套流程走一遍,也能在答辩现场拿出一个能看、能点、能出结果的作品。不过要注意,网上类似的源码很多,真正拉开差距的,是你对每个环节“为什么这么做”的理解深度。这篇就结合我实际开发时踩过的坑,把整个项目从设计到实现拆开讲清楚。
1. 项目拆解:光看标题你可能忽略了这些点
1.1 这一个题目里藏了三个技术栈
很多人第一眼看到“基于 Django 和机器学习的电商评论情感分析”,觉得它只是一个普通网站加一个预测按钮。实际上,题目背后藏着三个相对独立又互相衔接的技术栈:
第一是 Web 开发。Django 负责搭建用户界面、处理表单提交、展示预测结果,还要管理数据记录。这部分考察的是 MTV 架构、路由、模板和 ORM 操作,属于后端开发的基本功。
第二是机器学习。你要把评论文本变成模型能理解的数字,训练一个情感分类器,让它能判断“这个手机拍照很清晰”是正向评价,“快递太慢客服不回复”是负向评价。这里涉及文本分类、特征提取、模型评估等核心概念。
第三是自然语言处理。中文分词、停用词过滤、向量化表示,这些都是 NLP 的基础操作。跟英文不同,中文没有天然的空格分词,所以需要额外处理,这也是很多同学第一次接触时会卡住的地方。
这三个部分单独拿出来都可以展开做一个小课题,凑在一起就是一个完整的系统。毕业设计最讲究的就是技术覆盖面,这个题目天然就能让答辩老师看到你的工作量。
1.2 电商评论情感分析到底在解决什么问题
从业务角度看,电商平台上的评论量非常大,靠人工去读不现实。商家想知道用户对某个产品整体是夸还是骂,运营想找出最近负面口碑集中在哪里,这些需求背后都指向同一个技术任务——情感分类。
情感分析本质上是文本分类问题。最简单的方案是二分类,只区分正向和负向;也可以做三分类,把中性评价单独分出来。毕业设计场景下,我建议做三分类,因为电商评论里大量存在“一般般”“还行吧”这种没有强烈倾向的文本,如果强制分成正负两类,模型效果会很难看,答辩时不好解释。
这个任务的技术难度适中,但又足够有代表性:它需要你处理非结构化文本,需要做特征工程,需要训练模型,还要把模型包装成线上可用的服务。整套流程恰好对应企业里一个最小可用的 NLP 应用。把这一套走通,以后看其他分类任务,比如垃圾邮件过滤、新闻分类、舆情监控,思路几乎是通用的。
2. 技术选型与整体方案设计
2.1 为什么是 Django 而不是 Flask 或 FastAPI
毕业设计选框架,不要只看流行度,要看它跟题目匹配不匹配。Django 是一个重框架,自带 ORM、Admin 后台、模板系统、表单处理和用户认证,意味着你不太需要再去拼第三方库。
举个例子,Flask 很轻量,但要做用户登录、数据建模、后台管理,你得自己挑一堆扩展拼起来。FastAPI 性能好、写接口舒服,但在模板渲染和 Admin 后台方面,可参考的毕业设计案例相对少。Django 生成项目时自动帮你建好了 admin 站点,训练好的评论数据可以直接在里面管理,答辩演示时打开后台给老师看,立刻多一个亮点。
Django 的另一个优势是 MTV 架构清晰。models.py 定义数据结构,views.py 写业务逻辑,templates 放页面,你可以在答辩 PPT 里画一张分层图,老师一看就懂。同时,Django 的 ORM 在日常操作中非常顺手,比如筛选负面评论,只需要CommentRecord.objects.filter(sentiment='negative'),要删除记录就调用.delete()。对应到网上那些“django执行查询-删除对象”的搜索热词,核心就是先取 QuerySet 再操作,这个点面试也常问。
不过要提醒一句,Django 自带数据库是 SQLite,适合开发和学习。如果数据量特别大,建议换成 MySQL,在 settings.py 里改数据库配置并安装驱动就行。毕业设计直接用 SQLite 完全够用,别在这上面花太多时间折腾。
2.2 情感分析算法怎么选:从传统模型到深度学习
我见过不少同学一上来就想用 BERT,觉得深度学习更有排面。但真到训练的时候,数据集只有两三千条,显卡也跟不上,光跑一个 epoch 就要等半天。对于毕业设计项目,如果目标是拿到一个稳定可解释的结果,传统机器学习模型是更务实的选择。
推荐优先尝试这三个模型:
- 朴素贝叶斯(MultinomialNB):实现简单,收敛快,小样本下表现稳定,是文本分类的经典 baseline。
- 逻辑回归(LogisticRegression):可解释性最强,能直接输出每个特征对结果的影响权重,答辩时可以说清楚“哪些词把评论推向正面”。
- 线性 SVM(LinearSVC):分类边界更明确,在特征维度较高时精度通常比朴素贝叶斯好一点,但调参要稍微花点时间。
我的建议是,先用逻辑回归跑通全流程,因为它训练速度和准确率平衡得很好。等流程稳定了,再对比朴素贝叶斯和线性 SVM,把三者的准确率、F1 值放进论文的对比表格里,比一开始就追求复杂模型更有说服力。
至于 LSTM、BERT 这些深度学习方法,可以放在“后续改进与展望”章节里写。这样既展示了视野,又不会因为环境配置问题拖垮你的开发计划。如果你确实想尝试,建议用 Hugging Face 上的中文预训练模型做微调,至少需要 1 万条以上标注数据才看得出效果,否则很容易过拟合。
2.3 数据从哪来:公开数据集与合规采集
数据是整个项目的地基。最省事的方式是使用公开的电商评论语料,很多高校和开源社区都提供带情感标签的中文评论数据。使用公开数据的三个好处:标注质量有保障、可以省去大量人工标注时间、论文里可以直接引用对比。
如果你不想用现成数据,也可以自己写爬虫去电商平台采集评论。但这里必须提醒:只能用于个人学习和研究,要遵守网站的访问规则,控制请求频率,不要批量抓取非公开数据。更不要碰那些跟攻击、破解相关的灰色方式,这个圈子千万别沾。
数据规模上,三分类任务建议不少于 5000 条,最好能到 1 万条。数据越少,模型方差越大,随便一条噪声都会显著影响准确率。另外,数据集要做基本平衡,让正向、中性、负向的比例不要相差太悬殊。如果实际采集到的负向评论很少,会导致模型整体倾向预测正向,看起来准确率不低,实际没什么用。
拿到数据后,按照 8:2 或 7:3 划分训练集和测试集。注意,划分要在预处理之前做,避免测试集信息泄漏到模型训练里。这一点论文里也会重点讲,做了就是加分项。
3. 核心模块实现:从数据清洗到 Django 集成
3.1 环境准备与 Django 工程搭建
统一环境是少踩坑的第一要素。我建议用 Anaconda 创建独立虚拟环境,Python 版本选 3.9 或 3.10,Django 用 4.x。版本太新有时会跟某些依赖库冲突,没什么必要去追新。
安装依赖推荐一次装齐:
pip install django pandas numpy scikit-learn jieba joblib matplotlib然后创建项目和 app:
django-admin startproject sentiment_project cd sentiment_project python manage.py startapp review把review加到settings.py的INSTALLED_APPS里,不然 Django 不认这个 app。接着配置时区:
LANGUAGE_CODE = 'zh-hans' TIME_ZONE = 'Asia/Shanghai' USE_TZ = True到这里一个最小可运行的 Django 项目就成了。你可以先跑python manage.py runserver,浏览器打开 127.0.0.1:8000 看到默认页面,再往里面加业务代码。第一次做 Django 的同学尤其要养成“小步快跑”的习惯,每加一点功能就跑一下,别指望一次性写完再调试。
3.2 文本清洗与中文分词
模型输入的是文本,但文本必须转成数字才能训练。转换之前,得先把原始评论洗干净。这里每一步都要想清楚目的:
去除 HTML 标签,因为爬回来的评论里可能残留标签代码;去除 URL,链接对情感判断没有帮助;去除各种符号,让后续分词更干净。另外,评论里的“好评”“五星”这类词,单独出现时情感标记很强,保留即可。
中文分词我用 jieba,它会把“物流很快”切分成“物流 / 很快”。停用词表要去下载一份常见的中文停用词表,网上有很多开源版本。但停用词表不能乱用,我实际踩过一个大坑:有些停用词表把“不”“没”“很”也列进去了,结果“很不满意”被切成了“很 / 满意”,模型直接把负面评论判断成正面,整体准确率掉了 5 个点。
正确的做法是,只删除代词、语气词、连词这些高频无意义词,保留带情感倾向的否定词和程度副词。可以把预处理函数写成下面这样:
import re import jieba def clean_text(text): text = re.sub(r'<.*?>', '', text) text = re.sub(r'http\S+', '', text) text = re.sub(r'[^\u4e00-\u9fa5a-zA-Z0-9]', '', text) return text def cut_text(text, stopwords): words = jieba.lcut(clean_text(text)) words = [w for w in words if w.strip() and w not in stopwords] return ' '.join(words)预处理函数建议单独放在一个preprocess.py里,训练和预测都要调用同一个函数,避免出现“训练时处理了但线上预测时没处理”这种不一致。
3.3 特征工程与模型训练
把分词后的文本变成向量,毕业设计里最常用的就是 TF-IDF。TF 表示词在当前文本里出现得多不多,IDF 表示这个词在整体语料里罕不罕见。两者相乘,既保留了文本内部的信息,又压制了“的”“了”“是”这类在每篇文章里都出现的常见词。
在 scikit-learn 里用 TfidfVectorizer 一行就能完成。训练时先切分数据,再用训练集 fit,然后只 transform 测试集和数据:
from sklearn.model_selection import train_test_split from sklearn.feature_extraction.text import TfidfVectorizer from sklearn.linear_model import LogisticRegression X_train, X_test, y_train, y_test = train_test_split( texts, labels, test_size=0.2, random_state=42, stratify=labels ) vectorizer = TfidfVectorizer(max_features=5000, ngram_range=(1, 2), sublinear_tf=True) X_train_vec = vectorizer.fit_transform(X_train) X_test_vec = vectorizer.transform(X_test) model = LogisticRegression(C=1.0, max_iter=1000, class_weight='balanced') model.fit(X_train_vec, y_train) print(model.score(X_test_vec, y_test))代码里有几个容易被忽视的点。第一,测试集只能调用 transform,不能 fit_transform,否则会把测试集的信息混进词表里。第二,ngram_range=(1, 2)非常值得加,它会把相邻两个词作为一个组合特征,能捕捉“不好”和“不 好”的区别。第三,class_weight='balanced'可以在类别不均衡时自动调整权重。
训练完成后,模型要保存到磁盘,否则 Django 每启动一次就得重新训练一遍。用 joblib:
import joblib joblib.dump(vectorizer, 'vectorizer.pkl') joblib.dump(model, 'model.pkl')3.4 模型评估与可视化
准确率只是一个最基础的指标,在类别不平衡时会造成误导。我建议至少输出 classification_report,看每个类别的精确率、召回率和 F1 值。精确率是“模型说是正面的里面有多少真的是正面”,召回率是“真正的正面里有多少被找了出来”,两者都重要。
还可以画一个混淆矩阵热力图,能直观看出模型把中性评论误判成了哪一边。用 matplotlib 和 seaborn,几十行代码就能完成,生成的图直接放论文里,比大段文字说明更清楚。
评估通过后再考虑调参。下面章节会讲到具体参数。这里先提一个策略:不要在测试集上反复调参,否则会把你对测试集的“记忆”当成真实效果。更规范的做法是再切出一部分验证集,或者直接用交叉验证,最后再用测试集做一次最终评估。
3.5 将模型集成到 Django 页面
模型训练好了,接下来就是把它塞进 Django 系统里。最容易犯的错是在 views.py 函数内部加载模型,这样每个请求都会重新读一次磁盘,预测接口会慢到让人怀疑人生。
正确做法是把模型和向量器放到模块顶部,只加载一次:
import joblib from django.shortcuts import render from .preprocess import cut_text model = joblib.load('model.pkl') vectorizer = joblib.load('vectorizer.pkl') def predict_view(request): if request.method == 'POST': comment = request.POST.get('comment', '').strip() if not comment: return render(request, 'index.html', {'error': '请输入评论文本'}) words = cut_text(comment, stopwords) vec = vectorizer.transform([words]) label = model.predict(vec)[0] proba = model.predict_proba(vec)[0] return render(request, 'result.html', { 'comment': comment, 'label': label, 'positive_prob': round(proba[2], 4), 'neutral_prob': round(proba[1], 4), 'negative_prob': round(proba[0], 4), }) return render(request, 'index.html')urls.py 里加一条路由,模板里写一个表单页和一个结果页,项目就跑起来了。如果想把每次预测记录保存到数据库,可以建一个模型记录评论内容、预测结果、概率和时间,顺带还能演示 Django Admin 后台管理数据。
这里推荐一个小技巧:给结果页加一个简单的进度条,按预测概率的百分比显示正负情感强度。这个视觉效果很讨巧,答辩老师录入一条评论,页面立刻出现红色和绿色的进度条,比单纯显示一串文字直观得多。
4. 训练效果与参数调优经验
4.1 如何判断模型效果
不同的数据集规模、类别数量和任务难度下,准确率没有统一标准。但如果你的数据是公开标注语料、三分类任务、训练集 8000 条左右,我可以给你一个参考范围:
- 准确率 0.75 以下:数据清洗或特征工程大概率有问题,也可能是标签标注质量差。
- 0.75 到 0.85:属于正常水平,说明流程跑通,但模型还有提升空间。
- 0.85 到 0.90:相当不错,可以在论文里作为主结果展示。
- 0.90 以上:需要警惕过拟合,重点看一下测试集是否被你手滑放进了训练过程。
二分类任务通常比三分类高 5 个点左右。如果你只想快速出成果,二分类就能用,但论文深度会弱一些。三分类能讲更多的分析和调优故事,所以我更推荐。
不同模型也有差异。我拿一份 1 万条电商评论做过快速实验,朴素贝叶斯准确率大约 0.82,逻辑回归 0.87,线性 SVM 0.86。也就是说,逻辑回归在这类任务上常常是最稳的选择,而且可以通过查看特征权重解释模型。你在自己的数据上可以也跑一个基线对比,放进论文的表格里,比空口说“我的模型准确率很高”更有说服力。
4.2 参数调优的几个关键点
调优不要随机试。先盯两个模块:文本向量化和分类器正则化强度。
TfidfVectorizer 里最重要的参数是 max_features 和 ngram_range。max_features 控制特征总数。设太小,词表覆盖不全;设太大,训练变慢还容易过拟合。5000 到 10000 是一个比较合理的区间。ngram_range 刚才说过,尽量使用 (1, 2),对否定表达很有帮助。
还可以关注 min_df 和 max_df。min_df=5 表示只在少于 5 条评论中出现的词直接丢弃,能过滤掉生僻噪声;max_df=0.8 表示在超过 80% 评论中都出现的词会被忽略,这类词通常没有区分度。
分类器方面,逻辑回归最常调的是 C。C 是正则化强度的倒数,C 越小,正则越强,越不容易过拟合。默认 C=1.0,如果训练集准确率远高于测试集,可以把 C 降到 0.1 试试;如果欠拟合,再适当调大。
想同时调多个参数,用 GridSearchCV:
from sklearn.model_selection import GridSearchCV from sklearn.pipeline import Pipeline pipe = Pipeline([ ('tfidf', TfidfVectorizer()), ('clf', LogisticRegression(max_iter=1000)) ]) params = { 'tfidf__max_features': [3000, 5000, 8000], 'tfidf__ngram_range': [(1, 1), (1, 2)], 'clf__C': [0.1, 1.0, 10.0] } grid = GridSearchCV(pipe, params, cv=5, scoring='f1_macro') grid.fit(X_train, y_train) print(grid.best_params_)用 Pipeline 的好处是能保证交叉验证时向量化和分类器同步更新,不会出现数据泄漏。调优结果应该报告交叉验证均值,而不是单次分割的运气分。
4.3 在论文里怎么呈现这些结果
论文不需要包含所有实验细节,但几个关键点一定要有:数据集来源和规模、数据预处理的规则、模型选择的原因、评估指标的定义、实验结果对比表、混淆矩阵图、以及 Web 系统截图。
一个很有说服力的展示方式是把逻辑回归模型里权重最大的前 20 个正向词和负向词列出来。比如“不错”“很快”“满意”权重高,“差劲”“退货”“客服”权重低。这种特征级分析在答辩现场很容易吸引老师追问,而你能解释清楚,分数自然就上去了。
Web 页面截图也不要随便截。至少要有三张:用户输入评论的页面、预测结果展示页面、历史记录列表页面。如果做了数据可视化图表,比如评论情感分布的饼图,也可以放一张。
5. 毕设开发中的常见问题与排查技巧
5.1 环境与依赖问题
环境问题是最磨人的。常见情况是:在自己电脑跑得好好的,换到另一台电脑就报错。根源是 Python 版本、依赖版本不一致。解决办法是立刻在项目根目录生成一个 requirements.txt:
pip freeze > requirements.txt换环境时执行:
pip install -r requirements.txt另外一个很实际的经验是,虚拟环境独一档,不要把包直接装到系统 Python 里。Anaconda 的 conda 环境就可以很好地隔离不同项目的依赖。
如果你需要请别人帮你远程看问题,最稳妥的方法不是共享屏幕,而是让对方用同样的 Python 版本和 requirements.txt 复现一遍。这样双方环境一致,问题定位起来会快很多。把训练脚本、预处理函数和依赖文件都提交到 git 仓库,比隔着屏幕口头描述更有用。
5.2 中文编码与乱码
中文编码是新手必踩的坑。用 pandas 读取 CSV 时,如果文件是用 Excel 另存为 CSV 的,默认编码可能是 GBK,直接读会报UnicodeDecodeError。解决方法是读取时指定编码:
data = pd.read_csv('comments.csv', encoding='utf-8-sig')utf-8-sig会自动处理文件开头的 BOM 头,比utf-8更稳妥。如果文件是 GBK,就改成encoding='gbk'。
Windows 系统下,控制台用 print 输出中文也可能乱码,这通常不是代码的问题,而是控制台编码不是 UTF-8。启动前先执行set PYTHONIOENCODING=utf-8,或者直接在代码里指定。Django 页面乱码则要检查 HTML 模板的 meta 标签:
<meta charset="utf-8">只要数据源头按 UTF-8 处理,后面保存到数据库再读取展示,基本不会出现乱码。
5.3 模型加载与预测速度问题
用 runserver 启动时,每次请求都去 load 一次模型,速度会慢到难以接受。解决办法刚才已经说过,把joblib.load放到模块顶层。这样第一个请求之后,模型对象一直在内存里,预测单条评论只需要毫秒级。
如果你的模型 pkl 文件很大,比如十几 MB,加载时间可能会让用户等待。这时可以调低 max_features,或者把向量化后的特征压缩。另外,Django 自带的 runserver 只适合开发,不能扛高并发。线上部署可以用 Gunicorn 加 Nginx,但毕业设计一般只要求演示,runserver 够用了。
需要提醒的是,模型文件、向量器文件和预处理函数要在部署时一起拷贝。很多人只拷贝了模型文件,忘记带向量器,导致线上预测直接报错。
5.4 数据不平衡问题
电商评论里,只给了默认好评的用户很多,而正经写负面评论的人少,所以数据集常见正向偏多。如果不处理,模型会把所有评论都猜成正面,因为这样也能拿到很高的准确率。这就是准确率的高分陷阱。
解决办法有三个方向。一是收集更多负面和中性样本,也就是在数据层面做平衡。二是调整分类器参数,逻辑回归里设置class_weight='balanced',朴素贝叶斯里可以用类别先验。三是在评估时多关注 F1 macro,它会对少数类更敏感。
我在实际做评估时还遇到过一种情况:单独看每个类别的准确率都不错,但整体准确率很低。这通常是因为不同类别使用了不同的数据处理逻辑,或者标签映射混乱。遇到这种问题先检查数据分布和类别映射,再去怀疑模型。
5.5 答辩前检查清单
最后整理一份我在交付前会逐项检查的清单:
- 代码是否在全新环境里能跑通,不依赖 IDE 里的隐藏配置。
- 模型文件、向量器文件是否已经生成,并且能被项目代码正常加载。
- 预处理函数在训练和预测中是否完全一致,尤其是分词和停用词表。
- README 里是否写清楚环境安装、数据来源、训练命令和启动命令。
- 论文里的截图是否跟当前系统界面一致,避免出现旧版本截图。
- 准备 5 条测试评论,覆盖正向、中性和负向,临场演示时不要现场想。
- 如果老师要传一个新句子测试,你要能清空历史记录并快速得到结果。
这些细节看起来琐碎,但在答辩现场,能顺利运行一次完整演示,比任何口头解释都更有说服力。最后多提一句,整个项目里最值得花时间优化的不是漂亮页面,而是数据处理和评估那一段。页面整洁能用就行,真正决定项目质量的是模型训练流程是否规范、结论是否可信。把这个主线抓牢,毕业设计就不会跑偏。