保姆级教程:用Keras搞定路透社新闻分类(附完整代码与可视化分析)
2026/6/5 6:06:38 网站建设 项目流程

从零构建Keras新闻分类器:路透社数据集实战与模型可视化全解析

在自然语言处理领域,文本分类是最基础也最具实用价值的任务之一。路透社新闻数据集作为NLP领域的经典基准,包含了46个新闻类别的上万条短新闻文本,是学习多分类问题的理想选择。本文将带您从数据探索开始,逐步完成一个完整的文本分类项目,特别强化了模型训练过程的可视化分析,帮助您真正理解模型行为。

1. 环境准备与数据探索

首先确保已安装必要的Python库。推荐使用Python 3.8+环境和以下依赖:

pip install tensorflow keras numpy matplotlib pandas

路透社数据集已内置在Keras中,包含8982个训练样本和2246个测试样本。每个样本都被预处理为单词索引序列,标签则是0-45的类别编号。让我们先观察数据特征:

from keras.datasets import reuters # 加载数据,保留前10000个高频词 (train_data, train_labels), (test_data, test_labels) = reuters.load_data(num_words=10000) # 查看数据分布 print(f"训练样本数: {len(train_data)}") # 输出: 8982 print(f"测试样本数: {len(test_data)}") # 输出: 2246 print(f"首条新闻的词索引序列: {train_data[0][:10]}") # 显示前10个词索引 print(f"首条新闻的类别标签: {train_labels[0]}")

数据特点分析

  • 词汇表限制在10000个高频词,低频词被过滤
  • 样本长度不固定,平均约150个单词
  • 类别分布不均衡,部分类别样本较少

提示:可以使用reuters.get_word_index()获取单词到索引的映射字典,方便查看原始文本内容

2. 数据预处理与特征工程

文本数据需要转换为数值形式才能输入神经网络。我们采用多热编码(multi-hot encoding)将每条新闻表示为10000维的稀疏向量。

2.1 文本向量化

import numpy as np def vectorize_sequences(sequences, dimension=10000): results = np.zeros((len(sequences), dimension)) for i, sequence in enumerate(sequences): results[i, sequence] = 1. # 出现过的词置1 return results x_train = vectorize_sequences(train_data) x_test = vectorize_sequences(test_data)

2.2 标签编码

对于多分类问题,标签需要转换为one-hot编码:

from keras.utils import to_categorical one_hot_train_labels = to_categorical(train_labels, num_classes=46) one_hot_test_labels = to_categorical(test_labels, num_classes=46)

2.3 创建验证集

从训练集中划分20%作为验证集:

x_val = x_train[:1800] partial_x_train = x_train[1800:] y_val = one_hot_train_labels[:1800] partial_y_train = one_hot_train_labels[1800:]

3. 模型架构设计与实现

针对这个46分类问题,我们设计一个具有两个隐藏层的全连接网络:

from keras import models from keras import layers model = models.Sequential([ layers.Dense(128, activation='relu', input_shape=(10000,)), layers.Dropout(0.5), # 添加Dropout防止过拟合 layers.Dense(64, activation='relu'), layers.Dense(46, activation='softmax') ])

关键设计考虑

  • 最后一层使用softmax激活,输出46个类别的概率分布
  • 中间层使用ReLU激活函数避免梯度消失
  • 添加Dropout层提高泛化能力

编译模型时选择适合多分类的损失函数:

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

4. 模型训练与可视化分析

现在开始训练模型,并记录训练过程中的指标变化:

history = model.fit(partial_x_train, partial_y_train, epochs=30, batch_size=128, validation_data=(x_val, y_val))

4.1 训练过程可视化

绘制训练和验证的损失曲线:

import matplotlib.pyplot as plt loss = history.history['loss'] val_loss = history.history['val_loss'] epochs = range(1, len(loss) + 1) plt.figure(figsize=(10, 5)) plt.plot(epochs, loss, 'bo-', label='Training loss') plt.plot(epochs, val_loss, 'rs--', label='Validation loss') plt.title('Training and validation loss') plt.xlabel('Epochs') plt.ylabel('Loss') plt.legend() plt.grid(True) plt.show()

绘制准确率变化曲线:

acc = history.history['accuracy'] val_acc = history.history['val_accuracy'] plt.figure(figsize=(10, 5)) plt.plot(epochs, acc, 'bo-', label='Training acc') plt.plot(epochs, val_acc, 'rs--', label='Validation acc') plt.title('Training and validation accuracy') plt.xlabel('Epochs') plt.ylabel('Accuracy') plt.legend() plt.grid(True) plt.show()

曲线分析要点

  • 验证损失在第8轮后开始上升,表明出现过拟合
  • 训练准确率持续上升但验证准确率停滞,说明模型开始记忆训练数据
  • 最佳epoch可能在10-15之间

4.2 模型评估与调优

根据可视化结果,我们调整训练epoch数为12重新训练:

model.fit(partial_x_train, partial_y_train, epochs=12, batch_size=128, validation_data=(x_val, y_val))

最终在测试集上的评估:

results = model.evaluate(x_test, one_hot_test_labels) print(f"测试集损失: {results[0]:.4f}, 准确率: {results[1]:.4f}")

典型结果示例:

2246/2246 [==============================] - 0s 143us/step 测试集损失: 0.9567, 准确率: 0.7925

5. 高级技巧与性能提升

5.1 类别不平衡处理

路透社数据集的类别分布不均,可以采用以下策略:

from sklearn.utils import class_weight # 计算类别权重 class_weights = class_weight.compute_class_weight( 'balanced', classes=np.unique(train_labels), y=train_labels) class_weight_dict = dict(enumerate(class_weights)) # 训练时传入class_weight参数 model.fit(partial_x_train, partial_y_train, epochs=12, batch_size=128, class_weight=class_weight_dict, validation_data=(x_val, y_val))

5.2 模型架构优化实验

尝试不同的网络结构并比较效果:

架构验证准确率训练时间过拟合程度
128-64-4678.5%中等中等
256-128-4679.2%较长较高
64-32-4676.8%较短较低
128-64-64-4678.9%较长较高

5.3 预测与新样本处理

模型部署后对新文本进行预测的完整流程:

def predict_new_text(text): # 1. 文本分词和索引化 word_index = reuters.get_word_index() words = text.lower().split() sequence = [word_index[word] for word in words if word in word_index] # 2. 向量化 vectorized = vectorize_sequences([sequence]) # 3. 预测 predictions = model.predict(vectorized) # 4. 获取top3类别 top3_indices = predictions[0].argsort()[-3:][::-1] top3_probs = predictions[0][top3_indices] return list(zip(top3_indices, top3_probs)) # 示例使用 sample_news = "The company announced a merger with its competitor in Q2" print(predict_new_text(sample_news))

6. 错误分析与模型解释

理解模型的错误模式对改进至关重要:

6.1 混淆矩阵分析

from sklearn.metrics import confusion_matrix import seaborn as sns # 获取测试集预测结果 predictions = model.predict(x_test) predicted_labels = np.argmax(predictions, axis=1) # 生成混淆矩阵 cm = confusion_matrix(test_labels, predicted_labels) plt.figure(figsize=(12, 10)) sns.heatmap(cm, annot=True, fmt='d', cmap='Blues') plt.xlabel('Predicted') plt.ylabel('True') plt.show()

6.2 典型错误案例

分析混淆矩阵可以发现:

  • 相似主题容易混淆(如"earn"和"acq")
  • 样本量少的类别识别准确率较低
  • 多义性词汇影响分类结果

6.3 可视化词重要性

通过提取第一层的权重,可以分析哪些词对分类贡献最大:

# 获取第一个Dense层的权重 weights = model.layers[0].get_weights()[0] # 计算每个词在所有类别上的平均重要性 word_importance = np.mean(np.abs(weights), axis=1) # 获取词表 word_index = reuters.get_word_index() reverse_word_index = dict([(value, key) for (key, value) in word_index.items()]) # 打印最重要的20个词 important_indices = np.argsort(word_importance)[-20:] print("最重要的20个词:") for i in important_indices: print(reverse_word_index.get(i, '?'), word_importance[i])

在实际项目中,当验证准确率达到79%左右时,可以考虑以下优化方向:尝试更复杂的模型架构如Transformer,引入预训练词向量,或者使用数据增强技术增加训练样本多样性。不过对于教学目的,当前模型已经很好地展示了文本分类的完整流程和关键分析技术。

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

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

立即咨询