简介一份来自TUST本科毕业设计的完整工程包主题是基于机器学习的新闻标题分类系统面向人工智能、机器学习与深度学习方向的毕业设计或课程设计开发者。包内共63个文件整体仅10.93MB涵盖Python脚本、前端页面、文本语料、SQL数据库与分析笔记等类型主程序、配置、流程与视图分层清晰。其中主程序为项目入口流水线脚本处理数据视图模块关联前端页面完成Web展示配置与过滤逻辑分别管理全局参数和文本过滤数据侧则包含训练集、测试语料、多份中文与哈工大停用词表、敏感词表及标签映射表、词汇表可支撑新闻标题文本预处理与分类模型训练。随包附有ipynb分析笔记、Word文档和PDF任务书便于梳理毕设思路与成果汇报。目前已有88人学习下载适合需要复现新闻分类实验、拆解机器学习项目流程或参考本科毕设框架的读者二次开发。1. 新闻标题分类这个毕设题到底在做什么每年毕业季都有大量本科生的机器学习选题落在文本分类上而“新闻标题分类系统”是其中最典型的之一。它的核心任务很直白给一句短文本——比如“A股三大指数集体高开科技板块领涨”——判断它属于财经、体育、娱乐还是时政。标题短、噪声大、上下文少恰好把机器学习里最难处理的“短文本语义稀疏”问题浓缩在一个可控范围内非常适合本科生用来走完一整套机器学习的应用流程数据清洗、特征工程、模型选型、评估对比和结果解释。这篇笔记就把这套毕设从零到一拆开讲包括为什么选机器学习而不是深度学习、数据怎么来、特征怎么抽、算法怎么调、坑在哪里以及最后怎么收出一个能写进论文的结论。我见过不少学生在这个选题上翻车翻车的原因往往不是模型跑不起来而是不知道自己在做什么实验有的把全部数据丢进BERT微调显存爆了不说论文里也讲不清楚收益有的用朴素贝叶斯勉强到80%准确率就收工答辩被问“特征为什么这么选”直接卡壳。这篇就按“能毕业、能答辩、能被复现”的标准来写适合那些打算独立完成、不靠代做的本科生。2. 先把技术选型定死为什么是机器学习而不是深度学习2.1 两个方向的边界数据量、算力和解释性很多人在开题时会纠结新闻标题分类用BERT不香吗从效果上说预训练模型在长文本上确实碾压传统机器学习但在标题这种长度在20到40字、类别相对固定的短文本上优势并没有想象中那么大。关键在于数据量本科毕设能拿到的标注数据通常在几千到两三万条这个规模下词袋模型加TF-IDF再加线性分类器准确率可以做到85%到90%而BERT在小数据集上如果微调不当反而容易过拟合验证集分数还打不过逻辑回归。另一个现实约束是算力。传统机器学习在CPU上几分钟就能完成训练和网格搜索BERT至少要一块像样的GPU而且每次微调的时间成本高出两三个数量级。对毕设而言时间的优先级很高因为后面还有写论文、做系统、准备答辩这些环节。解释性也是一个容易被低估的点——答辩老师问“为什么这条标题被分到体育类”逻辑回归可以指出是哪几个词贡献了决策权重神经网络很难给出这种清晰的归因。这并不意味着要完全排斥深度学习。如果数据量超过五万条或者你确实想在论文里加一个“与深度学习基线对比”的实验可以最后再补一个TextRCNN或FastText作为对比模型。但主力方案应该落在传统机器学习上这既是毕设的稳妥选择也符合“先讲清楚基础方法再谈改进”的论文叙事。2.2 数据从哪来标注成本与类别设计新闻标题分类的数据集有三个来源公开数据集、爬虫自采、手工标注。公开数据集方面THUCNews的子集是常见的起点它有训练集、验证集、测试集的划分直接可以用于文本分类任务。自采数据则要谨慎——爬新闻本身不复杂麻烦的是标注标题没有现成的类别字段。比如新浪新闻的URL里有时会带分类但历史数据不一定完整搜狐新闻的频道页可以按栏目抓但栏目和你要的类别不一定一一对应。手工标注的代价更大一万条标题一个人标每天标一千条也要两周而且标到后面注意力下降标签质量会明显波动。类别设计上建议控制在5到8类。我在实际操作中比较推荐的配置是财经、体育、娱乐、科技、时政、社会共6类。为什么不是10类因为类别越多类间混淆越严重比如“教育”和“时政”经常互相踩线“健康”和“社会”也纠缠不清而本科生论文里的混淆矩阵会把这些错误暴露得很彻底。6个类别足够展示多分类能力又不至于让分类器的压力过大。每个类别的样本量尽量均衡最低不要低于每类1500条。如果总数据量在两万条左右六类平均每类三千条训练效果就已经比较稳定了。数据量不够时先别急着上模型优先考虑扩充数据而不是用采样技巧硬撑。2.3 评价指标不能只看准确率看混淆矩阵和F1新闻标题分类的类别分布如果不均衡——比如财经类标题远多于体育类——准确率就会变成一个欺骗性很强的指标模型只要把所有样本都预测成财经准确率也可能有40%。所以至少要同时看三样东西宏平均F1、加权平均F1、混淆矩阵。宏平均F1对每个类别一视同仁能反映出小类别的表现混淆矩阵则能精确告诉你哪两个类别在互相打架。另外要固定随机种子。数据集划分和模型初始化如果不固定种子每次跑出来的分数都会不一样论文里的实验对比就站不住。一般做法是在划分数据时用train_test_split的random_state42在模型训练时也给算法固定随机种子这样别人复现你的实验时能得到一致的结果。3. 搭建可复现的处理流程从原始标题到TF-IDF特征再到模型训练3.1 数据清洗与预处理的三个关键步骤新闻标题虽然比微博评论干净但同样有需要处理的地方。第一步是全角半角转换和统一大小写——英文单词在全角状态下会被分词器切成乱码这一步不处理后面特征空间里会多出一堆垃圾维度。第二步是去除非文本噪声括号里的来源信息比如“图”“(组图)”这类内容对分类没有帮助还会把特征维度撑大直接删掉。第三步是分词和去停用词中文分词用jieba停用词表可以选哈工大版本再加几个新闻场景下的自定义停用词。import jieba import re STOP_WORDS set() with open(stopwords_hit.txt, r, encodingutf-8) as f: for line in f: STOP_WORDS.add(line.strip()) def clean_title(title: str) - str: # 全角转半角 title title.translate({0xFF01 i: 0x21 i for i in range(94)}) # 去掉括号及括号内内容 title re.sub(r[(].*?[)], , title) # 去掉URL、数字串等噪声 title re.sub(rhttps?://\S, , title) title re.sub(r\d, , title) return title.strip() def tokenize(title: str) - list: title clean_title(title) words jieba.lcut(title) return [w for w in words if w.strip() and w not in STOP_WORDS]这段代码的逻辑分三部分清洗函数解决字符层面的噪声分词函数负责把标题切成词序列停用词过滤则把“的、了、在”这类高频但无语义贡献的词去掉。注意数字我直接删掉了——在新闻标题里数字对类别判断的帮助极其有限比如说“价格上涨15%”和“上涨”在特征上几乎等价但数字本身会制造稀疏特征白白增加维度。3.2 用TF-IDF做特征表示参数怎么设分词之后标题要从文本变成向量。常见做法是词袋加TF-IDF而不是直接用词频。TF-IDF的核心逻辑是一个词如果在当前标题里出现频率高但在整个语料里很少出现那它对这条标题的区分度就大。这个逻辑用在短文本上非常合适因为标题里能用的词本来就不多TF-IDF能把那些在类别间有区分力的词挑出来。from sklearn.feature_extraction.text import TfidfVectorizer vectorizer TfidfVectorizer( tokenizertokenize, max_features20000, ngram_range(1, 2), min_df2, max_df0.8, sublinear_tfTrue ) X_train_tfidf vectorizer.fit_transform(X_train) X_test_tfidf vectorizer.transform(X_test)几个参数的考量max_features20000限制特征维度防止词表过大导致训练变慢和过拟合。新闻标题的语料里两万维基本能覆盖高频有效词汇再往上提收益很小。ngram_range(1, 2)加入二元词组特征。新闻标题里很多类别信号是词组比如“股价”“涨停”是财经“进球”“比分”是体育单个词会丢失这种组合信息。min_df2至少在两条标题里出现过的词才保留。只出现一次的词是噪声对分类没有泛化价值。max_df0.8在超过80%的标题里都出现的词基本是停用词级别的权重会被IDF压得极低直接去掉能省维度。sublinear_tfTrue用1 log(tf)替代原始词频避免长标题里重复出现的词获得过高的权重。新闻标题虽然短但同一个词重复出现的概率依然存在。这里有一个容易犯的错误fit_transform只能用在训练集上测试集必须用已经拟合好的vectorizer.transform。否则测试数据会把自己的词表加进去造成特征空间不一致测试分数虚高但这部分虚高在真实场景里根本不存在。3.3 第一个能跑的模型先拿逻辑回归做基线在调任何复杂的模型之前先用逻辑回归做一个基线。逻辑回归在TF-IDF特征上表现稳定训练快而且系数可以直接用来解释特征重要性。这一步的目的不是追求最高分而是确认整个数据管道——从清洗到向量化——是通的。from sklearn.linear_model import LogisticRegression from sklearn.metrics import classification_report model LogisticRegression( max_iter2000, C1.0, solverliblinear, random_state42 ) model.fit(X_train_tfidf, y_train) y_pred model.predict(X_test_tfidf) print(classification_report(y_test, y_pred, digits4))solverliblinear适用于中小规模的多分类问题用一对多策略训练速度快内存占用低。max_iter设到2000是为了避免默认值在特征维度较高时不收敛的警告。C1.0先不动等基线跑出来之后再做网格搜索。一般来说这个基线在六类新闻标题数据集上应该能到85%左右的宏平均F1。如果连这个数字都到不了说明问题出在数据质量或预处理上而不是模型不够强——这时候应该回头检查标签是否错乱、清洗是否有误而不是继续换模型。4. 模型对比与调参哪些算法适合新闻标题怎么调出最优结果4.1 四个候选算法的选型对比拿到基线之后下一步是和其他算法做对比通常选四个朴素贝叶斯、逻辑回归、SVM、随机森林。它们在文本分类上各有特点恰好覆盖了生成式、判别式、核方法和树模型四个方向论文里也好写。算法训练速度对稀疏特征的适应性调参复杂度解释性朴素贝叶斯(MultinomialNB)极快好极低较好逻辑回归快好低最好SVM(LinearSVC)快好中等一般随机森林慢中等较高好朴素贝叶斯在小样本上表现稳定但它假设特征条件独立而标题里的词经常是强相关的比如“股市”和“上涨”明显不独立所以它的上限通常低于逻辑回归。SVM在高维稀疏特征上表现好但它的决策边界不如逻辑回归的系数那样直观答辩时需要额外解释。随机森林在稀疏高维文本特征上一般不占优——树模型擅长数值型稠密特征对词袋这种高维稀疏矩阵处理效率低这个对比正好说明“不是所有机器学习算法都适合文本分类”。在处理中文文本分类尤其是短文本分类这类任务时业界更看重实际效果与部署成本而非盲目追求复杂模型。选择这几个算法的另一个现实原因它们都在scikit-learn里开箱即用不需要额外的深度学习框架。4.2 调参路线先调C再调特征参数以逻辑回归为例调参的优先级应该是正则化系数C、loss函数类型、特征层的n-gram范围。网格搜索放在最后不要一开始就把所有参数丢进GridSearchCV时间成本太高。from sklearn.model_selection import GridSearchCV param_grid { C: [0.1, 0.5, 1.0, 2.0, 5.0], penalty: [l2], class_weight: [None, balanced] } gs GridSearchCV( LogisticRegression(max_iter2000, solverliblinear, random_state42), param_grid, cv5, scoringf1_macro, n_jobs-1, verbose1 ) gs.fit(X_train_tfidf, y_train) print(gs.best_params_) print(gs.best_score_)scoringf1_macro指定用宏平均F1作为模型选择的标准而不是准确率这样能让小类别的表现也进入优化目标。cv5用五折交叉验证避免单次划分的随机性。class_weightbalanced是一个值得尝试的选项——如果类间数量不平衡它会自动加大少数类的权重但对新闻标题这种相对均衡的数据集效果可能差异不大需要实验确认。4.3 加入LinearSVC做对比不要只调一个模型在论文里只有逻辑回归一组结果显得单薄。通常的做法是再跑一个SVM做对比并配合特征维度进行消融实验才能形成完整的实验结果分析。from sklearn.svm import LinearSVC svm_model LinearSVC(C1.0, max_iter2000, random_state42) svm_model.fit(X_train_tfidf, y_train) svm_pred svm_model.predict(X_test_tfidf) print(classification_report(y_test, svm_pred, digits4))LinearSVC的损失函数是hinge loss和逻辑回归的log loss不同它更关注分类边界的“最大间隔”。在高维稀疏文本特征上SVM通常和逻辑回归分数接近但某些类别分布下会有差异。这个对比放在论文里可以引出“不同损失函数对短文本分类的影响”这个讨论点。不过要注意LinearSVC不直接提供概率输出如果需要概率做置信度分析要用CalibratedClassifierCV包一层但如果不是做置信度过滤可以不用。5. 常见坑与排查新闻标题分类中那些让人反复翻车的问题5.1 分词和清洗顺序颠倒导致特征里全是废词现象训练出来的模型分数很低查看高频特征时发现一堆乱码比如“\u3000”或者“nbsp”还有大量单字“的”“了”“在”。原因先做了停用词过滤再做分词。停用词表里的词大多是全角字符分词前不清理它们在特征空间里仍然是独立的“词”白白占据维度。另一个常见问题是先分词再全角转半角结果切出来的词和词表对不上。解决严格按“清洗→分词→去停用词”的顺序执行。清洗阶段做字符统一和去噪声分词之后再做停用词过滤。检查特征是否干净直接打印vectorizer.get_feature_names_out()[:50]看前50个特征里有没有异常词。5.2 训练集和测试集的特征空间不一致现象验证集上的F1很高但在新数据上表现很差或者训练时报“dimension mismatch”错误。原因对训练集和测试集分别调用了fit_transform导致两边各自生成词表维度对不上。这是文本分类最经典的错误之一本质上是信息泄漏——测试集的特征分布被混入了训练过程分数虚高。解决训练集用fit_transform测试集和所有后续新数据一律用transform。用一个vectorizer实例贯穿整个流程不要在中间重新初始化。每次实验前检查X_train_tfidf.shape[1] X_test_tfidf.shape[1]这个断言能挡住大多数低级错误。5.3 类别标签不均衡被忽略现象总体准确率很高但看混淆矩阵时发现某个类别几乎没被预测对比如“体育”类样本被大量分到“社会”类。原因六个类别的样本量差异大模型倾向于预测样本多的类别。准确率指标被大类别拉高掩盖了小类别的缺陷。解决在训练前查看y_train.value_counts()的分布。如果不均衡程度超过2:1要么采样平衡在样本多的类别上随机下采样要么在模型里设置class_weightbalanced。但当数据不均衡远超3:1时用采样方法的意义有限这时候更要考虑去扩充少数类别的数据而不是靠算法硬扛。5.4 模型的随机性导致实验无法复现现象同一个模型运行两次分数完全不同论文里写的结果别人复现不了。原因没有固定随机种子。数据划分、模型初始化、网格搜索里的shuffle都依赖随机数每次运行时结果都会变。解决在数据划分时为train_test_split设置random_state42为模型设置random_state42如果用了多进程训练在脚本开头用np.random.seed(42)和random.seed(42)固定全局种子。把所有实验的随机种子记录下来写进论文的实验设置部分这是答辩时最容易被问到的一个细节。6. 最后一招用错误分析把结果从“能跑”变成“能答辩”模型调完、分数满意之后大多数本科生会直接开始写论文这是最浪费的一步。真正让毕设加分的关键是错误分析——找出模型分错的样本理解错误模式然后针对性地改进。这个环节做得好论文从“我用了机器学习”变成“我分析了问题并提出了改进”答辩的深度完全不同。常见的做法是把预测错误的样本单独抽出来按类别分组然后逐条看。我在新闻标题上总结过几种典型错误第一种是标题里没有类别特征词比如“最新消息三部门联合发布重要文件”这种标题信息量极低人也要结合背景才能判断类别机器没有背景知识自然容易错第二种是跨类别词干扰比如“电竞选手转会”属于体育还是娱乐取决于语境但如果词汇表里“选手”的权重偏向体育“转会”偏向娱乐分类器就可能被带偏第三种是标签本身的问题——有些数据源在标注时本身就带噪声样本被贴错了标签导致模型学到的信号互相矛盾。针对这些问题可以做一个简单的规则修正实验对低置信度的预测结果如果预测概率低于0.6则根据标题中的关键词做规则修正。比如标题里同时出现“转会”“战队”“选手”规则直接归为体育类。这个方法不一定能在整体F1上提升多少但它展示了模型融合的思路——机器学习加规则兜底这也是一种改进策略。最后一个技巧是绘制每个类别的前十大特征词。逻辑回归的系数可以直接输出比如model.coef_按类别排序后取前十个词。这张特征词表放在论文里非常直观财经类的“股市、资金、板块”体育类的“比赛、冠军、赛场”一眼就能看出模型学到了什么。如果某个类别的特征词不合理比如“体育”类里出现“公司”说明数据里有噪声标签需要回头检查。顺便提一句如果你有时间可以再做一次维度消融实验分别用ngram_range(1,1)和(1,3)再加上max_features从5000到30000的几组设置看F1的变化曲线。这个实验做出来的图表在论文里很能说明问题也能帮你理解参数和效果之间的关系答辩时被问“你调过什么参数”就有话可说了。我自己的习惯是每个实验记录一组固定的配置参数和当时的F1分数存成一个实验日志哪怕只是写在文本文件里也行。到写论文和答辩时这份日志能省下大量回忆的时间不至于被问到“你试过什么参数”时支支吾吾。毕设做到这里你手里就不仅是一个能运行的模型而是一套完整的方法论和实验记录希望帮到你。最后补一个关于“毕设系统”的建议如果题目要求做一个系统而不是只交实验结果前后端就用Flask加一个简单的web页面模型导出成pickle文件启动时加载模型输入一个标题返回分类结果和置信度。这部分本身不复杂但要在论文里把系统架构图画清楚并附上界面截图。系统的模块划分尽量贴合你前面的数据预处理、特征提取、模型推理这三个阶段这样每个模块都对应论文中的一个章节答辩时的逻辑会非常顺畅。本文还有配套的精品资源点击获取