☰
基于TF-IDF与MLP的虚假新闻检测器实战:从数据预处理到模型部署
2026/10/1 16:42:07 网站建设 项目流程

简介:这份资源是面向课程设计与机器学习入门者的互联网虚假新闻检测完整项目,编号100011870,核心是用Python多层感知器(MLP)完成新闻文本的二分类任务。项目覆盖数据预处理、分词与停用词过滤、TF-IDF或词嵌入特征工程、训练验证测试集划分、MLP模型构建与反向传播调优、测试集泛化评估等完整流程,并涉及Numpy、Pandas、Scikit-learn、NLTK、TensorFlow或PyTorch等常用库,适合想理解文本分类全链路的中级学习者。压缩包共19个文件,约66.23MB,包含py训练脚本、model模型文件、csv与pkl数据、xml配置、txt预测输出及docx实验报告,结构清晰便于复现与二次开发。目前已有227人学习下载,可帮助读者快速获得可运行的检测器实现、模型调参思路与实验报告参考。

1. 拆开这个 MLP 虚假新闻检测器:它到底能不能跑通

网上关于虚假新闻检测的项目一抓一大把,但真正能下载下来、解压、装完依赖、跑出准确率数字的没几个。我拿到这个编号 100011870 的压缩包时,第一反应也是先看目录结构——fakenewsdetector、doc report.docx、LICENSE、ML fit.py、dataset、.idea、model、mlp_pred.txt、README.md。有数据集、有训练脚本、有模型目录、有预测输出文件,还有一份 Word 报告,说明这是一个完整的课程设计交付物,不是半成品。

它解决的核心问题很明确:用 Python 的多层感知器(MLP)对新闻文本做二分类,判断一条新闻是真实还是虚假。适合谁?正在做 NLP 课程设计的学生、想快速搭一个文本分类 baseline 的工程师、以及需要理解 TF-IDF + MLP 这套经典组合怎么落地的人。不适合指望开箱即用做生产级检测的人,因为它的定位是教学和实验。

2. 数据预处理与 TF-IDF 特征工程:文本怎么变成 MLP 能吃的数字

2.1 为什么选 TF-IDF 而不是词嵌入

这个项目用的是 TF-IDF 向量化,不是 Word2Vec 或 BERT 词嵌入。原因很实际:MLP 是浅层前馈网络,参数量有限,TF-IDF 产生的是稀疏高维向量,配合全连接层做分类在中小规模数据集上效果稳定,训练速度快,不需要 GPU。词嵌入虽然语义表达更强,但需要额外训练或加载预训练模型,对课程设计来说引入的复杂度不划算。

常见做法是先用TfidfVectorizer把文本转成矩阵,再喂给 MLP。这里有个关键参数max_features,控制词汇表大小。设太大,特征维度爆炸,训练慢且容易过拟合;设太小,信息丢失严重。我一般会从 5000 开始试,看验证集准确率再调。

2.2 文本清洗与分词的可复现步骤

原始新闻文本里混着 HTML 标签、URL、标点、数字,这些对分类基本是噪声。下面是我按这个项目的数据特点写的预处理脚本,可以直接抄:

import re import pandas as pd from sklearn.feature_extraction.text import TfidfVectorizer def clean_text(text): # 去掉 HTML 标签 text = re.sub(r'<.*?>', '', text) # 去掉 URL text = re.sub(r'http\S+|www\S+', '', text) # 只保留字母和空格 text = re.sub(r'[^a-zA-Z\s]', '', text) # 转小写 text = text.lower() # 去掉多余空白 text = re.sub(r'\s+', ' ', text).strip() return text # 假设 dataset 目录下有一个 CSV,列名为 text 和 label df = pd.read_csv('dataset/news.csv') df['clean'] = df['text'].apply(clean_text) # TF-IDF 向量化 vectorizer = TfidfVectorizer(max_features=5000, stop_words='english') X = vectorizer.fit_transform(df['clean']) y = df['label'].values

逻辑说明:clean_text函数按顺序去 HTML、去 URL、去非字母字符、转小写、压缩空白。顺序不能乱,先去标签再去 URL,否则 URL 里的斜杠和点会被后面的正则误伤。TfidfVectorizer的max_features=5000是经验起点,stop_words='english'去掉英文停用词。如果你的数据集是中文新闻,需要换成 jieba 分词加中文停用词表,TfidfVectorizer的tokenizer参数要指定 jieba 的cut函数。

参数怎么改:max_features从 3000 到 10000 之间调,看验证集表现;ngram_range可以设成(1,2)捕捉二元词组,但维度会翻倍,慎用。

3. MLP 模型构建与训练:层数、激活函数、优化器怎么定

3.1 网络结构设计的取舍

这个项目的 MLP 结构不复杂,输入层维度等于 TF-IDF 特征数(比如 5000),然后接一到两个隐藏层,最后输出层用 sigmoid 做二分类。隐藏层激活函数用 ReLU,因为它在深层网络中梯度消失问题比 sigmoid 小,计算也快。

隐藏层节点数怎么定?常见做法是第一层设 256 或 512,第二层减半。比如 5000 → 256 → 64 → 1。层数不是越多越好,两层隐藏层对文本分类已经够用,再加层参数量上去但收益递减,还容易过拟合。

3.2 训练脚本与关键参数

下面是一个基于 Keras 的 MLP 训练脚本,对应项目里的ML fit.py思路:

import numpy as np from sklearn.model_selection import train_test_split from tensorflow.keras.models import Sequential from tensorflow.keras.layers import Dense, Dropout from tensorflow.keras.optimizers import Adam # 划分训练集和测试集,70/15/15 的思路这里简化为 85/15 X_train, X_test, y_train, y_test = train_test_split( X, y, test_size=0.15, random_state=42 ) # 构建 MLP model = Sequential([ Dense(256, activation='relu', input_shape=(X_train.shape[1],)), Dropout(0.3), Dense(64, activation='relu'), Dropout(0.2), Dense(1, activation='sigmoid') ]) model.compile( optimizer=Adam(learning_rate=0.001), loss='binary_crossentropy', metrics=['accuracy'] ) history = model.fit( X_train.toarray(), y_train, epochs=20, batch_size=32, validation_split=0.15, verbose=1 ) # 保存模型 model.save('model/mlp_model.h5')

逻辑说明:Dropout层放在隐藏层后面,训练时随机丢弃一部分神经元,防止过拟合。Adam优化器学习率设 0.001 是默认值,如果 loss 震荡大就降到 0.0005。batch_size=32是常见起点,数据量小可以降到 16,数据量大可以升到 64。epochs=20配合validation_split看验证 loss 什么时候不再下降,早停可以加EarlyStopping回调。

注意:X_train.toarray()是因为 TF-IDF 输出的是稀疏矩阵,Keras 的fit不直接吃稀疏矩阵,要先转稠密。如果特征维度 5000 以上,转稠密后内存占用会很大,这时候要么减小max_features,要么改用SparseTensor输入。

参数怎么改:隐藏层节点数从 256 开始,加到 512 看验证准确率有没有提升;Dropout率从 0.3 开始,过拟合严重就加到 0.5,欠拟合就降到 0.2。

4. 模型评估与预测输出:准确率之外还要看什么

4.1 评估指标的选择

训练完模型,model.evaluate给出的是准确率。但虚假新闻检测是个二分类问题,准确率在类别不平衡时会骗人。比如 90% 是真实新闻,模型全猜真实也有 90% 准确率,但虚假新闻一条都抓不到。所以要看 precision、recall 和 F1。

from sklearn.metrics import classification_report, confusion_matrix y_pred = (model.predict(X_test.toarray()) > 0.5).astype(int) print(confusion_matrix(y_test, y_pred)) print(classification_report(y_test, y_pred))

confusion_matrix看假阳性和假阴性各多少,classification_report看每类的 precision 和 recall。如果虚假新闻的 recall 低,说明模型漏检多,需要调整分类阈值或者对少数类过采样。

4.2 预测输出文件 mlp_pred.txt 的生成

项目里有个mlp_pred.txt,应该是模型对测试集的预测结果。生成方式:

predictions = model.predict(X_test.toarray()) with open('mlp_pred.txt', 'w') as f: for pred, true in zip(predictions, y_test): label = 'fake' if pred > 0.5 else 'real' f.write(f'{label}\n')

这个文件可以用来做后续分析,比如找出模型预测置信度低的样本,人工检查是不是标注错了。

5. 避坑与常见问题:跑不通的时候先查这几条

5.1 依赖版本不匹配导致 import 报错

现象:import tensorflow报ModuleNotFoundError或者版本冲突。原因:项目没有requirements.txt,不同版本的 TensorFlow API 有差异,比如tf.keras和独立keras的导入路径不同。解决:装 TensorFlow 2.x 的稳定版,pip install tensorflow==2.13.0,然后确认from tensorflow.keras.models import Sequential能正常导入。如果用的是 PyTorch 版本,检查torch和torchvision版本对应关系。

5.2 TF-IDF 矩阵转稠密时内存溢出

现象:X_train.toarray()执行时进程被 kill 或者报MemoryError。原因:max_features设太大,比如 50000,训练集几万条,转稠密后矩阵占几个 G。解决:把max_features降到 5000 以内,或者用SparseTensor输入。Keras 可以用tf.sparse.SparseTensor包装稀疏矩阵,但需要自定义输入层。

5.3 验证集准确率不动或者震荡

现象:训练几个 epoch 后验证准确率卡在 50% 左右,或者上下大幅跳动。原因:学习率太大导致梯度爆炸,或者数据没有打乱,或者标签编码有问题。解决:先把学习率降到 0.0001 试;检查train_test_split有没有设random_state保证可复现;确认标签是 0 和 1 而不是字符串,如果是字符串要用LabelEncoder转。

5.4 中文新闻数据集分词缺失

现象:如果数据集是中文,直接用TfidfVectorizer默认分词会把整句话当一个 token,特征毫无意义。原因:TfidfVectorizer默认按空格分词,中文没有空格。解决:用 jieba 分词,TfidfVectorizer(tokenizer=jieba.cut),同时把stop_words换成中文停用词表。注意 jieba 分词后要去掉单字和标点。

5.5 模型保存后加载预测结果不一致

现象:训练时准确率 90%,保存模型再加载预测,准确率掉到 70%。原因:保存模型时没有保存 TF-IDF 的vectorizer,加载后用了新的vectorizer导致特征空间不一致。解决:用joblib把vectorizer一起保存,预测时先加载vectorizer再transform新文本。

import joblib joblib.dump(vectorizer, 'model/tfidf_vectorizer.pkl') # 加载时 vectorizer = joblib.load('model/tfidf_vectorizer.pkl') X_new = vectorizer.transform(new_texts)

6. 进阶技巧:把 MLP 检测器接成可调用的预测函数

课程设计交完不是终点,把这个模型封装成一个能接收任意新闻文本、返回真假判断的函数,才算真正跑通。下面是我常用的封装方式,顺便把置信度也带出来:

import joblib import re import numpy as np from tensorflow.keras.models import load_model class FakeNewsDetector: def __init__(self, model_path, vectorizer_path): self.model = load_model(model_path) self.vectorizer = joblib.load(vectorizer_path) def _clean(self, text): text = re.sub(r'<.*?>', '', text) text = re.sub(r'http\S+|www\S+', '', text) text = re.sub(r'[^a-zA-Z\s]', '', text) return re.sub(r'\s+', ' ', text).lower().strip() def predict(self, text): cleaned = self._clean(text) vec = self.vectorizer.transform([cleaned]).toarray() prob = self.model.predict(vec, verbose=0)[0][0] label = 'fake' if prob > 0.5 else 'real' confidence = prob if prob > 0.5 else 1 - prob return {'label': label, 'confidence': round(float(confidence), 4)} # 使用 detector = FakeNewsDetector('model/mlp_model.h5', 'model/tfidf_vectorizer.pkl') result = detector.predict("Breaking: scientists discover new planet") print(result)

这个封装做了三件事:把清洗逻辑内聚到类里,避免每次调用都手动预处理;把vectorizer和模型绑定,保证特征空间一致;输出置信度,方便设置阈值过滤低置信样本。置信度低于 0.6 的样本我一般会标记出来人工复核,因为 MLP 在边界样本上容易摇摆。

阈值怎么调:默认 0.5,如果虚假新闻漏检多就降到 0.4,如果误报多就升到 0.6。调阈值比重新训练模型快得多,先用验证集画一条 precision-recall 曲线,找到 F1 最大的那个点。

还有一个实用技巧:把mlp_pred.txt里的预测结果和原始文本对照,找出模型预测错但置信度很高的样本,这些往往是标注噪声。我上次跑一个类似项目,发现十几条标为 fake 的新闻其实是 real,清理后验证准确率涨了 3 个点。从那以后我每次训练完都强制走一遍「高置信错误样本检查」,比调参管用。希望帮到你。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询