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

简介:该语料库由复旦大学提供,包含4902个训练文档和4902个测试文档,共9833篇中文文本,覆盖新闻、娱乐、科技、体育等20个类别,适用于构建和评估文本分类模型。文本分类是自然语言处理的重要任务,广泛应用于新闻分类、情感分析、垃圾邮件过滤和社交媒体监控。本数据集支持多种主流分类算法,如朴素贝叶斯、SVM、CNN、LSTM,以及BERT、RoBERTa等预训练模型的微调与测试,有助于提升模型的泛化能力与实际应用效果。
(中文)文本分类语料(复旦)训练集+测试集.rar

1. 中文文本分类任务概述

文本分类是自然语言处理(NLP)领域中最基础且应用广泛的任务之一。其核心目标是将一段给定的文本自动分配到一个或多个预定义的类别中。在中文环境下,由于语言本身的复杂性,如缺乏自然分隔符、语义模糊、歧义性强等问题,使得文本分类任务更具挑战性。

1.1 文本分类的基本概念

文本分类(Text Classification)是指根据文本内容,自动判断其所属类别的过程。通常,它是一个监督学习任务,依赖于标注好的训练数据。基本流程如下:

  1. 文本预处理 :包括分词、去除停用词、标准化等。
  2. 特征提取 :将文本转化为数值向量,如TF-IDF、词袋模型或词嵌入。
  3. 模型训练 :使用分类算法(如朴素贝叶斯、SVM、CNN等)进行训练。
  4. 分类预测 :对新文本进行类别预测。

例如,使用Scikit-learn进行简单的文本分类流程如下:

from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.naive_bayes import MultinomialNB
from sklearn.pipeline import make_pipeline

# 假设有训练文本和标签
texts = ["这部电影太棒了", "非常失望,内容很烂", ...]
labels = ["正面", "负面", ...]

# 构建分类模型管道
model = make_pipeline(TfidfVectorizer(), MultinomialNB())

# 模型训练
model.fit(texts, labels)

# 预测新文本
new_text = ["剧情紧凑,演员演技出色"]
print(model.predict(new_text))  # 输出:['正面']

代码说明:

  • TfidfVectorizer() :将文本转换为TF-IDF特征向量;
  • MultinomialNB() :多项式朴素贝叶斯分类器;
  • make_pipeline() :构建特征提取与分类的流水线;
  • fit() :训练模型;
  • predict() :预测新文本的类别。

1.2 应用场景

中文文本分类广泛应用于以下领域:

  • 情感分析 :判断评论是正面还是负面;
  • 新闻分类 :将新闻文章归类到体育、科技、财经等类别;
  • 垃圾邮件过滤 :识别邮件是否为垃圾邮件;
  • 法律文书分类 :自动归档不同类型的法律文件;
  • 智能客服 :理解用户意图并自动分类问题类型。

这些应用场景对模型的准确率、效率、可解释性都有不同的要求,因此在选择模型和特征表示时需要综合考虑。

1.3 中文分类的主要难点与解决方案

主要难点:

  1. 歧义性强 :中文没有空格分隔,需依赖分词技术,但分词本身存在歧义;
  2. 语义模糊 :同一句话可能表达多种含义;
  3. 词汇多样性 :同义词、近义词丰富,需语义层面理解;
  4. 噪声干扰 :网络文本中存在大量错别字、表情符号、缩写等;
  5. 类别不平衡 :某些类别样本稀少,影响模型训练效果。

常见解决方案:

  • 分词优化 :采用如jieba、THULAC等高效中文分词工具;
  • 语义建模 :使用词向量(如Word2Vec、GloVe、BERT)提升语义理解;
  • 特征选择 :通过TF-IDF、卡方检验、互信息等方法提取关键特征;
  • 数据增强 :对小样本类别进行数据扩充;
  • 模型调优 :引入深度学习模型(如CNN、RNN、Transformer)提升分类效果;
  • 集成学习 :结合多个模型提升整体性能。

本章为后续章节打下理论基础,接下来将深入复旦大学语料库的结构与预处理方法。

2. 复旦大学语料库结构说明

复旦大学中文语料库是中国自然语言处理领域的重要资源之一,广泛应用于文本分类、情感分析、信息检索等多个研究方向。本章将围绕该语料库的结构、内容特征以及预处理方法展开详细解析,帮助读者理解其组织方式、统计特征以及在实际应用中的处理流程。

2.1 语料库的基本组成

复旦大学语料库通常以文件夹和文件的形式进行组织,具有清晰的层级结构和命名规范。这种结构不仅便于数据管理,也为后续的数据加载和处理提供了便利。

2.1.1 数据目录结构

语料库的主目录通常包含多个子文件夹,每个子文件夹代表一个类别,例如“体育”、“科技”、“财经”等。每个类别文件夹下存放若干文本文件,每条文本文件对应一篇文档。这种结构体现了典型的监督学习数据组织方式。

corpus/
├── 体育/
│   ├── 1.txt
│   ├── 2.txt
│   └── ...
├── 科技/
│   ├── 1.txt
│   ├── 2.txt
│   └── ...
├── 财经/
│   ├── 1.txt
│   ├── 2.txt
│   └── ...
└── ...

这种结构设计使得数据读取和标签对应变得非常直观,便于构建数据集和标签映射关系。

2.1.2 文件命名规则

语料库中的文本文件通常采用统一的命名方式,如“1.txt”、“2.txt”等。虽然文件名本身不携带语义信息,但结合文件夹的类别标签,可以构建完整的训练样本。

例如, 科技/3.txt 表示科技类的第3篇文档。这种命名方式有助于程序批量读取文件并自动打标签。

2.1.3 数据格式与编码规范

语料库中的文本文件一般采用 UTF-8 编码格式存储,确保中文字符的正确显示。文件内容为纯文本,通常不包含 HTML 标签、特殊符号或格式化内容。

示例文本内容:

近年来,人工智能技术取得了飞速发展,尤其是在图像识别和自然语言处理领域。复旦大学的研究团队也在不断探索深度学习在文本分类中的应用。

参数说明:
- 编码格式 :UTF-8,避免乱码问题;
- 文本内容 :无格式纯文本,便于后续分词与向量化处理;
- 语言种类 :主要为简体中文,部分可能包含繁体或方言,需额外处理。

2.2 语料内容特征分析

为了更好地理解语料库的统计特性,我们需要从文本长度、词汇分布、标签平衡性等方面进行分析。这些特征将直接影响模型的选择和训练策略。

2.2.1 语料的文本长度分布

文本长度对分类模型的影响较大。过长文本可能引入噪声,而过短文本则可能信息不足。我们可以使用 Python 统计每个类别的平均文本长度。

import os

def get_avg_length(category_path):
    total_len = 0
    file_count = 0
    for filename in os.listdir(category_path):
        with open(os.path.join(category_path, filename), 'r', encoding='utf-8') as f:
            content = f.read()
            total_len += len(content)
            file_count += 1
    return total_len / file_count if file_count > 0 else 0

categories = ['体育', '科技', '财经', '娱乐', '军事']
corpus_path = 'corpus/'

lengths = {cat: get_avg_length(os.path.join(corpus_path, cat)) for cat in categories}

代码解释:
- get_avg_length 函数计算指定类别目录下所有文本的平均字符数;
- 遍历每个类别文件夹,读取文件内容,统计字符长度;
- 返回每个类别的平均长度,用于后续分析。

输出结果示例:

类别 平均文本长度(字符数)
体育 1520
科技 1780
财经 1650
娱乐 1420
军事 1800

从表中可以看出,不同类别的文本长度存在差异,这对后续的文本预处理(如截断或填充)提出了要求。

2.2.2 常见词汇与停用词统计

通过对所有文本进行词频统计,可以提取高频词,进而识别停用词并进行过滤。停用词如“的”、“了”、“是”等常见词汇通常对分类无帮助,应予以去除。

from collections import Counter
import jieba

def build_vocab(corpus_path, categories):
    vocab = Counter()
    for cat in categories:
        cat_path = os.path.join(corpus_path, cat)
        for filename in os.listdir(cat_path):
            with open(os.path.join(cat_path, filename), 'r', encoding='utf-8') as f:
                content = f.read()
                words = jieba.cut(content)
                vocab.update(words)
    return vocab

vocab = build_vocab(corpus_path, categories)
print(vocab.most_common(20))

代码解释:
- 使用 jieba 进行中文分词;
- 统计所有文本的词频;
- 输出前20个高频词。

输出示例:

[('的', 12034), ('是', 9823), ('了', 8754), ('在', 7653), ('和', 6543), 
 ('一', 5432), ('我们', 4321), ('也', 4210), ('有', 4109), ('人', 3987),
 ('他们', 3876), ('中国', 3765), ('这个', 3654), ('可以', 3543), ('不', 3432),
 ('中', 3321), ('互联网', 3210), ('发展', 3109), ('技术', 3098), ('信息', 2987)]

分析说明:
- 前几项“的”、“是”、“了”等属于典型停用词;
- 后续“互联网”、“技术”、“发展”等则可能是具有语义区分能力的关键词;
- 建议构建停用词表,剔除高频无意义词。

2.2.3 标签分布与数据平衡性分析

类别分布的平衡性直接影响模型的训练效果。如果某些类别样本过多,模型可能偏向预测这些类别。

import matplotlib.pyplot as plt

def count_samples(corpus_path, categories):
    return {cat: len(os.listdir(os.path.join(corpus_path, cat))) for cat in categories}

sample_counts = count_samples(corpus_path, categories)

plt.bar(sample_counts.keys(), sample_counts.values())
plt.title('类别样本数量分布')
plt.xlabel('类别')
plt.ylabel('样本数量')
plt.show()

代码解释:
- 遍历每个类别目录,统计文件数量;
- 使用 matplotlib 绘制柱状图展示分布;
- 观察是否存在类别不平衡现象。

输出示例图表:
(此处可插入实际绘制的柱状图)

分析说明:
- 如果某一类样本远多于其他类(如“科技”类样本是“娱乐”的3倍),则需要考虑采样策略;
- 可采用上采样、下采样或加权损失函数等方式缓解不平衡问题。

2.3 语料预处理方法

预处理是文本分类任务中不可或缺的一环,包括分词、去除停用词、向量化等步骤。

2.3.1 分词与词性标注

中文文本需要先进行分词,才能被模型处理。常用的中文分词工具包括 jieba HanLP THULAC 等。

import jieba.posseg as pseg

text = "近年来,人工智能技术取得了飞速发展"
words = pseg.cut(text)
for word, flag in words:
    print(f'{word}({flag})', end=' ')

输出结果:

近年来(d) ,(x) 人工智能(nz) 技术(n) 取得(v) 了(u) 飞速(ad) 发展(vn)

参数说明:
- jieba.posseg 提供词性标注功能;
- flag 表示词性,如名词(n)、动词(v)、形容词(a)等;
- 有助于后续特征提取或关键词提取。

2.3.2 去除停用词与无意义符号

停用词和特殊符号对分类无帮助,需过滤。

def remove_stopwords(words, stopwords):
    return [word for word in words if word not in stopwords and word.strip() != '']

# 示例停用词表
stopwords = set(['的', '是', '了', '在', '和', '一', '不', '中', '有', '也', '这'])

text = "近年来,人工智能技术取得了飞速发展"
words = jieba.cut(text)
filtered_words = remove_stopwords(words, stopwords)
print(' '.join(filtered_words))

输出结果:

人工智能 技术 取得 飞速 发展

分析说明:
- 过滤掉“的”、“了”等无意义词;
- 得到更简洁、语义更强的文本表示。

2.3.3 文本向量化表示方法

经过分词和清洗后,文本需转换为数值形式,才能输入模型。常用方法包括:

  • Bag-of-Words (BoW)
  • TF-IDF
  • Word2Vec / GloVe / BERT 等词向量
from sklearn.feature_extraction.text import TfidfVectorizer

texts = [
    "人工智能技术取得了飞速发展",
    "中国经济正在稳步增长",
    "科技改变生活"
]

vectorizer = TfidfVectorizer(tokenizer=jieba.cut, stop_words=stopwords)
X = vectorizer.fit_transform(texts)
print(X.toarray())

代码解释:
- 使用 TfidfVectorizer 自动进行分词、停用词过滤、TF-IDF 权重计算;
- X.toarray() 输出向量化后的矩阵;
- 每一行代表一个文本的向量表示。

输出示例:

[[0.5 0.3 0.2 0.1 0. ...]
 [0.4 0.3 0.1 0.2 0. ...]
 [0.6 0.2 0.1 0.1 0. ...]]

分析说明:
- 向量维度等于词表大小;
- 数值代表每个词在该文本中的 TF-IDF 权重;
- 该向量可作为输入用于朴素贝叶斯、SVM 或神经网络等分类模型。

小结(非总结性陈述)

通过对复旦大学语料库的结构分析与内容特征挖掘,我们建立了清晰的数据认知。接下来的章节将基于这些预处理步骤,进一步探讨训练集与测试集的划分策略,为模型训练打下坚实基础。

3. 训练集与测试集划分策略

在机器学习任务中,合理的数据划分策略是模型训练与评估的基础。尤其在中文文本分类任务中,由于语料库的类别分布不均、样本数量有限等问题,如何科学地将数据集划分为训练集与测试集,直接影响模型的泛化能力和评估的可靠性。本章将从划分原则与常见方法出发,深入探讨不同划分策略对模型性能的影响,并结合复旦大学语料库的实际场景,提供具体的划分技巧与实现方法。

3.1 划分原则与常见方法

在划分训练集和测试集时,应遵循以下基本原则: 数据代表性、划分均衡性、可重复性与可解释性 。这些原则帮助我们在有限的数据条件下,最大化模型的学习能力与评估的准确性。

3.1.1 简单随机划分

简单随机划分(Simple Random Split)是最基础的数据划分方式。它通过随机打乱数据集后按比例(如7:3或8:2)划分为训练集和测试集。

from sklearn.model_selection import train_test_split

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)

代码解释:

  • X :输入特征数据(如TF-IDF向量)
  • y :目标标签(分类类别)
  • test_size=0.3 :表示30%作为测试集
  • random_state=42 :固定随机种子以保证结果可重复

适用场景: 数据类别分布均匀、样本量较大时,该方法足够有效。

缺点: 若数据类别分布不均,容易导致训练集和测试集类别分布差异较大,影响模型评估的稳定性。

3.1.2 分层抽样划分

为了解决类别分布不均的问题,可以使用 分层抽样划分(Stratified Sampling) ,它在划分过程中保持训练集和测试集中各类别的比例与原始数据集一致。

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, stratify=y, random_state=42)

新增参数说明:

  • stratify=y :根据标签 y 进行分层抽样,确保每个类别的样本在训练集和测试集中比例一致

适用场景: 复旦语料库中部分类别样本较少,使用该方法可以保证划分后的数据集类别分布稳定。

3.1.3 交叉验证策略

在样本量较小或模型调参阶段, 交叉验证(Cross-Validation) 是一种更可靠的划分策略。常见的有 K折交叉验证(K-Fold CV) 分层K折交叉验证(Stratified K-Fold)

from sklearn.model_selection import StratifiedKFold

skf = StratifiedKFold(n_splits=5)
for train_index, test_index in skf.split(X, y):
    X_train, X_test = X[train_index], X[test_index]
    y_train, y_test = y[train_index], y[test_index]
    # 模型训练与评估

参数说明:

  • n_splits=5 :表示将数据分为5份,轮流使用其中一份作为测试集
  • StratifiedKFold :在每次划分中保持类别分布一致

优点:

  • 更全面地利用所有数据进行训练与验证
  • 减少由于一次划分导致的评估偏差

适用场景: 小样本数据集、模型调参、性能评估更严格时使用

3.2 数据划分对模型性能的影响

数据划分策略直接影响模型的训练效果和评估质量,特别是在中文文本分类任务中,以下几个方面尤为关键。

3.2.1 过拟合与欠拟合的规避

训练集划分不当可能导致模型在训练集上表现优异,但在测试集上表现差( 过拟合 ),或者在训练集和测试集上都表现不佳( 欠拟合 )。

  • 过拟合 通常发生在训练集样本太少或数据划分不够多样化时。
  • 欠拟合 则可能由于训练数据过于杂乱、噪声大或模型过于简单。

解决策略:

  • 使用交叉验证来增强模型对数据的适应能力
  • 在划分时保持数据多样性,避免训练集样本过于集中

3.2.2 类别分布不均带来的影响

复旦大学语料库中,某些类别(如“体育”、“科技”)样本量较多,而其他类别(如“教育”、“政治”)样本较少。若不进行合理划分,模型可能偏向多数类,忽略少数类。

示例分析:

假设原始数据中类别A占80%,类别B仅占20%:

划分方式 类别A占比 类别B占比
简单随机划分 78% 22%
分层抽样划分 80% 20%
交叉验证平均结果 80.2% 19.8%

从上表可以看出,分层抽样和交叉验证能更准确地保持原始数据的类别分布,从而提升模型的泛化能力。

3.2.3 小样本情况下的划分策略

在一些特定类别样本较少的情况下(如某些新闻子类别),常规划分方法难以保证测试集样本的代表性。

解决方案:

  • 使用重复划分(Repeated Holdout) :多次随机划分取平均结果,提高评估稳定性
  • 使用Bootstrap方法 :从原始数据中有放回抽样构建训练集,测试集为未被选中的样本
  • 结合数据增强技术 :如SMOTE上采样少数类样本,再进行划分

3.3 实践中的划分技巧

在实际项目中,除了选择合适的划分方法,还需要关注划分的实现细节和结果的可视化分析。

3.3.1 使用Scikit-learn进行划分

Scikit-learn 提供了丰富的划分接口,除了上述 train_test_split StratifiedKFold ,还可以使用 GroupKFold (用于分组数据)或 TimeSeriesSplit (用于时间序列数据)等。

from sklearn.model_selection import GroupKFold

gkf = GroupKFold(n_splits=5)
for train_idx, test_idx in gkf.split(X, y, groups=groups):
    X_train, X_test = X[train_idx], X[test_idx]
    y_train, y_test = y[train_idx], y[test_idx]

适用场景: 若样本存在分组结构(如多篇文章来自同一作者),使用 GroupKFold 可避免组内信息泄露。

3.3.2 自定义划分函数的实现

当标准方法无法满足特定需求时,可以自定义划分逻辑。例如,在复旦语料库中,我们希望按类别单独划分,确保每个类别的训练与测试样本都具有代表性。

import numpy as np
from collections import defaultdict

def custom_stratified_split(X, y, test_size=0.3):
    class_indices = defaultdict(list)
    for idx, label in enumerate(y):
        class_indices[label].append(idx)

    train_indices, test_indices = [], []
    for label, indices in class_indices.items():
        np.random.shuffle(indices)
        split_point = int(len(indices) * (1 - test_size))
        train_indices.extend(indices[:split_point])
        test_indices.extend(indices[split_point:])
    return X[train_indices], X[test_indices], y[train_indices], y[test_indices]

代码逻辑分析:

  • 按类别收集索引
  • 对每个类别的索引进行随机打乱
  • 按比例划分训练与测试集
  • 最终合并所有类别的划分结果

优点: 完全可控的划分逻辑,适用于特定需求(如按类别分层、按时间排序等)

3.3.3 划分结果的可视化分析

划分完成后,应通过可视化手段检查训练集和测试集的类别分布是否一致。

类别分布直方图对比
import matplotlib.pyplot as plt

def plot_class_distribution(y_true, y_pred, title):
    plt.figure(figsize=(10, 5))
    plt.subplot(1, 2, 1)
    plt.hist(y_true, bins=20, alpha=0.7, label='True')
    plt.title(f'{title} - True')
    plt.subplot(1, 2, 2)
    plt.hist(y_pred, bins=20, alpha=0.7, label='Predicted')
    plt.title(f'{title} - Predicted')
    plt.show()

plot_class_distribution(y_train, y_test, 'Train/Test Distribution')
流程图:划分过程示意
graph TD
    A[原始数据集] --> B{是否类别分布不均?}
    B -->|否| C[简单随机划分]
    B -->|是| D[分层抽样或交叉验证]
    D --> E[划分训练集与测试集]
    E --> F[可视化分布对比]
    F --> G{分布一致?}
    G -->|否| H[重新调整划分策略]
    G -->|是| I[进入模型训练]

流程说明:

  1. 初始数据集进入流程
  2. 判断是否类别分布不均,选择划分策略
  3. 执行划分并可视化分析
  4. 若分布不一致则重新调整,否则进入模型训练

本章通过介绍多种数据划分策略,分析其适用场景与优缺点,并结合复旦大学语料库的实际需求,提供了具体的实现代码与可视化方法。下一章将深入探讨20个文本类别的分布情况,进一步分析类别不平衡问题及其处理策略。

4. 20个文本类别分布解析

在中文文本分类任务中,类别分布是影响模型训练与性能表现的重要因素之一。特别是在使用复旦大学语料库进行训练时,其包含的20个文本类别具有不同的文本长度、关键词分布与语义特征。本章将围绕类别分布的统计方法、不平衡问题的处理策略以及类别特征分析与可视化三个方面,深入解析这20个文本类别的分布规律,为后续模型训练提供数据层面的支撑。

4.1 类别分布统计方法

在进行文本分类任务前,了解各个类别的数据分布是基础且必要的工作。类别分布的统计方法主要包括类别标签频次统计、类别分布直方图绘制以及类别间相似性分析。

4.1.1 类别标签频次统计

类别标签频次统计是最直接的分布分析方式。通过对语料库中每个类别的文档数量进行统计,可以快速了解是否存在类别不平衡问题。

import os
from collections import Counter

# 假设语料目录为 'data/reuters-21578',每个子目录代表一个类别
data_dir = 'data/reuters-21578'
class_counts = Counter()

for cls in os.listdir(data_dir):
    class_path = os.path.join(data_dir, cls)
    if os.path.isdir(class_path):
        num_files = len([f for f in os.listdir(class_path) if os.path.isfile(os.path.join(class_path, f))])
        class_counts[cls] = num_files

# 输出前10个类别数量
for cls, count in class_counts.most_common(10):
    print(f"{cls}: {count}")
代码解析:
  • os.listdir(data_dir) :列出语料目录下的所有子目录,每个子目录代表一个类别。
  • os.path.isdir(class_path) :判断路径是否为目录,防止误统计非类别文件。
  • len([f for f in os.listdir(class_path) if os.path.isfile(...)]) :统计每个类别目录下的文件数量。
  • Counter :用于高效统计类别数量,并支持排序输出。

该代码输出的结果如下(示例):

类别名称 文档数量
财经新闻 4892
体育新闻 3421
科技新闻 2310
政治新闻 2005
娱乐新闻 1800
旅游新闻 1200
军事新闻 1100
健康新闻 980
教育新闻 900
汽车新闻 850

通过该统计,我们可以初步判断数据集中是否存在类别不平衡问题,例如“财经新闻”数量远多于“教育新闻”。

4.1.2 类别分布直方图绘制

为了更直观地展示类别分布情况,可以绘制直方图进行可视化分析。

import matplotlib.pyplot as plt

# 绘制直方图
classes = list(class_counts.keys())
counts = list(class_counts.values())

plt.figure(figsize=(12, 6))
plt.bar(classes, counts, color='skyblue')
plt.xticks(rotation=90)
plt.xlabel('类别')
plt.ylabel('样本数量')
plt.title('20个文本类别分布直方图')
plt.tight_layout()
plt.show()
代码解析:
  • plt.bar(classes, counts) :绘制柱状图,X轴为类别名称,Y轴为文档数量。
  • plt.xticks(rotation=90) :旋转X轴标签,防止重叠。
  • plt.tight_layout() :自动调整子图参数,防止标签被截断。
输出效果说明:

直方图展示了20个类别的文档数量分布情况。通过观察柱状图高度,可以清晰看到哪些类别样本较多,哪些较少。这种可视化方式有助于发现类别分布不均问题,为后续采样策略提供依据。

4.1.3 类别间相似性分析

不同类别之间可能存在语义上的相似性,例如“财经新闻”与“股市新闻”、“体育新闻”与“赛事新闻”等。通过计算类别之间的相似度,可以进一步优化模型结构设计或进行类别合并策略。

from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.metrics.pairwise import cosine_similarity

# 假设有每个类别的代表性文档集合
class_representative_texts = {
    '财经新闻': '股票 基金 市场 投资',
    '体育新闻': '篮球 足球 比赛 运动员',
    '科技新闻': 'AI 算法 数据 模型',
    '政治新闻': '政府 政策 党派 法律',
    # 其他类别略
}

vectorizer = TfidfVectorizer()
tfidf_matrix = vectorizer.fit_transform(class_representative_texts.values())
similarity_matrix = cosine_similarity(tfidf_matrix)

print(similarity_matrix)
代码解析:
  • TfidfVectorizer :将文本转化为TF-IDF向量,用于计算相似度。
  • cosine_similarity(tfidf_matrix) :计算向量之间的余弦相似度,得到类别之间的相似性矩阵。
输出示例:
[[1.         0.10234567 0.12345678 ...]
 [0.10234567 1.         0.09876543 ...]
 [0.12345678 0.09876543 1.         ...]
 ...
]
结果分析:
  • 相似度值范围在0~1之间,值越大表示两个类别越相似。
  • 可以据此设计多标签分类模型,或者将相似类别合并以简化任务。

4.2 类别不平衡问题及处理策略

类别不平衡是文本分类中常见的问题,尤其在复旦语料中,不同类别样本数量差异较大,容易导致模型偏向多数类,影响分类性能。常见的处理策略包括上采样、下采样、合成样本(如SMOTE)以及损失函数加权等。

4.2.1 上采样与下采样技术

上采样(Oversampling)和下采样(Undersampling)是处理类别不平衡的常用方法。

上采样示例(使用 imbalanced-learn 库):
from imblearn.over_sampling import RandomOverSampler
import numpy as np

# 假设 X 为特征矩阵,y 为类别标签
ros = RandomOverSampler(random_state=42)
X_resampled, y_resampled = ros.fit_resample(X, y)
下采样示例:
from imblearn.under_sampling import RandomUnderSampler

rus = RandomUnderSampler(random_state=42)
X_resampled, y_resampled = rus.fit_resample(X, y)
方法对比:
方法 优点 缺点
上采样 保留所有样本信息,适合小样本 可能引入过拟合
下采样 减少训练时间,避免过拟合 丢失信息,适合大样本

4.2.2 SMOTE等合成样本方法

SMOTE(Synthetic Minority Over-sampling Technique)是一种经典的合成样本方法,通过在少数类样本之间生成新样本,来平衡类别分布。

from imblearn.over_sampling import SMOTE

smote = SMOTE(random_state=42)
X_smote, y_smote = smote.fit_resample(X, y)
SMOTE优势:
  • 避免简单重复少数类样本,减少过拟合风险。
  • 可以与多数类样本形成更清晰的决策边界。
注意事项:
  • 不适用于高维稀疏数据(如TF-IDF向量),可能需要降维或特征选择。
  • 适用于连续特征,对文本分类中的离散特征需做适当调整。

4.2.3 损失函数加权调整

在模型训练过程中,可以通过设置类别权重来平衡损失函数,使模型更加关注少数类。

from sklearn.linear_model import LogisticRegression

# 计算类别权重
class_weights = {cls: 1 / count for cls, count in class_counts.items()}

# 在模型中设置 class_weight 参数
model = LogisticRegression(class_weight=class_weights)
model.fit(X_train, y_train)
参数说明:
  • class_weight='balanced' :自动根据类别分布计算权重。
  • 自定义权重 :可手动设置,如对少数类赋予更高权重。
优势:
  • 不改变原始数据分布,适用于不能修改训练数据的场景。
  • 易于在大多数模型中实现。

4.3 类别特征分析与可视化

了解每个类别的关键特征,有助于提升模型的可解释性和分类效果。本节将介绍TF-IDF特征分析、类别关键词提取以及特征分布的可视化方法。

4.3.1 TF-IDF特征分析

TF-IDF是一种常用的文本特征表示方法,能够衡量词语在文档中的重要程度。

from sklearn.feature_extraction.text import TfidfVectorizer

vectorizer = TfidfVectorizer(max_features=5000)
X_tfidf = vectorizer.fit_transform(corpus)  # corpus为文本语料
参数说明:
  • max_features=5000 :控制特征维度,避免特征爆炸。
  • fit_transform(corpus) :对语料进行拟合并转换为TF-IDF矩阵。
可视化TF-IDF权重最高的关键词:
import pandas as pd

# 获取特征名称和权重
feature_names = vectorizer.get_feature_names_out()
tfidf_scores = X_tfidf.toarray().sum(axis=0)

# 构建DataFrame并排序
df_tfidf = pd.DataFrame({'word': feature_names, 'score': tfidf_scores})
top_words = df_tfidf.sort_values(by='score', ascending=False).head(20)

print(top_words)
输出示例:
word score
经济 12.345
发展 11.234
市场 10.123
科技 9.876

4.3.2 类别关键词提取

针对每个类别,可以分别提取其关键词,用于分析类别语义特征。

from sklearn.feature_extraction.text import TfidfVectorizer

# 假设每个类别都有一个文本集合
category_keywords = {}

for category, texts in category_texts.items():
    vectorizer = TfidfVectorizer()
    tfidf_matrix = vectorizer.fit_transform(texts)
    feature_names = vectorizer.get_feature_names_out()
    scores = tfidf_matrix.toarray().sum(axis=0)
    top_words = [feature_names[i] for i in scores.argsort()[-10:][::-1]]
    category_keywords[category] = top_words
输出示例:
{
    '财经新闻': ['股市', '基金', '投资', '金融', '经济'],
    '体育新闻': ['比赛', '运动员', '球队', '赛事', '体育'],
    '科技新闻': ['AI', '算法', '模型', '数据', '技术'],
    ...
}
应用价值:
  • 可用于构建关键词特征。
  • 可用于可视化分析类别语义差异。

4.3.3 特征分布可视化方法

使用词云(WordCloud)可以直观展示每个类别的关键词分布。

from wordcloud import WordCloud
import matplotlib.pyplot as plt

# 生成词云
wordcloud = WordCloud(width=800, height=400, background_color='white').generate_from_frequencies(dict(top_words))

# 绘制图像
plt.figure(figsize=(10, 5))
plt.imshow(wordcloud, interpolation='bilinear')
plt.axis("off")
plt.show()
输出效果:

生成的词云图像中,字体大小反映关键词的重要性。高频关键词如“经济”、“科技”等会以较大字体呈现,有助于直观理解类别特征。

通过本章对20个文本类别的分布统计、不平衡处理与特征分析,我们不仅掌握了数据分布的基本情况,也为后续模型训练提供了数据预处理与特征工程的依据。在实际应用中,可以根据类别分布动态调整采样策略、特征提取方式以及模型训练参数,以提升整体分类性能。

5. 朴素贝叶斯分类实现

5.1 朴素贝叶斯模型原理

5.1.1 概率模型的基本假设

朴素贝叶斯(Naive Bayes)是一类基于贝叶斯定理并假设特征之间相互独立的概率分类模型。其核心公式为:

P(Y|X) = \frac{P(X|Y)P(Y)}{P(X)}

其中:
- $P(Y|X)$:给定输入特征 $X$ 下类别 $Y$ 的后验概率;
- $P(Y)$:类别 $Y$ 的先验概率;
- $P(X|Y)$:给定类别 $Y$ 下输入特征 $X$ 的似然;
- $P(X)$:输入特征 $X$ 的边缘概率(常作为归一化项,可忽略)。

在文本分类任务中,特征 $X$ 通常为词频向量或TF-IDF特征向量。由于朴素贝叶斯假设特征之间相互独立,因此:

P(X|Y) = \prod_{i=1}^{n} P(x_i | Y)

这种独立性假设虽然在现实中不一定成立,但在文本分类任务中却表现出良好的性能。

5.1.2 多项式、伯努利与高斯模型的区别

朴素贝叶斯根据特征的分布形式,主要有以下三种变体:

模型类型 特征类型 适用场景 特点
多项式朴素贝叶斯(MultinomialNB) 离散值(如词频) 文本分类、词袋模型 对词频敏感,适用于文本数据
伯努利朴素贝叶斯(BernoulliNB) 布尔值(是否出现) 二值特征 适合特征为是否出现的文本
高斯朴素贝叶斯(GaussianNB) 连续值 数值型数据 假设特征服从正态分布

以中文文本分类为例,我们通常使用 MultinomialNB ,因为它适用于词频统计的特征表示。

5.1.3 拉普拉斯平滑技术

在计算 $P(x_i|Y)$ 时,如果某个词在某一类别中从未出现,那么 $P(x_i|Y) = 0$,这将导致整个乘积为零,从而影响模型性能。为此,我们引入 拉普拉斯平滑(Laplace Smoothing)

P(x_i|Y) = \frac{count(x_i, Y) + 1}{count(Y) + N}

其中:
- $count(x_i, Y)$:词 $x_i$ 在类别 $Y$ 中的出现次数;
- $count(Y)$:类别 $Y$ 中所有词的总出现次数;
- $N$:词汇表大小(所有不同词的数量)。

通过加1平滑,可以避免概率为零的问题,提高模型的鲁棒性。

5.2 基于复旦语料的分类实现

5.2.1 文本向量化方法选择

在复旦大学中文语料库中,每篇文本是中文新闻,我们需要将其转换为数值特征向量。常用方法包括:

  • 词袋模型(Bag of Words, BoW) :统计每个词在文档中出现的次数;
  • TF-IDF :不仅考虑词频,还考虑词在整个语料中的重要性;
  • One-Hot 编码 :适合小规模词汇,效率较低;
  • Word2Vec、GloVe 等词向量嵌入 :适用于深度学习模型。

在朴素贝叶斯分类中,我们通常选择 TF-IDF 向量化 ,因为它能够缓解高频词对分类的干扰,同时保留关键词的权重信息。

from sklearn.feature_extraction.text import TfidfVectorizer

vectorizer = TfidfVectorizer(max_features=5000)
X_train_tfidf = vectorizer.fit_transform(X_train)
X_test_tfidf = vectorizer.transform(X_test)

代码逻辑分析:

  • max_features=5000 :限制词典大小,只保留TF-IDF得分最高的5000个词;
  • fit_transform(X_train) :学习词典并转换训练集;
  • transform(X_test) :使用训练集的词典转换测试集,保证特征空间一致。

5.2.2 模型训练与预测流程

我们使用 MultinomialNB 对 TF-IDF 向量进行训练和预测。

from sklearn.naive_bayes import MultinomialNB
from sklearn.metrics import classification_report

# 初始化模型
model = MultinomialNB()

# 训练模型
model.fit(X_train_tfidf, y_train)

# 预测
y_pred = model.predict(X_test_tfidf)

# 输出分类报告
print(classification_report(y_test, y_pred))

代码逻辑分析:

  • MultinomialNB() :使用多项式朴素贝叶斯模型;
  • fit() :训练过程,计算每个词在每个类别中的条件概率;
  • predict() :对测试集进行预测;
  • classification_report :输出准确率、召回率、F1值等指标。

5.2.3 模型调参与性能优化

虽然朴素贝叶斯参数较少,但仍有以下可调参数:

  • alpha :平滑系数,默认为1.0(即拉普拉斯平滑),可尝试0.1、0.5等值;
  • fit_prior :是否学习类先验概率,默认为True;
  • class_prior :可手动设置类先验概率,适用于类别不平衡数据。
model = MultinomialNB(alpha=0.5)

性能优化建议:

  • 特征筛选 :可通过卡方检验、互信息法等筛选高信息量特征;
  • 停用词过滤 :去除无意义词,提升特征质量;
  • n-gram 特征 :使用二元词(bigram)提升分类性能;
  • 数据增强 :对样本较少的类别进行上采样。

5.3 模型评估与结果分析

5.3.1 准确率、召回率与F1值计算

模型训练完成后,我们使用 classification_report 输出详细评估指标:

from sklearn.metrics import classification_report

print(classification_report(y_test, y_pred))

输出示例:

              precision    recall  f1-score   support

           0       0.90      0.88      0.89       100
           1       0.85      0.87      0.86       100
           2       0.89      0.91      0.90       100
           ...
    accuracy                           0.88       900
   macro avg       0.88      0.88      0.88       900
weighted avg       0.88      0.88      0.88       900

指标解释:

  • precision(准确率) :预测为正类中实际为正的比例;
  • recall(召回率) :实际为正类中被正确预测的比例;
  • F1-score :两者的调和平均,适用于类别不平衡场景;
  • support :该类别的样本数量。

5.3.2 混淆矩阵可视化

我们可以使用混淆矩阵更直观地观察分类结果。

from sklearn.metrics import confusion_matrix
import seaborn as sns
import matplotlib.pyplot as plt

cm = confusion_matrix(y_test, y_pred)
plt.figure(figsize=(10, 8))
sns.heatmap(cm, annot=True, fmt='d', cmap='Blues')
plt.xlabel('Predicted')
plt.ylabel('True')
plt.title('Confusion Matrix')
plt.show()

流程图:混淆矩阵生成流程

graph TD
A[模型预测结果] --> B[构建混淆矩阵]
B --> C[使用Seaborn绘制热力图]
C --> D[展示分类错误分布]

5.3.3 模型优缺点总结

优点 缺点
训练速度快,适合高维稀疏数据 假设特征独立,对强相关特征敏感
对小规模数据表现良好 对噪声敏感,需清洗数据
参数少,易于调优 对输入特征的表示敏感,需合理向量化
适合文本分类、垃圾邮件识别等任务 无法建模复杂的非线性关系

适用场景建议:

  • 当数据量较小,且特征维度高时,推荐使用朴素贝叶斯;
  • 若需更高精度,可结合 TF-IDF + SVM 或深度学习模型(如CNN);
  • 对速度要求高、资源有限的部署环境,朴素贝叶斯是理想选择。

总结:

在本章中,我们深入解析了朴素贝叶斯模型的原理,包括其概率模型、三大变体以及拉普拉斯平滑技术;结合复旦大学中文语料库,完成了从文本向量化到模型训练与预测的全过程;并通过分类报告与混淆矩阵对模型性能进行了评估。朴素贝叶斯虽结构简单,但在中文文本分类中表现稳定,是入门NLP任务的理想起点。

6. 支持向量机(SVM)分类实现

支持向量机(Support Vector Machine, SVM)是机器学习中一种经典的分类算法,尤其在高维空间中表现优异,因此在文本分类任务中得到了广泛应用。SVM的核心思想是寻找一个最优超平面,使得不同类别的样本尽可能被分开,同时最大化分类间隔。在中文文本分类任务中,SVM因其良好的泛化能力和对高维稀疏特征的适应性而备受青睐。

6.1 SVM分类原理与核函数选择

6.1.1 线性可分与非线性分类

在理想情况下,数据是 线性可分 的,即存在一个超平面可以将不同类别的样本完全分开。SVM通过最大化分类间隔(margin)来提升模型的泛化能力。然而,实际数据往往并非完全线性可分,此时需要引入松弛变量(slack variables)来允许部分样本被误分类。

线性SVM的数学表达式如下:

\min_{w, b} \frac{1}{2} |w|^2 + C \sum_{i=1}^{n} \xi_i
\text{subject to } y_i (w \cdot x_i + b) \geq 1 - \xi_i, \quad \xi_i \geq 0

其中:
- $ w $:超平面的法向量;
- $ b $:偏置项;
- $ \xi_i $:松弛变量,表示样本的误分类程度;
- $ C $:正则化参数,控制模型复杂度与误差之间的权衡。

当数据 线性不可分 时,SVM通过 核技巧 (Kernel Trick)将原始输入映射到更高维空间,在那里数据可能变得线性可分。

6.1.2 常用核函数对比

SVM的强大之处在于其核函数的选择。不同核函数适用于不同类型的数据分布。在中文文本分类中,常用的核函数包括:

核函数类型 公式表示 特点说明
线性核(Linear) $ K(x, x’) = x \cdot x’ $ 适用于高维稀疏数据,训练速度快
多项式核(Polynomial) $ K(x, x’) = (\gamma x \cdot x’ + r)^d $ 可以捕捉非线性关系,但参数多
径向基函数(RBF) $ K(x, x’) = \exp(-\gamma |x - x’|^2) $ 非常强大,适合大多数非线性问题
Sigmoid核 $ K(x, x’) = \tanh(\gamma x \cdot x’ + r) $ 类似神经网络激活函数,适合二分类

对比分析:
- 线性核 在文本分类中表现优异,尤其是在TF-IDF特征下,因为其计算高效,且在高维空间中依然能保持良好的泛化能力。
- RBF核 虽然表达能力强,但参数调节复杂,训练时间长,容易过拟合。
- 多项式核和Sigmoid核 在文本分类中应用较少,主要由于其对参数敏感,且容易陷入局部最优。

6.1.3 支持向量与决策边界的理解

SVM的核心在于寻找 支持向量 (Support Vectors),这些样本位于决策边界附近,是构建分类器的关键。SVM的决策边界由这些支持向量决定,其余样本对最终模型无影响。

决策函数如下:

f(x) = \text{sign} \left( \sum_{i=1}^{n} \alpha_i y_i K(x_i, x) + b \right)

其中:
- $ \alpha_i $:拉格朗日乘子,仅非零时对应的样本为支持向量;
- $ K(x_i, x) $:核函数;
- $ b $:偏置项。

支持向量的作用:
- 决定分类器的最终形式;
- 影响模型的泛化能力;
- 数量越少,模型越简洁,泛化能力越强。

可视化决策边界:
使用二维数据可以直观展示SVM的决策边界与支持向量,如下图所示:

graph TD
    A[线性可分数据点] --> B[支持向量]
    B --> C[SVM分类器]
    C --> D[最大化分类间隔]
    D --> E[构建决策边界]

6.2 SVM在中文文本分类中的应用

6.2.1 特征选择与降维方法

在中文文本分类中,原始文本通常被表示为高维稀疏向量(如TF-IDF、词袋模型等),直接使用这些特征训练SVM可能导致计算复杂度高、过拟合风险大。因此需要进行 特征选择与降维

常用方法:
- 卡方检验(Chi2) :选择与类别相关性高的特征;
- 信息增益(IG) :衡量特征对分类的贡献;
- 主成分分析(PCA) :降维,保留主要信息;
- 奇异值分解(SVD) :适用于稀疏矩阵的降维技术。

代码示例:使用Scikit-learn进行特征选择与降维

from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.decomposition import TruncatedSVD
from sklearn.feature_selection import SelectKBest, chi2

# 文本向量化
vectorizer = TfidfVectorizer()
X_tfidf = vectorizer.fit_transform(corpus)

# 特征选择:卡方检验
selector = SelectKBest(chi2, k=1000)
X_selected = selector.fit_transform(X_tfidf, y)

# 降维:SVD
svd = TruncatedSVD(n_components=300)
X_reduced = svd.fit_transform(X_selected)

逐行解读:
1. 使用 TfidfVectorizer 将文本转换为TF-IDF特征;
2. SelectKBest 结合卡方检验选择前1000个最具判别能力的特征;
3. TruncatedSVD 将高维特征降维至300维,减少计算复杂度。

6.2.2 使用Scikit-learn实现分类

在中文文本分类任务中,SVM的实现通常使用 scikit-learn 库,其提供了丰富的SVM接口和工具。

代码示例:使用LinearSVC进行文本分类

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_reduced, y, test_size=0.2)

# 训练SVM分类器
clf = LinearSVC(C=1.0, class_weight='balanced', max_iter=10000)
clf.fit(X_train, y_train)

# 预测与评估
y_pred = clf.predict(X_test)
print(classification_report(y_test, y_pred))

逐行解读:
1. 使用 train_test_split 划分训练集与测试集;
2. LinearSVC 为线性SVM分类器, C 控制正则化强度;
3. class_weight='balanced' 用于处理类别不平衡问题;
4. classification_report 输出分类结果的准确率、召回率、F1值等指标。

6.2.3 多分类SVM的策略

SVM本质上是二分类器,但在文本分类中常常需要处理多分类问题(如20个类别)。常见的多分类策略有:

  • One-vs-One(OvO) :构建每对类别的分类器,最终通过投票决定类别;
  • One-vs-Rest(OvR) :为每个类别训练一个分类器,判断是否属于该类。

在Scikit-learn中,LinearSVC默认使用OvR策略进行多分类。

性能对比:
| 策略 | 训练时间 | 准确率 | 适用场景 |
|----------|----------|--------|------------------|
| OvO | 较长 | 较高 | 类别较多时 |
| OvR | 较短 | 中等 | 类别较少或线性可分 |

6.3 性能优化与调参技巧

6.3.1 参数网格搜索

SVM模型的性能高度依赖于参数选择,尤其是正则化参数 C 和核函数的参数(如RBF的 gamma )。可以使用网格搜索(Grid Search)进行调参。

代码示例:使用GridSearchCV进行参数搜索

from sklearn.model_selection import GridSearchCV
from sklearn.pipeline import Pipeline

pipeline = Pipeline([
    ('tfidf', TfidfVectorizer()),
    ('clf', LinearSVC())
])

parameters = {
    'tfidf__max_df': (0.75, 0.9),
    'tfidf__ngram_range': [(1, 1), (1, 2)],
    'clf__C': [0.1, 1, 10],
}

grid_search = GridSearchCV(pipeline, parameters, n_jobs=-1, verbose=1)
grid_search.fit(train_texts, train_labels)

print("Best parameters found: ", grid_search.best_params_)

逐行解读:
1. 构建包含TF-IDF和SVM的Pipeline;
2. 定义参数搜索空间,包括 max_df (过滤高频词)、 ngram_range (词组长度)和 C (正则化强度);
3. 使用 GridSearchCV 进行交叉验证搜索;
4. 输出最优参数组合。

6.3.2 正则化与泛化能力提升

SVM中的正则化参数 C 决定了模型对误分类的容忍度。较小的 C 值意味着更强的正则化,模型更简单;较大的 C 值则更关注训练误差。

建议:
- 在训练初期设置 C=1.0 作为默认值;
- 若模型过拟合,适当减小 C
- 若模型欠拟合,适当增大 C

6.3.3 高效训练与内存优化

在处理大规模中文文本数据时,SVM的训练可能面临内存瓶颈。可以采取以下策略:

  • 使用线性核(LinearSVC) :计算效率高;
  • 采用稀疏矩阵存储 :避免内存浪费;
  • 分批训练(Out-of-Core Learning) :适用于内存不足的场景;
  • 使用SGDClassifier :基于随机梯度下降的SVM,适合大规模数据。

代码示例:使用SGDClassifier进行在线训练

from sklearn.linear_model import SGDClassifier

clf = SGDClassifier(loss='hinge', penalty='l2', alpha=0.0001, max_iter=1000, tol=1e-3)
clf.partial_fit(X_batch, y_batch, classes=np.unique(y))

逐行解读:
1. SGDClassifier 使用随机梯度下降优化;
2. partial_fit 支持增量训练;
3. loss='hinge' 对应SVM的损失函数;
4. penalty='l2' 为L2正则化;
5. alpha 控制正则化强度。

性能对比:

模型 训练速度 内存占用 适用场景
LinearSVC 中等 中小型数据集
SGDClassifier 非常快 大规模数据集
SVM with RBF 小数据、非线性

通过本章的学习,我们掌握了SVM的基本原理、核函数选择策略、在中文文本分类中的具体应用方法以及性能优化技巧。SVM在文本分类中具有良好的泛化能力和高效的计算性能,尤其适合高维稀疏特征的处理。在后续章节中,我们将进一步探讨深度学习方法在文本分类中的应用。

7. 卷积神经网络(CNN)文本分类实战

7.1 CNN在文本分类中的原理

卷积神经网络(CNN)最初广泛应用于图像识别领域,但近年来在自然语言处理任务中也表现出色,尤其是在文本分类任务中。CNN能够自动提取文本中的局部特征,并通过池化操作降低维度,提高模型泛化能力。

7.1.1 词向量与嵌入层

在文本分类任务中,首先需要将文本转化为数值形式。通常采用词嵌入(Word Embedding)技术将每个词映射为一个固定维度的向量。例如,可以使用预训练的 Word2Vec、GloVe 或随机初始化的嵌入矩阵。在 Keras 中, Embedding 层用于实现这一功能。

from keras.layers import Embedding

# 构建嵌入层
embedding_layer = Embedding(input_dim=vocab_size,   # 词汇表大小
                            output_dim=embedding_dim, # 词向量维度
                            input_length=max_length)  # 输入文本长度

参数说明:
- input_dim :词汇表大小,即词典中不同词的数量。
- output_dim :每个词嵌入向量的维度。
- input_length :每条文本的长度(经过统一填充或截断)。

7.1.2 一维卷积与池化操作

在文本处理中,CNN 使用一维卷积层来提取局部特征。例如,使用大小为 3 的卷积核滑动窗口扫描文本的词向量序列,提取 n-gram 特征。随后,通过最大池化操作(Global Max Pooling)获取全局特征。

from keras.layers import Conv1D, GlobalMaxPooling1D

# 一维卷积层
conv_layer = Conv1D(filters=128, kernel_size=3, activation='relu')(embedding_output)

# 最大池化层
pooled_output = GlobalMaxPooling1D()(conv_layer)

参数说明:
- filters :卷积核数量,决定提取的特征图数量。
- kernel_size :卷积核大小,通常取 2~5。
- activation :激活函数,如 ReLU。

7.1.3 多通道输入与特征提取

多通道 CNN 是一种提升文本分类性能的有效方法。通常做法是将不同的词向量(如 Word2Vec 和 GloVe)作为两个通道输入,分别提取特征后进行融合。

from keras.layers import Input, Concatenate

# 假设有两个嵌入层
input1 = Input(shape=(max_length,))
input2 = Input(shape=(max_length,))

embedding1 = Embedding(vocab_size, 100)(input1)
embedding2 = Embedding(vocab_size, 100)(input2)

conv1 = Conv1D(128, 3, activation='relu')(embedding1)
conv2 = Conv1D(128, 3, activation='relu')(embedding2)

pooled1 = GlobalMaxPooling1D()(conv1)
pooled2 = GlobalMaxPooling1D()(conv2)

merged = Concatenate()([pooled1, pooled2])

这种方式可以提升模型对不同语义特征的捕捉能力。

7.2 使用TensorFlow/Keras实现CNN分类

7.2.1 数据预处理与词向量加载

在使用 CNN 模型前,需要对文本数据进行预处理,包括分词、构建词汇表、填充序列等。Keras 提供了 Tokenizer pad_sequences 工具简化流程。

from keras.preprocessing.text import Tokenizer
from keras.preprocessing.sequence import pad_sequences

# 初始化分词器
tokenizer = Tokenizer(num_words=vocab_size)
tokenizer.fit_on_texts(texts)

# 文本转序列
sequences = tokenizer.texts_to_sequences(texts)
data = pad_sequences(sequences, maxlen=max_length)

若使用预训练词向量,可加载如下:

import numpy as np

# 加载 GloVe 词向量
glove_path = 'glove.6B.100d.txt'
embeddings_index = {}

with open(glove_path, encoding='utf-8') as f:
    for line in f:
        values = line.split()
        word = values[0]
        coefs = np.asarray(values[1:], dtype='float32')
        embeddings_index[word] = coefs

# 构建嵌入矩阵
embedding_matrix = np.zeros((vocab_size, embedding_dim))
for word, i in tokenizer.word_index.items():
    if i < vocab_size:
        embedding_vector = embeddings_index.get(word)
        if embedding_vector is not None:
            embedding_matrix[i] = embedding_vector

7.2.2 构建CNN模型结构

使用 Keras 构建完整的 CNN 文本分类模型,结构如下:

from keras.models import Model
from keras.layers import Dense, Dropout

# 构建完整模型
inputs = Input(shape=(max_length,))
embedding = Embedding(vocab_size, embedding_dim, weights=[embedding_matrix], trainable=False)(inputs)
conv = Conv1D(128, 3, activation='relu')(embedding)
pooled = GlobalMaxPooling1D()(conv)
dropout = Dropout(0.5)(pooled)
outputs = Dense(num_classes, activation='softmax')(dropout)

model = Model(inputs=inputs, outputs=outputs)
model.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['accuracy'])

模型结构图如下(使用 Mermaid 格式):

graph TD
    A[Input Layer] --> B[Embedding Layer]
    B --> C[Conv1D Layer]
    C --> D[Global Max Pooling]
    D --> E[Dropout]
    E --> F[Dense Output]

7.2.3 模型训练与验证

使用训练集训练模型,并在验证集上评估性能:

history = model.fit(data_train, labels_train,
                    validation_data=(data_val, labels_val),
                    epochs=10,
                    batch_size=64)

训练过程中的准确率和损失可通过 history 对象查看,并绘制训练曲线分析模型收敛情况。

7.3 模型优化与性能提升

7.3.1 激活函数与损失函数选择

在 CNN 中,常用的激活函数有 ReLU、Tanh 和 Leaky ReLU。ReLU 在大多数情况下表现最佳,因其计算简单且能缓解梯度消失问题。

损失函数方面,多分类任务常用 categorical_crossentropy ,若标签为 one-hot 编码:

model.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['accuracy'])

若标签为整数形式,则使用 sparse_categorical_crossentropy

model.compile(optimizer='adam', loss='sparse_categorical_crossentropy', metrics=['accuracy'])

7.3.2 Dropout与Batch Normalization应用

Dropout 是一种有效的防止过拟合的方法。在 CNN 后加入 Dropout 层,可以随机丢弃部分神经元,提升模型泛化能力:

dropout_layer = Dropout(0.5)(pooled_output)

Batch Normalization 可加速训练过程并提升模型稳定性:

from keras.layers import BatchNormalization

bn_layer = BatchNormalization()(conv_layer)

可将 BN 层插入在卷积层与激活函数之间:

conv = Conv1D(128, 3)(embedding)
bn = BatchNormalization()(conv)
relu = Activation('relu')(bn)

7.3.3 可视化卷积特征图与注意力机制

为了理解 CNN 提取了哪些关键特征,可以通过可视化卷积层输出的特征图来进行分析。此外,引入注意力机制可以帮助模型聚焦于关键词。

from keras.layers import Attention

# 假设有两个卷积分支
attention_output = Attention()([conv1, conv2])

通过可视化工具(如 Grad-CAM)可以绘制出模型关注的文本区域,帮助分析分类依据。

(未完待续)

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

简介:该语料库由复旦大学提供,包含4902个训练文档和4902个测试文档,共9833篇中文文本,覆盖新闻、娱乐、科技、体育等20个类别,适用于构建和评估文本分类模型。文本分类是自然语言处理的重要任务,广泛应用于新闻分类、情感分析、垃圾邮件过滤和社交媒体监控。本数据集支持多种主流分类算法,如朴素贝叶斯、SVM、CNN、LSTM,以及BERT、RoBERTa等预训练模型的微调与测试,有助于提升模型的泛化能力与实际应用效果。


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

Logo

火山引擎开发者社区是火山引擎打造的AI技术生态平台,聚焦Agent与大模型开发,提供豆包系列模型(图像/视频/视觉)、智能分析与会话工具,并配套评测集、动手实验室及行业案例库。社区通过技术沙龙、挑战赛等活动促进开发者成长,新用户可领50万Tokens权益,助力构建智能应用。

更多推荐