基于Python与Django的文本情感分析系统:从分词到朴素贝叶斯 📅 发布时间:2026/9/19 14:36:00 👁 浏览次数: 简介这是一份基于Python的机器学习文本情感系统设计与实现的毕业设计文档适合计算机相关专业学生、毕业设计选题者及对文本情感分析感兴趣的学习者参考。内容从开发背景、开发意义入手详细介绍了Python、Django框架和MySQL数据库的技术选型并围绕自然语言处理场景完成系统分析、结构设计、功能模块设计与数据库设计覆盖登录模块、管理员首页、文本分类、文本管理及用户信息管理等核心功能实现最后通过系统测试验证可行性。文档结构完整目录层级清晰能帮助读者快速把握一个基于Web的文本情感分析系统的完整构建流程。资源包大小为1.07MB包含1个docx文档已有323人学习下载。对需要撰写毕业设计说明书、搭建类似系统或理解机器学习文本情感分析应用落地的人来说是一份具备参考价值的完整范本。1. 从一条微博到情感标签基于Python与Django的文本情感系统你在做舆情监控时每天要处理成千上万条评论单靠人工标注积极或消极显然不现实。这个项目要解决的正是这个问题用Python做自然语言处理把输入的中文句子自动判断为“积极”或“消极”再通过Django把能力包装成Web系统MySQL负责存储分类记录。它不依赖大模型只凭jieba分词、TF-IDF和朴素贝叶斯就能跑起来适合NLP入门、课程设计或毕业设计参考。整个系统的核心链路是文本输入 → 分词 → 特征向量化 → 分类器预测 → 结果入库管理。下面从模型、框架、实现和测试四个层面拆开讲。2. 自然语言处理与情感分类模型jieba分词到朴素贝叶斯实践2.1 情感分类的本质把中文句子映射为积极/消极文本情感分析在机器学习里属于有监督文本分类输入是字符串输出是预定义类别。中文和英文最大的差异是没有天然空格所以第一步是分词。一个完整的处理流程通常包含文本清洗、分词、去停用词、特征向量化、训练分类器、评估效果。对于小数据集和初学者项目朴素贝叶斯是性价比最高的起点它假设特征间相互独立虽然这个假设在真实文本中并不成立但在短文本情感分类上表现依然稳定训练速度也快。实际项目中不要一上来就选深度学习。大部分毕业设计或内部工具的数据量只有几千条LSTM或Transformer很容易过拟合还需要GPU调参。传统机器学习只要特征设计得当准确率可以达到85%以上而且推理时间在毫秒级部署进Django毫无压力。2.2 用TfidfVectorizer构造特征给朴素贝叶斯喂数据下面是一段可以直接运行的最小示例展示如何用jieba分词后再通过TfidfVectorizer把文本转成向量最后训练一个MultinomialNB分类器。import jieba from sklearn.feature_extraction.text import TfidfVectorizer from sklearn.naive_bayes import MultinomialNB from sklearn.model_selection import train_test_split # 模拟一个小型标注语料0表示消极1表示积极 texts [ 卫生特别差不会再来了, 上菜速度太慢等了一个小时, 味道很好下次还来, 服务热情环境干净, 价格偏高分量很少, 性价比很高推荐 ] labels [0, 0, 1, 1, 0, 1] def cut_words(text): # 用空格连接分词结果方便TfidfVectorizer按空白切分 return .join(jieba.cut(text)) corpus [cut_words(t) for t in texts] # token_pattern必须设置为\S否则默认规则匹配不了中文词 vectorizer TfidfVectorizer( token_patternr\S, max_features1000, ngram_range(1, 2) ) X vectorizer.fit_transform(corpus) y labels X_train, X_test, y_train, y_test train_test_split( X, y, test_size0.2, random_state42 ) model MultinomialNB(alpha0.5) model.fit(X_train, y_train) # 注意这里只有6条数据准确率不代表真实效果 accuracy model.score(X_test, y_test) print(f测试集准确率: {accuracy:.2f})这段代码有几个关键参数值得注意。token_patternr\S是必须的因为我们已经用空格把中文词分开默认的\b\w\w\b对中文完全无效。max_features1000限制了字典大小避免维度爆炸实际项目中可以根据语料规模调到5000到20000。ngram_range(1, 2)除了单个词还保留相邻两个词的组合这样不 好会被拆成不、好、不好能抓住一部分否定含义。alpha0.5是拉普拉斯平滑系数防止某个词在某一类样本中没出现导致概率为0。它越大模型越保守对噪声容忍度越高越小越容易过拟合训练集。调参时可以按0.1、0.3、0.5、0.8、1.0依次尝试用交叉验证选最优值。2.3 模型评估与算法选型为什么不用深度学习在做选型对比时我一般会从训练成本、推理速度、小样本表现三个维度看。下面是几个常见模型的横向对比数据来自我个人的项目经验具体数值会随语料质量浮动。对比项朴素贝叶斯SVMLSTM/Transformer小语料表现5000条好一般差容易过拟合训练速度秒级分钟级小时级需GPU部署资源占用极小小大需推理框架可解释性强概率直接可见较弱弱黑盒对于论文里的运行环境普通笔记本就够跑朴素贝叶斯和SVM。如果直接上BERT光是加载预训练模型就要几百MB内存推理一次比朴素贝叶斯慢两个数量级对“在浏览器里输入一句话立刻返回情感”这种场景很不友好。因此我的建议是第一版先做朴素贝叶斯或逻辑回归留好接口后续数据量大了再替换成深度学习。2.4 保存模型与向量器让Web层只负责调用训练完成后需要把向量器和分类器都保存下来否则每次启动Django都要重新训练。这里用joblib序列化。import joblib joblib.dump(vectorizer, models/tfidf.pkl) joblib.dump(model, models/sentiment.pkl)注意必须同时保存vectorizer和model因为预测时先用vectorizer.transform把新文本转成和训练时相同维度的向量再传给model.predict。如果只保存分类器新文本特征维度对不上程序会直接报错。模型文件建议放在项目根目录的models/下并在Django设置里配置好绝对路径避免工作目录变化导致加载失败。3. Django MTV架构与MySQL建模把分类器包装成Web服务3.1 MTV架构中的路由编排Django用的是MTV模式Model负责数据模型和数据库交互Template负责页面渲染View负责业务逻辑。很多开发者容易把它和MVC搞混其实对应关系是Django的View相当于MVC里的ControllerDjango的Template相当于MVC里的View。理解这个对应关系之后写代码时就知道该把逻辑放在哪里。一个请求在Django里的流转顺序是浏览器请求URL → URLconf匹配路由 → 调用对应的View函数 → View操作Model并读取数据库 → 返回渲染后的Template。对于文本情感系统View要做两件事一是调用情感分类模型得到结果二是把结果和原文写入数据库。业务逻辑集中在View里模型部分只负责定义字段和增删改查。3.2 初始化项目并连接MySQL推荐用虚拟环境隔离依赖。先创建项目和应用。python -m venv venv source venv/bin/activate # Windows 下是 venv\Scripts\activate pip install django mysqlclient jieba scikit-learn joblib django-admin startproject sentiment cd sentiment python manage.py startapp text_classifiermysqlclient是Django连接MySQL的驱动在Linux下安装前可能需要先装libmysqlclient-dev。安装完成后在settings.py里配置数据库连接。INSTALLED_APPS [ django.contrib.admin, django.contrib.auth, # 注册自己创建的应用 text_classifier, ] DATABASES { default: { ENGINE: django.db.backends.mysql, NAME: sentiment_db, USER: root, PASSWORD: your_password, HOST: 127.0.0.1, PORT: 3306, OPTIONS: {charset: utf8mb4}, } }这里容易踩的坑是字符集。如果不加OPTIONS: {charset: utf8mb4}写入中文时虽然大部分情况下正常但遇到emoji就会报Incorrect string value错误。同时MySQL侧要保证数据库和表的默认字符集是utf8mb4。建库语句建议用CREATE DATABASE sentiment_db CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;。3.3 基于E-R图设计数据模型管理员与文本分类表根据系统需求核心实体有两个用户管理员和文本分类记录。用Django的ORM定义如下。from django.db import models from django.contrib.auth.models import User class Profile(models.Model): # 扩展Django自带的User记录手机号等额外信息 user models.OneToOneField(User, on_deletemodels.CASCADE) phone models.CharField(max_length11, blankTrue) class TextRecord(models.Model): # 用户输入的原始文本 content models.TextField() # 模型判断的结果积极或消极 sentiment models.CharField( max_length10, choices[(积极, 积极), (消极, 消极)] ) # 记录由哪个用户发起分类 user models.ForeignKey(User, on_deletemodels.SET_NULL, nullTrue) created_at models.DateTimeField(auto_now_addTrue) def __str__(self): return f{self.content[:20]} - {self.sentiment}这里没有重新设计一张独立的管理员表而是直接扩展Django自带的User表。实际开发中这样做更安全因为Django内置了密码哈希、会话管理、权限控制没必要自己实现登录逻辑。Profile.phone字段对应原文中“用户的手机号信息”。TextRecord中的外键user关联到User删掉用户时记录保留SET_NULL保证文本历史不丢失。生成并执行迁移python manage.py makemigrations python manage.py migrate python manage.py createsuperuser执行完后MySQL会自动创建以下核心表auth_user是Django内置text_classifier_textrecord是自定义表。字段类型说明idINT主键自增contentTEXT待分类文本sentimentVARCHAR(10)分类结果积极/消极user_idINT外键关联auth_usercreated_atDATETIME创建时间自动写入3.4 用Admin后台快速管理分类记录在text_classifier/admin.py中注册模型就能直接使用Django自带的Admin界面管理文本记录。from django.contrib import admin from .models import Profile, TextRecord admin.register(TextRecord) class TextRecordAdmin(admin.ModelAdmin): list_display (content, sentiment, user, created_at) search_fields (content,)Admin后台只适合后期管理面向普通用户的界面仍然需要自己写。接下来的章节会处理登录、分类调用和记录列表这些前台功能。4. 文本分类与文本管理模块实现登录、分类调用与记录入库4.1 登录与注册复用Django内置认证登录不需要从零造轮子。Django的authenticate和login已经实现了密码校验和会话写入。下面是一个简化的登录视图。from django.contrib.auth import authenticate, login from django.shortcuts import render, redirect def login_view(request): if request.method POST: username request.POST.get(username) password request.POST.get(password) user authenticate(request, usernameusername, passwordpassword) if user is not None: login(request, user) return redirect(/classify/) else: # 返回错误信息给模板 return render(request, login.html, {error: 用户名或密码错误}) return render(request, login.html)authenticate负责校验用户名和密码是否匹配匹配成功返回User对象否则返回None。login会把用户ID写入Django的session之后的请求可以通过request.user识别当前用户。注意密码不能明文存储Django默认使用PBKDF2算法哈希这是安全底线。4.2 把模型加载和预测封装成独立服务为了避免每个请求都重新加载模型我把预测逻辑单独放在text_classifier/ml_service.py中用模块级变量缓存模型。import jieba import joblib _vectorizer None _model None def _load(): global _vectorizer, _model if _vectorizer is None: _vectorizer joblib.load(models/tfidf.pkl) _model joblib.load(models/sentiment.pkl) def predict(text: str) - str: _load() # 与训练时保持一致先分词再用空格拼接 words .join(jieba.cut(text)) vec _vectorizer.transform([words]) result _model.predict(vec)[0] return 积极 if result 1 else 消极这里的全局缓存技巧在单进程开发环境很有效。如果使用Gunicorn等多进程部署每个进程会各自加载一份模型内存占用会翻倍但仍在可接受范围内。更高并发时可以把模型放进Redis或使用独立推理服务这里不过度设计。4.3 文本分类视图接收文本、返回结果、自动入库视图函数的职责很明确接收POST参数调用predict把结果存库再返回页面。示例代码如下。from django.contrib.auth.decorators import login_required from django.shortcuts import render from .models import TextRecord from .ml_service import predict login_required def classify_view(request): result None if request.method POST: content request.POST.get(content, ).strip() if content: result predict(content) # 自动保存分类记录关联当前登录用户 TextRecord.objects.create( contentcontent, sentimentresult, userrequest.user ) return render(request, classify.html, {result: result})login_required装饰器会拦截未登录用户自动跳转到登录页。strip()去掉首尾空格避免空文本入库。保存记录时如果用户为匿名外键会报错所以必须保证视图登录后才可访问。模板部分用一个简单的表单接收输入。{% if user.is_authenticated %} form methodpost {% csrf_token %} textarea namecontent rows4 required/textarea button typesubmit开始分类/button /form {% if result %} p情感判断strong{{ result }}/strong/p {% endif %} {% endif %}csrf_token是Django防止跨站请求伪造的必须项不写会报403。这里不需要额外传用户信息模板中的user由Django上下文自动注入。4.4 文本管理列表分页展示与删除原文中“文本管理界面”需要列表展示输入内容、系统判断结果和操作人员。使用Django分页组件可以轻松实现。from django.core.paginator import Paginator from django.shortcuts import render, get_object_or_404, redirect from .models import TextRecord login_required def record_list(request): records TextRecord.objects.all().order_by(-created_at) paginator Paginator(records, 10) # 每页10条 page paginator.get_page(request.GET.get(page)) return render(request, records.html, {page: page}) login_required def record_delete(request, record_id): record get_object_or_404(TextRecord, pkrecord_id) record.delete() return redirect(/records/)分页传page参数模板循环page.object_list就能显示当前页记录。删除操作建议用POST而不是GET这里为了示例简化展示。用户信息管理界面逻辑与此类似只是换一个模型不再赘述。5. 提升分类鲁棒性与黑盒测试边界词、语料与结果验证5.1 中文预处理全角字符与URL清洗实际输入文本远比赛样例恶心全角标点、表情符号、超链接混在一起。在喂给模型前加一道清洗函数。import re def clean_text(text: str) - str: # 统一常见标点为半角减少特征稀疏 text text.replace(, ,).replace(。, .).replace(, !) # 去掉URL和用户名 text re.sub(rhttp\S, , text) text re.sub(r[^\s], , text) # 压缩连续空白 text re.sub(r\s, , text).strip() return text清洗后再进行分词和向量化。注意清洗规则必须和训练时保持一致否则模型看到的特征分布会漂移。调试时最直接的方法是打印清洗后的文本确认每一个步骤效果。5.2 黑盒测试用例设计系统开发完成后需要验证。不能用“高兴”“生气”这种明显词测试要覆盖否定、反讽、中性表达。下面是一组可参考的用例。输入文本期望情感系统输出问题分析太差了消极消极基础用例通过不差积极消极否定句误判加bigram特征好得不得了啊积极不确定口语化句式扩充语料今天天气不错中性可能为积极中性句没有默认策略对于“不差”这类否定句如果模型分词后出现了“不 差”两个词单用unigram只看“差”就会误判。我在2.2节建议ngram_range(1, 2)就是为缓解这个问题。要彻底解决需要增加“不正面词”组合的语料让模型学到“不差”整体出现时更接近积极。中性句如果业务上不需要就在数据标注时把“天气不错”这种句子从训练集里剔除让模型只负责积极/消极二分类。5.3 增量学习把人工纠正的结果重新喂给模型文本管理界面允许管理员删除错误记录但更好的做法是允许修改分类结果并把修正后的数据加入训练集。常见做法是定期重新训练一次。用sklearn的Pipeline把预处理和模型组合在一起保存后Django侧加载更简单。from sklearn.pipeline import Pipeline from sklearn.feature_extraction.text import TfidfVectorizer from sklearn.naive_bayes import MultinomialNB import joblib def retrain(texts, labels): pipe Pipeline([ (tfidf, TfidfVectorizer(token_patternr\S, ngram_range(1, 2))), (clf, MultinomialNB(alpha0.5)) ]) pipe.fit(texts, labels) joblib.dump(pipe, models/sentiment_pipeline.pkl)训练好的Pipeline对象同时包含向量器和分类器预测时只需一行pipe.predict([text])。这样把“人工修正结果 → 定期重新训练 → 线上无缝更新”形成一个闭环系统就可以在真实使用中不断变准。ml_service里的_load逻辑也要对应改成加载pipeline文件前端调用方式不变。本文还有配套的精品资源点击获取