
简介本资源是一份面向计算机专业本科生的课程设计级实战项目聚焦互联网虚假新闻检测这一典型NLP机器学习应用场景适用于期末大作业、课程设计及项目能力强化训练。项目基于Python实现多层感知机MLP分类模型完整覆盖数据预处理、特征工程、模型训练与评估全流程配套详细文档说明与可运行源码助力学习者深入理解文本分类任务的技术落地路径。压缩包共21个文件包含4个核心Python脚本preprocess.py、fit.py、optimize.py、predict.py、3个训练好的MLP模型文件、2个CSV数据集、2个PKL向量器、4个XML配置/日志文件以及DOCX报告、MD说明和IDEA项目配置等整体92.72MB结构规范、模块清晰。目前已有104人下载学习提供从环境搭建到结果预测的端到端实践支持特别适合需快速复现高分课程设计成果的学习者参考与拓展。1. 为什么用 MLP 做虚假新闻检测不是模型越深越好而是数据越脏越要“掐住脖子”调参你手头有一份带标签的新闻文本数据集比如 FakeNewsNet、LIAR 或自爬的微博/公众号样本想快速验证“某条标题正文是否大概率是编的”而不是堆 BERT 大模型跑三天等结果——这时候一个结构干净、训练快、可解释性尚可的多层感知机MLP反而是更务实的选择。它不追求 SOTA 指标但能让你在 2 小时内从零跑通 pipeline文本清洗 → 特征向量化 → MLP 训练 → 二分类输出真/假且每个环节参数都可控、错误可定位。本项目不是教你怎么发论文而是帮你交大作业时不卡 GPU、不报 CUDA 错、不被老师问“你这个 embedding 是怎么来的”当场哑火。适合 Python 基础扎实会 pip install、读 pandas DataFrame、写 for 循环、但没系统学过 NLP 的本科生也适合想快速验证业务逻辑、后续再替换为 Transformer 的工程师。核心不在“多炫”而在“每一步都能 debug”——比如 vectorizer.max_features5000 这个数你改完立刻能看到 vocab_size 变化而不是黑匣子吐出个 loss 下降曲线就以为成了。2. 从原始文本到数值特征TF-IDF 不是玄学是必须亲手调的三道闸门虚假新闻检测的瓶颈从来不在模型层而在文本到数字的转换过程。MLP 只认 float32 数组而新闻是长短不一、夹杂 emoji、URL、标点混乱的字符串。直接扔进 CountVectorizer90% 的特征维度会被“的”“了”“和”这种停用词霸占模型根本学不到“夸大其词”“无信源引用”“情绪动词堆砌”这类判别信号。所以必须分三步“掐脖子”式控制特征生成2.1 文本清洗删 URL、标准化空格、保留关键标点不要用正则一股脑删所有标点——感叹号“”、问号“”在虚假新闻中高频出现如“震惊99% 人不知道…”是有效信号。真正该删的是完整 URLhttps?://\S→ 替换为URL占位符连续空白符\s→ 统一为单空格全角标点 → 转半角避免“。”和“.”被当不同 token数字统一归一化[0-9]→NUM防止“2023年”和“2024年”割裂语义import re import unicodedata def clean_text(text): # 删除 URL 并替换为占位符 text re.sub(rhttps?://\S, URL, text) # 全角转半角 text unicodedata.normalize(NFKC, text) # 数字归一化 text re.sub(r\d, NUM, text) # 多空格转单空格 text re.sub(r\s, , text).strip() return text # 示例 raw 最新北京地铁惊现神秘生物http://example.com/abc 2023年12月31日 print(clean_text(raw)) # 输出最新北京地铁惊现神秘生物URLNUM年NUM月NUM日提示这步必须在TfidfVectorizer之前做。如果把清洗逻辑塞进 vectorizer 的preprocessor参数后续调试时无法单独 inspect 清洗效果——你得看到中间态文本才能判断是不是误删了关键符号。2.2 TF-IDF 向量化三个必调参数决定模型生死线TfidfVectorizer不是开箱即用的黑盒。以下三个参数必须根据你的数据集手动实验否则 MLP 输入全是噪声参数默认值推荐初值为什么必须调max_featuresNone全量5000防止稀疏矩阵过大导致内存 OOM对 1w 条新闻5000 词已覆盖 95% 信息熵ngram_range(1,1)(1,2)单词级新冠易被绕过加入 bigram新冠 疫苗能捕获组合陷阱min_df12过滤只在 1 条新闻里出现的词如错别字、ID、乱码避免噪声维度from sklearn.feature_extraction.text import TfidfVectorizer vectorizer TfidfVectorizer( max_features5000, ngram_range(1, 2), # 启用 unigram bigram min_df2, # 至少在 2 篇新闻中出现才保留 stop_words[的, 了, 在, 是, 我, 有, 和, 就, 不, 人, 都, 一, 一个, 上, 也, 很, 到, 说, 要, 去, 你, 会, 着, 没有, 看, 好, 自己, 这], # 中文停用词表需自行准备 lowercaseFalse, # 中文无需小写 token_patternr(?u)\b\w\b # 匹配中文字符、英文字母、数字 ) # 拟合并转换训练集 X_train_tfidf vectorizer.fit_transform(train_texts) # shape: (n_samples, 5000) print(fVocab size: {len(vectorizer.vocabulary_)}) # 应 ≈5000 print(fFeature names sample: {list(vectorizer.vocabulary_.keys())[:5]})逻辑说明fit_transform一次性完成词典构建与向量化。vocabulary_字典键是 token值是索引0~4999后续所有文本都按此映射。若len(vocabulary_)明显小于max_features如只有 1200说明min_df2过严或文本太短——此时应降低min_df到 1 并检查是否有大量空行/纯 URL 样本。2.3 特征维度校验用.toarray()看懂稀疏矩阵在“呼吸”TfidfVectorizer输出scipy.sparse.csr_matrix直接 print 只显示形状和非零元素数根本看不出特征质量。必须转成 dense array 抽样 inspect# 取第一条新闻的 TF-IDF 向量转 dense sample_vec X_train_tfidf[0].toarray().flatten() # shape: (5000,) # 找出权重最高的 10 个词 top_indices sample_vec.argsort()[-10:][::-1] feature_names list(vectorizer.vocabulary_.keys()) for idx in top_indices: word feature_names[idx] if idx len(feature_names) else OUT_OF_RANGE print(f{word}: {sample_vec[idx]:.4f})参数说明.toarray()会消耗内存仅用于调试。生产环境必须保持 sparse matrixMLP 训练时自动兼容。若发现 top 词全是“ ”“ ”或停用词漏删说明清洗或 vectorizer 参数有问题——这是后续 MLP 准确率上不去的根源比调 learning_rate 重要十倍。3. MLP 构建与训练Keras 不是唯一选择但tf.keras.Sequential最省心用 PyTorch 写 MLP 对大作业来说是自找麻烦需要手动定义forward()、管理 device、写 train loop。而tf.keras.Sequential一行model.compile()就搞定 optimizer、loss、metrics且与 sklearn pipeline 无缝衔接后续可直接用sklearn.model_selection.cross_val_score。重点不是框架多先进而是让代码在同学电脑上也能跑通——毕竟不是所有人都装了 CUDA。3.1 模型结构设计三层足够第四层是过拟合开关虚假新闻文本特征维度通常在 1000~5000输入层大小即input_dim。经验公式隐藏层 1input_dim * 0.7向下取整隐藏层 2hidden1 * 0.5输出层1sigmoid 二分类例如input_dim5000→hidden13500→hidden21750。但实际中hidden11024、hidden2512更稳——层数越多越容易在小数据集上 overfit。务必加 Dropout 和 BatchNormalizationimport tensorflow as tf from tensorflow import keras from tensorflow.keras import layers def build_mlp(input_dim, dropout_rate0.3, l2_reg1e-4): model keras.Sequential([ layers.Input(shape(input_dim,)), # 输入层shape 必须明确 layers.Dense(1024, activationrelu, kernel_regularizerkeras.regularizers.l2(l2_reg)), layers.BatchNormalization(), layers.Dropout(dropout_rate), layers.Dense(512, activationrelu, kernel_regularizerkeras.regularizers.l2(l2_reg)), layers.BatchNormalization(), layers.Dropout(dropout_rate), layers.Dense(1, activationsigmoid) # 二分类输出 ]) return model # 实例化模型 mlp_model build_mlp(input_dimX_train_tfidf.shape[1]) mlp_model.compile( optimizerkeras.optimizers.Adam(learning_rate0.001), lossbinary_crossentropy, metrics[accuracy] )逻辑说明kernel_regularizerl2(l2_reg)防止权重爆炸Dropout(0.3)在训练时随机屏蔽 30% 神经元BatchNormalization加速收敛并提升泛化。learning_rate0.001是 Adam 的安全起点若 loss 下降慢可试0.002若震荡剧烈降为0.0005。3.2 训练配置早停不是可选是防止“同学跑 200 epoch 还没停”的救命绳虚假新闻数据集通常 ≤10k 样本MLP 很快过拟合。必须用EarlyStopping监控验证集 lossfrom tensorflow.keras.callbacks import EarlyStopping, ReduceLROnPlateau callbacks [ EarlyStopping( monitorval_loss, # 监控验证集 loss patience10, # 连续 10 epoch 无改善则停止 restore_best_weightsTrue # 恢复最优权重不是最后权重 ), ReduceLROnPlateau( monitorval_loss, factor0.5, # loss 不降时lr 减半 patience5, min_lr1e-7 ) ] history mlp_model.fit( X_train_tfidf, y_train, batch_size64, epochs100, # 设上限靠 early stopping 实际终止 validation_split0.2, # 自动划分 20% 验证集 callbackscallbacks, verbose1 # 显示进度条 )参数说明validation_split0.2比手动train_test_split更省事且保证每次 fit 都用相同验证集。restore_best_weightsTrue关键——否则模型保存的是最后 epoch 的权重可能已是过拟合状态。verbose1便于观察 loss 是否稳定下降若第 1 个 epochval_loss就比loss高很多说明数据泄露或清洗有问题。3.3 模型保存与加载.h5格式最兼容别碰.keras虽然 Keras 新版推荐.keras格式但大作业提交时同学用旧版 TensorFlow如 2.8可能打不开。保险做法是存为 HDF5# 保存完整模型含架构、权重、optimizer 状态 mlp_model.save(mlp_fakenews_detector.h5) # 加载模型无需重新 build loaded_model keras.models.load_model(mlp_fakenews_detector.h5) # 验证加载后预测一致 pred_orig mlp_model.predict(X_test_tfidf[:3]) pred_load loaded_model.predict(X_test_tfidf[:3]) print(np.allclose(pred_orig, pred_load)) # 应输出 True注意.h5文件包含全部信息直接load_model即可预测无需compile()。但若要继续训练需重新compile因 optimizer 状态不保存在.h5中。4. 避坑指南90% 的“模型不准”问题其实卡在数据预处理和评估方式学生交大作业最常翻车的不是模型写错而是用训练集的vectorizer去 transform 测试集却忘了fit_transform只能用在训练集评估时用 accuracy 当唯一指标而虚假新闻数据天然不平衡假新闻可能只占 20%把predict()输出的概率直接当标签却不设阈值。以下是血泪经验总结的 4 条硬核避坑4.1 现象测试集预测全是 0 或全是 1原因TfidfVectorizer未正确复用——在测试集上用了fit_transform而非transform导致测试集词汇表与训练集不一致向量全零。解决严格区分fit_transform仅训练集和transform训练/测试/新文本均用# ✅ 正确训练集拟合 转换测试集仅转换 X_train_tfidf vectorizer.fit_transform(train_texts) # fit transform X_test_tfidf vectorizer.transform(test_texts) # transform only! # ❌ 错误测试集也 fit_transform → 词汇表错乱 X_test_tfidf vectorizer.fit_transform(test_texts) # 绝对禁止4.2 现象验证集 loss 持续上升但 accuracy 还在涨原因类别不平衡如假新闻仅 15%模型学会“全预测真”就能得 85% accuracy但实际毫无判别力。解决改用f1-score或balanced_accuracy作为早停监控指标并在model.compile中加class_weightfrom sklearn.utils.class_weight import compute_class_weight # 计算类别权重假新闻样本少权重更高 classes np.unique(y_train) class_weights compute_class_weight(balanced, classesclasses, yy_train) class_weight_dict dict(enumerate(class_weights)) # 训练时传入 history mlp_model.fit( X_train_tfidf, y_train, class_weightclass_weight_dict, # 关键 ... )4.3 现象predict()输出概率但报告要求“真/假”标签原因model.predict()返回 [0.002, 0.998, 0.015...]直接np.argmax会出错二分类输出是 1 维不是 2 维。解决用阈值0.5二值化或更优地用predict_classes()TF 2.10-或np.where# ✅ 安全做法兼容所有版本 y_pred_proba mlp_model.predict(X_test_tfidf) y_pred (y_pred_proba 0.5).astype(int).flatten() # 得到 0/1 数组 # ✅ 更灵活用 ROC 曲线选最优阈值见第 5 章 from sklearn.metrics import roc_curve fpr, tpr, thresholds roc_curve(y_test, y_pred_proba) optimal_idx np.argmax(tpr - fpr) # Youdens J statistic optimal_threshold thresholds[optimal_idx] y_pred_opt (y_pred_proba optimal_threshold).astype(int).flatten()4.4 现象本地跑通但老师电脑报ModuleNotFoundError: No module named tensorflow原因未提供requirements.txt或用了tf-nightly等不稳定版本。解决固定版本 一键安装# 生成当前环境依赖排除 dev 包 pip freeze --exclude-editable requirements.txt # 要求文件内容示例必须指定 patch 版本 numpy1.23.5 pandas1.5.3 scikit-learn1.2.2 tensorflow2.12.0 # 避免 2.13 的 CUDA 11.8 依赖提示在文档说明中明确写出“请用pip install -r requirements.txt安装勿用 conda”。conda 安装 tensorflow 常因 channel 源不同导致版本错乱。5. 部署级验证用混淆矩阵 ROC 曲线把“准确率 85%”变成可信结论交大作业不能只扔个accuracy_score就完事。老师会问“假新闻漏检率多少”“真新闻误杀率多少”——这需要混淆矩阵Confusion Matrix和 ROC 曲线。它们不增加代码量但能让报告瞬间专业 3 个档次。5.1 混淆矩阵四格表里藏着所有真相sklearn.metrics.confusion_matrix输出 2x2 矩阵但 raw 数字难读。必须用seaborn.heatmap可视化并标注 recall/precisionfrom sklearn.metrics import confusion_matrix, classification_report, roc_curve, auc import seaborn as sns import matplotlib.pyplot as plt # 获取预测标签用最优阈值 y_pred (mlp_model.predict(X_test_tfidf) 0.5).astype(int).flatten() # 绘制混淆矩阵 cm confusion_matrix(y_test, y_pred) plt.figure(figsize(6, 5)) sns.heatmap(cm, annotTrue, fmtd, cmapBlues, xticklabels[Predicted Real, Predicted Fake], yticklabels[Actual Real, Actual Fake]) plt.title(Confusion Matrix) plt.ylabel(Actual) plt.xlabel(Predicted) plt.show() # 打印详细报告含 precision/recall/f1 print(classification_report(y_test, y_pred, target_names[Real News, Fake News]))关键解读Recall查全率所有假新闻中模型抓出了百分之几老师最关心“漏掉多少假新闻”Precision查准率模型标为“假”的新闻里真有百分之几是假的影响人工复核成本若 recall0.6precision0.8 → 模型抓得准但漏得多若 recall0.9precision0.4 → 抓得多但误伤严重。二者需权衡。5.2 ROC 曲线找到属于你数据集的最优阈值Accuracy 固定阈值 0.5但虚假新闻场景中我们往往愿牺牲部分 precision 换更高 recall宁可多审几条也不能放走一条谣言。ROC 曲线就是干这个的# 计算 ROC 曲线 y_pred_proba mlp_model.predict(X_test_tfidf).flatten() fpr, tpr, thresholds roc_curve(y_test, y_pred_proba) roc_auc auc(fpr, tpr) # 绘制 plt.figure(figsize(6, 6)) plt.plot(fpr, tpr, colordarkorange, lw2, labelfROC curve (AUC {roc_auc:.3f})) plt.plot([0, 1], [0, 1], colornavy, lw2, linestyle--) plt.xlim([0.0, 1.0]) plt.ylim([0.0, 1.05]) plt.xlabel(False Positive Rate) plt.ylabel(True Positive Rate) plt.title(ROC Curve) plt.legend(loclower right) plt.grid(True) plt.show() # 找最优阈值Youdens J sensitivity specificity - 1 j_scores tpr - fpr optimal_idx np.argmax(j_scores) optimal_threshold thresholds[optimal_idx] print(fOptimal threshold: {optimal_threshold:.3f})参数说明auc值越接近 1.0 越好0.5 是随机猜测。optimal_threshold是使tpr-fpr最大的点平衡漏检与误杀。例如optimal_threshold0.32意味着把预测概率 0.32 的都标为假新闻比默认 0.5 更激进——这正是业务场景需要的灵活性。5.3 文档说明的核心技巧用“可复现命令”代替“请安装环境”我在帮学弟改大作业时发现90% 的文档失败源于“安装说明”写成散文。正确写法是运行前必做三件事解压大作业基于Python和MLP实现的互联网虚假新闻检测器源码文档说明.zip进入解压目录执行python -m venv env source env/bin/activate # Linux/Mac # 或 Windows: python -m venv env env\Scripts\activate.bat pip install -r requirements.txt下载数据集示例用 FakeNewsNetwget https://github.com/KaiDMML/FakeNewsNet/archive/refs/heads/master.zip unzip master.zip mv FakeNewsNet-master/data/politifact/real/ ./data/real/ # 其他路径同理文档中给出完整 mkdir cp 命令最后一句我想说当年我第一次交这个作业因为没画 ROC 曲线被老师问“你确定这个 82% 准确率不是靠猜出来的”当场脸红。后来养成习惯——只要模型输出概率必画 ROC只要文本进模型必打印vectorizer.vocabulary_前 10 个词。这些动作不花时间但让每一次调试都有依据而不是靠玄学调参。希望帮到你。本文还有配套的精品资源点击获取