基于Python与机器学习的文本分类系统:从数据预处理到Flask部署全流程

发布时间:2026/10/3 14:39:45
基于Python与机器学习的文本分类系统:从数据预处理到Flask部署全流程 简介本资源为基于Python与机器学习的文本分类系统毕业设计完整资料包面向计算机相关专业需要完成毕业设计的学生以及希望了解文本分类项目落地流程的开发者。系统以新闻文本分类为核心场景涵盖登录权限校验、首页数据概览、新闻分类操作与新闻列表管理等模块用户可通过输入标题与内容完成娱乐、财经等类别的自动归类并查看用户数量、新闻类别数量、新闻数量等统计信息。压缩包为zip格式整体约626.06MB内含源码、数据库与演示视频等文件可支撑从环境搭建到功能演示的完整流程。目前已有191人学习下载适合需要参考系统结构、数据库设计、分类功能实现与界面交互逻辑的读者也可作为撰写论文与准备答辩的实践素材。1. 从一份毕业设计压缩包说起文本分类系统到底在做什么打开一份名为「基于python基于机器学习的文本分类系统毕业设计与实现」的压缩包多数人第一反应是找main.py或者run.py然后直接python main.py跑起来看效果。但真正决定这套系统能不能过答辩、能不能改成自己的东西从来不是那个入口文件而是数据从哪来、特征怎么提、模型怎么选、结果怎么评这四件事。文本分类系统的本质是把一段自然语言映射到一个预定义类别标签上——新闻按频道分、评论按情感分、邮件按垃圾/正常分都是同一套骨架。这套骨架在毕业设计里通常由 Python scikit-learn 或 PyTorch 搭起来配合一个 Flask 或 Django 的演示界面再加一份数据库存历史记录。它适合两类人一类是刚接触机器学习、想找一个完整闭环练手的同学另一类是要交付毕业设计、需要一套能讲清楚原理又能演示的系统。下面我按自己带项目和改别人代码的经验把这条链路拆开讲透。2. 数据、特征与模型文本分类系统的三根支柱2.1 数据集从哪来以及中文文本预处理的四个必做步骤毕业设计里最常见的数据集来源有三种一是公开语料比如 THUCNews、ChnSentiCorp、搜狗新闻语料二是自己爬用 requests BeautifulSoup 抓某个垂直站点的标题和正文三是老师直接给一份 Excel 或 CSV。不管哪种拿到手第一件事不是建模而是把数据读进来看看长什么样。import pandas as pd # 读取数据假设是两列text 和 label df pd.read_csv(data.csv, encodingutf-8) print(df.shape) # 看样本量 print(df[label].value_counts()) # 看类别分布 print(df[text].iloc[0]) # 看一条原始文本这段代码做三件事确认样本总数、检查类别是否均衡、观察原始文本里有没有 HTML 标签或乱码。如果某个类别只有几十条而另一个有几千条后面训练出来的模型会严重偏向多数类这是第一个要处理的问题。中文文本和英文不同没有天然空格分词所以预处理必须走完四步去噪、分词、去停用词、统一长度。去噪是去掉 HTML 标签、URL、特殊符号分词常用 jieba去停用词是去掉「的、了、是、在」这类高频但无区分度的词统一长度是为了后续向量化时维度一致。import jieba import re def clean_text(text): text re.sub(r.*?, , text) # 去 HTML 标签 text re.sub(rhttp\S, , text) # 去 URL text re.sub(r[^\u4e00-\u9fa5a-zA-Z0-9], , text) # 只留中英文数字 return text.strip() def tokenize(text): words jieba.lcut(text) stopwords set(open(stopwords.txt, encodingutf-8).read().split()) return [w for w in words if w not in stopwords and len(w) 1] df[clean] df[text].apply(clean_text) df[tokens] df[clean].apply(tokenize) df[seg] df[tokens].apply(lambda x: .join(x))clean_text里的正则顺序不能反先去标签再去 URL否则标签里的链接可能残留。tokenize里len(w) 1是为了过滤单字中文里单字噪声大但如果你做的是细粒度情感分析这条可以放宽。停用词表网上有很多版本建议自己根据语料补充比如你的数据里「转发」「分享」出现极多且无区分度就加进去。2.2 特征工程TF-IDF 和词向量怎么选参数怎么调文本不能直接喂给模型必须转成数值向量。毕业设计里两条主流路线TF-IDF 和词向量Word2Vec / BERT。TF-IDF 适合传统机器学习模型朴素贝叶斯、SVM、逻辑回归词向量适合深度学习模型TextCNN、LSTM、BERT 微调。TF-IDF 的核心思想是一个词在当前文档出现越多、在整个语料出现越少它越重要。scikit-learn 里一行就能算from sklearn.feature_extraction.text import TfidfVectorizer vectorizer TfidfVectorizer( max_features5000, # 只保留权重最高的 5000 个词 ngram_range(1, 2), # 同时考虑单字和双字组合 min_df2, # 至少在 2 篇文档里出现才保留 max_df0.9 # 出现在超过 90% 文档里的词丢掉 ) X vectorizer.fit_transform(df[seg])max_features5000是控制维度的关键太大容易过拟合且训练慢太小会丢信息。ngram_range(1,2)能捕捉「不 好看」这种双词组合对情感分类帮助明显。min_df2过滤只出现一次的词这些词多半是噪声。max_df0.9过滤掉几乎每篇都有的词效果类似停用词但更自动。如果你用词向量Word2Vec 训练时注意vector_size一般设 100 到 300window设 5 左右min_count设 2 到 5。BERT 微调则直接用 HuggingFace 的AutoTokenizer但显存要求高毕业设计如果只有笔记本建议先用 TextCNN Word2Vec 跑通。2.3 模型选型从朴素贝叶斯到 BERT 的四档方案模型选择取决于你的数据量、算力和答辩要求。我一般把方案分四档方案模型适合数据量训练时间准确率参考一档朴素贝叶斯 TF-IDF几千条秒级80%–88%二档SVM / 逻辑回归 TF-IDF几千到几万秒到分钟85%–92%三档TextCNN / LSTM Word2Vec几万条以上分钟到小时90%–95%四档BERT 微调几万条以上小时级GPU93%–97%一档和二档适合快速出结果答辩时讲清楚 TF-IDF 原理和混淆矩阵就够了。三档需要 PyTorch 或 TensorFlow代码量翻倍但能体现深度学习能力。四档效果最好但对硬件要求高且微调不好容易翻车。from sklearn.svm import LinearSVC from sklearn.model_selection import train_test_split from sklearn.metrics import classification_report X_train, X_test, y_train, y_test train_test_split( X, df[label], test_size0.2, random_state42, stratifydf[label] ) model LinearSVC(C1.0, max_iter2000) model.fit(X_train, y_train) y_pred model.predict(X_test) print(classification_report(y_test, y_pred))stratifydf[label]保证训练集和测试集类别比例一致避免某类全进训练集。C1.0是正则化强度的倒数越大越容易过拟合数据噪声大时调到 0.5 甚至 0.1。max_iter2000是防止不收敛报 warningSVM 在文本高维数据上通常几百次内收敛设大一点保险。2.4 评估与调参准确率之外必须看的三个指标准确率accuracy在类别均衡时够用但类别不均衡时会被多数类带偏。比如 90% 是正面、10% 是负面模型全猜正面也有 90% 准确率但负面一个都抓不到。所以必须看精确率precision、召回率recall和 F1 值。from sklearn.metrics import confusion_matrix import seaborn as sns import matplotlib.pyplot as plt cm confusion_matrix(y_test, y_pred) sns.heatmap(cm, annotTrue, fmtd, cmapBlues) plt.xlabel(Predicted) plt.ylabel(True) plt.show()混淆矩阵能直观看到哪两类容易混。比如情感分类里「中性」和「正面」经常互错这时候要么补充中性样本要么把两类合并。调参时优先调max_features和C这两个对结果影响最大。如果 F1 在 0.85 以上毕业设计答辩基本没问题如果低于 0.7先检查数据标注是否一致再检查预处理有没有把关键信息洗掉。3. 从训练脚本到可演示系统Flask 接口与数据库落地3.1 用 Flask 把模型包成 HTTP 接口的最小实现训练完模型不能只停在 Jupyter Notebook 里毕业设计通常要求有一个能输入文本、点击按钮、看到分类结果的界面。最轻量的做法是 Flask 起一个服务前端一个简单 HTML 页面。from flask import Flask, request, jsonify import joblib app Flask(__name__) model joblib.load(svm_model.pkl) vectorizer joblib.load(tfidf_vectorizer.pkl) app.route(/predict, methods[POST]) def predict(): text request.json.get(text, ) if not text: return jsonify({error: empty text}), 400 seg .join(tokenize(clean_text(text))) vec vectorizer.transform([seg]) label model.predict(vec)[0] return jsonify({label: label}) if __name__ __main__: app.run(host0.0.0.0, port5000)joblib.load加载的是训练阶段用joblib.dump保存的模型和向量器注意两者必须配套换一个向量器模型就废了。vectorizer.transform而不是fit_transform因为测试阶段不能重新拟合词表。返回 JSON 而不是渲染模板是为了前后端分离前端用 fetch 调用即可。3.2 数据库表设计与历史记录存储演示系统一般要存两类数据分类历史记录和用户反馈可选。用 SQLite 最省事不用额外装服务。import sqlite3 def init_db(): conn sqlite3.connect(history.db) conn.execute( CREATE TABLE IF NOT EXISTS records ( id INTEGER PRIMARY KEY AUTOINCREMENT, text TEXT NOT NULL, label TEXT NOT NULL, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ) ) conn.commit() conn.close() def save_record(text, label): conn sqlite3.connect(history.db) conn.execute(INSERT INTO records (text, label) VALUES (?, ?), (text, label)) conn.commit() conn.close()表结构只保留三个核心字段原文、预测标签、时间。created_at用数据库默认值避免 Python 端时区问题。如果要做用户系统再加一个user_id外键。查询历史时按时间倒序取前 50 条即可数据量大时加索引。3.3 前端页面与接口联调的三个注意点前端不需要框架一个 HTML 加一段 JavaScript 就够。关键是跨域和编码问题。!DOCTYPE html html headmeta charsetutf-8title文本分类演示/title/head body textarea idinput rows5 cols60/textareabr button onclickpredict()分类/button p idresult/p script async function predict() { const text document.getElementById(input).value; const res await fetch(/predict, { method: POST, headers: {Content-Type: application/json}, body: JSON.stringify({text: text}) }); const data await res.json(); document.getElementById(result).innerText 分类结果 data.label; } /script /body /htmlContent-Type: application/json必须写否则 Flask 的request.json拿不到数据。页面编码声明meta charsetutf-8不能少中文乱码十有八九是这里漏了。如果前端和后端不在同一个端口需要 Flask 加 CORS 头或者直接用 Flask 的render_template把页面和后端放一起省去跨域麻烦。4. 避坑与排查改别人毕业设计代码时最容易翻车的五件事4.1 现象模型训练报「empty vocabulary」→ 原因分词后全是停用词或单字 → 解决检查停用词表和len(w)1过滤这个报错通常出现在TfidfVectorizer.fit_transform阶段意思是所有文档分词后没有任何一个词进入词表。最常见的原因是停用词表太大把有效词也滤掉了或者tokenize里len(w)1把中文双字词也误杀了。解决方法是先打印一条分词结果看看确认有正常词汇后再调min_df。4.2 现象准确率 95% 但实际用起来全错 → 原因训练集和测试集有重复样本 → 解决去重后再划分很多人爬数据时没去重同一条文本出现多次随机划分后训练集和测试集里都有模型等于背答案。用df.drop_duplicates(subset[text])去重再做train_test_split。如果同一类别的文本高度相似还要考虑按来源分组划分。4.3 现象Flask 接口返回中文乱码 → 原因jsonify默认 ASCII 编码 → 解决设置app.config[JSON_AS_ASCII] FalseFlask 旧版本jsonify会把中文转成\uXXXX前端显示就是乱码。在 app 初始化后加app.config[JSON_AS_ASCII] False即可。新版 Flask 2.3 之后默认就是 UTF-8但如果你用的是旧代码这一行不能省。4.4 现象换一台电脑跑不起来 → 原因依赖版本不一致或模型文件路径写死 → 解决用requirements.txt锁版本路径用os.path.join毕业设计压缩包里经常没有requirements.txt或者有但没锁版本。scikit-learn 不同版本joblib保存的模型可能不兼容。建议在项目根目录生成pip freeze requirements.txt并在代码里用os.path.dirname(__file__)拼路径不要写D:\xxx\model.pkl这种绝对路径。4.5 现象答辩时被问「为什么用 SVM 不用 BERT」答不上来 → 原因选型理由没提前准备 → 解决从数据量、算力、可解释性三个角度回答这不是代码问题但翻车率极高。标准回答框架数据量只有几千条BERT 微调容易过拟合实验室机器没有 GPUSVM 训练秒级完成答辩要求讲清楚特征工程TF-IDF 可解释性比 BERT 强。如果老师追问 BERT就说后续改进方向是引入预训练模型但当前方案在有限资源下性价比最高。5. 把系统改成自己的换数据集、换模型、加功能的实操路径拿到一份毕业设计压缩包最忌讳的是只改个标题就交。真正让这套系统变成你自己的东西走三步换数据、换模型、加一个原系统没有的功能。换数据是最快体现差异的方式。把原来的新闻分类换成你熟悉的领域比如校园论坛帖子分类、电商评论情感分类、技术博客标签分类。换数据后预处理规则要跟着调比如电商评论里「好评」「差评」是关键词不能当停用词滤掉。# 换数据集后重新检查类别分布 new_df pd.read_csv(my_data.csv, encodingutf-8) print(new_df[label].value_counts()) # 如果某类少于 100 条考虑合并或补充 new_df new_df[new_df[label].isin([类别A, 类别B, 类别C])]换模型是第二个差异点。原系统用朴素贝叶斯你可以换成 LinearSVC 或 TextCNN只要在论文里写清楚对比实验。加功能是第三个差异点比如加一个「批量导入 CSV 并导出分类结果」的功能或者加一个「置信度展示」让前端显示模型对当前预测的概率。# 用 predict_proba 展示置信度SVM 需要 probabilityTrue 或改用逻辑回归 from sklearn.linear_model import LogisticRegression clf LogisticRegression(max_iter1000) clf.fit(X_train, y_train) proba clf.predict_proba(X_test)[0] print(f类别 {clf.classes_} 的概率{proba})逻辑回归的predict_proba直接给出每个类别的概率前端可以显示「正面 0.87负面 0.13」比只显示一个标签更有说服力。如果坚持用 SVM需要LinearSVC配合CalibratedClassifierCV做概率校准代码量稍大。最后说一个我自己的习惯每次改完代码先在一个只有 100 条数据的小样本上跑通全流程确认训练、保存、加载、预测、存库、前端展示六个环节都不断再换全量数据。这样出问题能快速定位是数据问题还是代码问题。毕业设计拼的不是模型多先进而是整条链路能不能稳定跑通、能不能讲清楚每个环节为什么这么做。希望帮到你。本文还有配套的精品资源点击获取