简介:一份围绕中文谣言检测的本科毕业设计完整资料,面向自然语言处理、机器学习方向的毕设学生与研究者。压缩包以论文配套代码为核心,覆盖从微博等平台数据爬取、预处理、分词、停用词过滤,到TF-IDF特征构建及逻辑回归、聚类、最终分类模型训练的完整流程。研究同时涉及谣言演化分析、实时检测机制与人工+自动应对策略,可帮助读者复现实验并理解中文谣言识别的关键环节。

整包共26个文件,含12个Python脚本、9个txt词典与中间结果、4个json数据集和1个readme说明文档,仅4.93MB,目录按数据处理、特征工程、模型训练分阶段编号(如wholeDataProcess、featureProcess、jiebaTM、tfidfTM、logisticFM),便于逐步对照学习。txt/json文件为各阶段提供停用词表、语料与特征数据支撑。

目前已有125人学习下载,对正在做中文谣言检测或其他NLP文本分类课题的本科生、开发者有直接参考价值。

1. 中文谣言检测的第一步:把论文题目翻译成可执行的任务

Chinese Rumor Recognition 对应到本科毕设,通常就是“中文谣言检测”:给一条中文文本,预测它是真实消息还是谣言。每年 GitHub 上都会冒出同名的毕业设计压缩包,里面内容大同小异——一份论文、一份实验代码、一个演示界面。但真正动手复现过的人会承认,这题的难点从来不在模型本身,而在数据标注口径不统一、类别不平衡、短文本噪声大这三件事上。这篇博客按毕设项目最常见的落地路径展开:先想清楚任务边界,再处理数据和特征,然后对比基线与深度模型,最后把评估指标和演示接口做扎实,末尾补几个答辩前真正用得上的技巧。适合正在复现或准备开题的学生,也适合需要把这套流程迁移到内容审核场景的工程师。

2. 中文谣言检测的数据准备:从原始标注到能训练的特征

2.1 常见中文谣言数据集有哪些,读进来要注意什么

做中文谣言检测,第一步是拿到带标签的文本。常见做法是直接用公开的微博谣言数据集,通常包含“真/假”二分类标签和原始微博文本;也有从辟谣平台(如腾讯较真、微博辟谣)抓取整理的三分类数据,标签为“真实/谣言/未证实”。这些数据集在 GitHub 上以 ChineseRumorDataset、微博谣言等关键词可以搜到,格式多为 CSV 或 JSON。

数据集方向 标签体系 文本来源 典型字段 使用注意
微博谣言数据集 真/假 二分类 微博短文本,带话题标签 text、label、转发数、发布时间 需人工复核,存在历史时效性
辟谣平台整理集 真实/谣言/未证实 辟谣栏目长文 title、content、verdict 长文本为主,与微博短文本分布差异大
爬虫自建集 自定义 特定时间窗口的微博 text、举报数、评论内容 标注成本高,批次一致性难控制

读数据时最常见的问题一是编码,二是标签不统一。中文 CSV 用 UTF-8 写、Excel 打开再另存,常变成 GBK,读取时用 encoding="utf-8-sig" 或 gbk 逐个试。标签字段里“谣言”和“假”可能是同一个含义,必须先统一映射:

import pandas as pd

df = pd.read_csv("rumor_data.csv", encoding="utf-8-sig")
df["label"] = df["label"].map({"真": 0, "真实": 0, "假": 1, "谣言": 1})
df = df.dropna(subset=["text"])
df = df.drop_duplicates(subset=["text"])
print(df["label"].value_counts())

这段代码做了三件事:统一二分类标签、剔除空文本、按文本内容去重。去重这一步尤其重要,因为微博谣言数据里大量存在转发的重复文案,不去重会导致训练集和测试集之间有同文重叠,模型表现虚高,答辩时被问到就能直接答出这个坑。做三分类同理,把“未证实”映射成单独的数字即可。建议在论文里单独写一段“数据清洗与标注口径说明”,把每条规则列出来,这比堆模型细节更容易拿分。

2.2 中文文本清洗:为什么先做保守的正则再做分词

中文谣言检测的文本清洗要克制。很多教程上来就删掉所有标点、表情、URL,但对谣言检测这个任务,URL 可以作为信源特征,感叹号数量也能反映情绪强度。我一般只做最小清洗:去掉微博话题标签、@用户、URL,保留中英文、数字和常用标点,再交给分词器。

import re
import jieba

def clean_text(text: str) -> str:
    text = re.sub(r"#.*?#", "", text)                # 去掉 #话题#
    text = re.sub(r"@[\w\u4e00-\u9fa5]+", "", text)  # 去掉 @用户
    text = re.sub(r"https?://\S+", "", text)         # 去掉 URL
    text = re.sub(r"\s+", " ", text)
    return text.strip()

def load_stopwords(path: str) -> set:
    with open(path, encoding="utf-8") as f:
        return {line.strip() for line in f}

def cut_and_filter(text: str, stopwords: set) -> list:
    words = jieba.lcut(text)
    return [w for w in words if w.strip() and w not in stopwords and len(w) > 1]

这里用 jieba.lcut 而不是 jieba.cut ,前者直接返回 list,省一次转换。停用词表网上有现成的中文停用词表,我通常再手动追加“转发、分享、链接”这类对谣言判断无意义的词。 len(w) > 1 会滤掉单字,但对“假、真、毒”这类单字情感词可能误伤,所以如果你的数据里单字词占比高,这一步可以取消。

分词结果建议直接落盘成中间文件,比如 train_seg.txt ,每行一条文本的空格分词结果。这样一来,后面切 TF-IDF、Word2Vec、TextCNN 用的是同一份预处理结果,不会因为改了某个环节导致三套特征对不上。

2.3 特征表示:TF-IDF、Word2Vec 和预训练向量怎么搭

特征通常备三套:TF-IDF 适合传统模型,Word2Vec 是深度模型的输入,预训练词向量或 BERT tokenizer 输出是加分项。TF-IDF 用 sklearn 一行搞定,关键是参数:

from sklearn.feature_extraction.text import TfidfVectorizer

seg_train = [" ".join(words) for words in train_corpus]
vectorizer = TfidfVectorizer(
    max_features=50000,
    ngram_range=(1, 2),
    min_df=2,
    max_df=0.9,
    sublinear_tf=True,
)
X_train = vectorizer.fit_transform(seg_train)

参数说明: max_features=50000 限制特征维度,防止大词表把内存撑爆; ngram_range=(1,2) 让“不是/谣言”这类双词组合也能进入特征空间,对否定句极其关键; min_df=2 去掉只出现一次的单词; max_df=0.9 去掉出现在 90% 文本里的高频噪声词; sublinear_tf=True 用 1+log(tf) 代替原始词频,削弱长文本里高频词的压制。测试集只调用 vectorizer.transform ,绝不重新 fit,这是最常犯的泄漏错误。

Word2Vec 用 gensim 在训练集上自己训:

from gensim.models import Word2Vec

sentences = [cut_and_filter(clean_text(t), stopwords) for t in train_texts]
w2v = Word2Vec(sentences, vector_size=200, window=5, min_count=2, sg=0, epochs=10)

sg=0 表示 CBOW,小数据量下更快更稳; sg=1 是 skip-gram,对低频词更友好。毕设数据量通常只有几万条,用 CBOW 加 epochs=10 就够。训练好的向量喂给 TextCNN 时,记得把 Embedding 层初始化为 w2v.wv.vectors ,先在冻结状态下训几轮,再解冻微调。

3. 中文谣言检测的模型取舍:基线、深度模型与 BERT 微调

3.1 用逻辑回归和 SVM 快速建立基线

拿到 TF-IDF 特征后,先不要急着上深度学习。逻辑回归在中文谣言这种短文本分类上通常已经能拿到可用的 macro-F1,而且可解释性强,能把“哪些词让模型判定为谣言”直接写成答辩材料。建基线用 Pipeline 一步到位:

from sklearn.pipeline import Pipeline
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import train_test_split

X_train, X_test, y_train, y_test = train_test_split(
    seg_data, y_data, test_size=0.2, random_state=42, stratify=y_data
)

pipe = Pipeline([
    ("tfidf", TfidfVectorizer(max_features=50000, ngram_range=(1, 2), min_df=2, sublinear_tf=True)),
    ("clf", LogisticRegression(C=1.0, class_weight="balanced", max_iter=2000)),
])
pipe.fit(X_train, y_train)

class_weight="balanced" 让模型按类别频率反向加权,缓解谣言样本占比低的问题; C=1.0 是默认正则强度,先跑通再在 [0.1, 1, 10] 上网格搜索。逻辑回归的好处是能直接看特征系数:

import numpy as np

coef = pipe.named_steps["clf"].coef_[0]
top_idx = np.argsort(coef)[-15:]
words = pipe.named_steps["tfidf"].get_feature_names_out()[top_idx]
print(list(zip(words, coef[top_idx])))

输出里排在前面的一般是“转发、速看、真相、扩散”这类词。把这些词挑进论文的案例分析段,比单纯贴准确率数字更有说服力。SVM 可以替换分类器做对照,线性核 SVC(kernel="linear") 效果和逻辑回归接近、训练更慢,但有些评审默认“SVM 是经典方法”,放一个对比表即可。

3.2 TextCNN 和 BiLSTM 怎么搭、超参数怎么定

深度模型里 TextCNN 是中文谣言检测最常用的结构:用多个不同宽度的卷积核并行提取局部 n-gram 特征,再池化拼接到一起。对短文本来说,TextCNN 的训练速度和稳定性都优于 BiLSTM,是论文里“深度方法”部分的首选。

from tensorflow.keras.layers import Embedding, Conv1D, GlobalMaxPooling1D, Concatenate, Dropout, Dense
from tensorflow.keras.models import Model
from tensorflow.keras import Input

inputs = Input(shape=(max_len,))
embedding = Embedding(vocab_size, 128, mask_zero=True)(inputs)
convs = [
    GlobalMaxPooling1D()(
        Conv1D(64, k, activation="relu", padding="same")(embedding)
    ) for k in (2, 3, 4)
]
x = Concatenate()(convs)
x = Dropout(0.4)(x)
outputs = Dense(2, activation="softmax")(x)
model = Model(inputs, outputs)
model.compile(optimizer="adam", loss="sparse_categorical_crossentropy", metrics=["accuracy"])

kernel_size 取 2、3、4,分别对应短语里的 2-gram 到 4-gram; padding="same" 保证每个卷积输出长度一致,否则短句子的特征在池化层会缩水; GlobalMaxPooling1D 对每个卷积核取最大响应,等价于“这段文本里有没有出现这类谣言模式”。词嵌入用上一节训好的 Word2Vec 初始化,比随机初始化收敛快得多。超参经验值列在下面,毕设阶段不用网格搜索,照抄再微调一两个即可:

超参数 常见取值 影响
embedding_dim 100~300 数据量小就选 100,防止过拟合
卷积核数量 64~128 越大表达能力越强,越容易过拟合
kernel_size (2, 3, 4) 对应 n-gram 窗口,微博短文本用 2-4 即可
max_len 64~128 微博文本平均较短,128 覆盖绝大多数样本
dropout 0.3~0.5 0.5 是谣言数据集上的常见安全值

BiLSTM 只有在加上 attention 或者文本相对较长时才明显比 TextCNN 好。如果论文里必须有两个深度模型做对比,BiLSTM 可以作为“结构不同”的对照组,但不要期待它在微博短文本上碾压 TextCNN,这个结论本身就可以写进实验分析。

3.3 BERT 微调:什么时候值得做,怎么做省钱

把 BERT 微调当作最终对标模型是现在毕设的常见做法。中文谣言检测用 bert-base-chinese 就能拿到不错的结果,如果显卡显存有限,换 hfl/rbt3 这种小模型,精度损失不大,训练时间少一半。

from transformers import AutoTokenizer, AutoModelForSequenceClassification, Trainer, TrainingArguments

ckpt = "hfl/rbt3"
tokenizer = AutoTokenizer.from_pretrained(ckpt)

def encode(example):
    return tokenizer(example["text"], truncation=True, padding="max_length", max_length=128)

train_args = TrainingArguments(
    output_dir="./rbt3_checkpoints",
    learning_rate=2e-5,
    per_device_train_batch_size=32,
    num_train_epochs=3,
    weight_decay=0.01,
    logging_steps=200,
    save_strategy="no",
)
trainer = Trainer(
    model=AutoModelForSequenceClassification.from_pretrained(ckpt, num_labels=2),
    args=train_args,
    train_dataset=train_ds,
    eval_dataset=eval_ds,
)
trainer.train()

max_length=128 在微博短文本场景通常足够,超长文本被截断后信息损失有限,但能显著降低显存占用。学习率 2e-5 是微调常见默认值,不要随便调大,否则会出现 loss 震荡。如果只有 CPU 或显存不足,可以冻结 encoder 只训练分类头,效果比从头跑 TextCNN 略好,训练时间可控。注意训练集和测试集必须在同一批切分数据上生成,避免样本重叠导致测试集虚高。

4. 中文谣言检测的评估与演示:别让准确率骗了你

4.1 用 macro-F1 和混淆矩阵定位模型短板

中文谣言数据集普遍类别不平衡:真实样本和谣言样本比例经常失衡。纯准确率在这种分布下没有意义——如果 70% 是真实消息,一个全部判真的模型准确率就有 70%,但在谣言检测场景等于没做。我一般用 macro-F1 做主指标,再配混淆矩阵看具体错在哪:

from sklearn.metrics import classification_report, confusion_matrix, ConfusionMatrixDisplay
import matplotlib.pyplot as plt

print(classification_report(y_test, y_pred, target_names=["真实", "谣言"]))
cm = confusion_matrix(y_test, y_pred)
ConfusionMatrixDisplay(cm, display_labels=["真实", "谣言"]).plot()
plt.savefig("confusion_matrix.png", dpi=150)

macro-F1 把每个类别的 F1 平均,类别不平衡时比 accuracy 更诚实。看混淆矩阵时重点看两个格子:真实误报成谣言的数量,和谣言漏报成真实的数量。对内容审核场景,漏报比误报代价大,宁可误报多一点;毕设演示时主动说明这个取舍,会让评审觉得你理解业务而不只是会调包。

4.2 三分类“未证实”类别怎么处理

很多公开谣言数据集不止二分类,还有“未证实”这个中间态。毕设里常见两种处理:一是直接删掉未证实样本只做二分类;二是保留三分类,单独报告每个类别的 F1。我建议保留三分类,因为“未证实”本身就是谣言检测场景的重要输出,删掉会浪费信息。

report = classification_report(y_test, y_pred, target_names=["真实", "谣言", "未证实"], output_dict=True)
for cls in ["真实", "谣言", "未证实"]:
    print(cls, "F1 =", round(report[cls]["f1-score"], 4))

三分类时,未证实类别的 F1 通常最低,因为它的边界模糊:一条“传言称”的文本在不同标注者眼里可能是未证实也可能是谣言。论文里要把标注口径写清楚,比如“出现明确否定或官方辟谣的判为真实,出现无来源断言且为负面指向的判为谣言,其余无法判定归属的进入未证实”。口径写清楚后,模型对未证实的识别才有稳定的学习目标。

4.3 用 Flask 和 joblib 把模型封装成可演示接口

毕设答辩时,演示一个 Web 接口比跑一遍 notebook 更有说服力。常见做法是训练完把模型和向量器都存成 joblib,再用 Flask 起一个最小接口:

from flask import Flask, request, jsonify
import joblib

app = Flask(__name__)
pipe = joblib.load("rumor_model.pkl")      # 完整 Pipeline,包含向量器和分类器
stopwords = load_stopwords("stopwords.txt")

@app.route("/predict", methods=["POST"])
def predict():
    data = request.get_json()
    text = clean_text(data.get("text", ""))
    words = cut_and_filter(text, stopwords)
    prob = pipe.predict_proba([" ".join(words)])[0]
    return jsonify({"label": int(prob[1] > 0.5), "rumor_score": round(float(prob[1]), 4)})

if __name__ == "__main__":
    app.run(host="0.0.0.0", port=5000)

predict_proba 返回每个类别的概率,直接取谣言类概率做阈值判断,返回时保留原始分数,方便前端做“绿黄红”三档展示。模型和停用词表在模块加载时一次性读入,不要在每次请求里重新 load,否则并发一上来响应就卡死。启动后用 curl 验证接口:

curl -X POST http://127.0.0.1:5000/predict \
  -H "Content-Type: application/json" \
  -d '{"text": "网传某品牌饮用水检出致癌物,官方尚未回应"}'

返回 {"label":1,"rumor_score":0.93} 就说明链路通了。这里注意用 POST 而不是 GET,避免文本内容进访问日志;线上部署时再加鉴权和限流,毕设演示则不用过度设计。

5. 中文谣言检测落地的三个实用技巧

5.1 用阈值搜索替代默认 0.5

二分类模型默认取 0.5 作为正负类分界,但谣言检测里我更倾向在验证集上做阈值搜索。把验证集上每个候选阈值对应的 F1 算出来,选让 macro-F1 最大的阈值,再灌进接口:

import numpy as np
from sklearn.metrics import f1_score

probs = pipe.predict_proba(X_val)[:, 1]
best_th, best_f1 = 0.5, 0.0
for th in np.arange(0.3, 0.8, 0.05):
    f1 = f1_score(y_val, (probs >= th).astype(int), average="macro")
    if f1 > best_f1:
        best_th, best_f1 = th, f1
print("best threshold", round(best_th, 2), "macro-F1", round(best_f1, 4))

阈值调完后,接口里的判断边界要同步更新,不要模型里一个阈值、演示代码里另一个阈值,这种不一致在答辩时会被一眼看穿。

5.2 给模型补充“立场无关”的辅助特征

纯文本词向量会把“据说”“传”“求证”这类词当成特征,但同样的词在真实新闻里也会出现。常见改进是拼接辅助特征:文本长度、URL 数量、感叹号数量、是否为转发句式。把这些数值特征和文本表征拼起来,再接一个分类层,能明显改善短文本的判别。这在论文里叫“多源特征融合”,是一个成本低、可写深度的加分点。

5.3 用错误样本反推模型弱点,而不是只调超参

训练结束后的第一件事,是把验证集里分错的样本打印出来,按错误类型归类。比如“真实被判为谣言”的样本多是带反问句的澄清帖,“谣言被判为真实”的样本多是伪权威口吻。把归因写进论文的误差分析一节,比盲目调参更有价值。最后一招是数据增强:对谣言句做同义词替换,保持核心实体不变,把训练集扩一到两倍,TextCNN 和 BERT 都能从中受益,但注意增强只作用在训练集上,验证与测试集保持原样。

本文还有配套的精品资源,点击获取 menu-r.4af5f7ec.gif

Logo

聚焦RDK与具身智能,汇集机器人开发教程、开源案例和技术交流

更多推荐