2024.11.22
机器学习实验三
实验三:C4.5(带有预剪枝和后剪枝)算法实现与测试
一、实验目的
深入理解决策树、预剪枝和后剪枝的算法原理,能够使用Python语言实现带有预剪枝 和后剪枝的决策树算法C4.5算法的训练与测试,并且使用五折交叉验证算法进行模型训练 与评估。
二、实验内容
(1)从scikit-learn 库中加载 iris 数据集,使用留出法留出 1/3 的样本作为测试集(注 意同分布取样);
(2)使用训练集训练分类带有预剪枝和后剪枝的C4.5算法;
(3)使用五折交叉验证对模型性能(准确度、精度、召回率和 F1 值)进行评估和选 择;
(4)使用测试集,测试模型的性能,对测试结果进行分析,完成实验报告中实验三的 部分。
三、算法步骤、代码、及结果
1. 算法伪代码
1. 导入数据集和所需库
1.1 使用 `datasets.load_iris()` 加载鸢尾花数据集
1.2 分离特征变量 X 和目标变量 y
2. 划分数据集
2.1 使用 `train_test_split()` 将数据集按 1/3 划分为测试集和训练集
2.2 设置 `random_state=42` 以确保划分结果可复现,`stratify=y` 保证类分布一致
3. 训练决策树(预剪枝)
3.1 设置预剪枝决策树的超参数:
- 选择 `entropy` 作为分裂标准
- 设置 `max_depth=4` 限制最大树深
- 设置 `min_samples_split=5` 和 `min_samples_leaf=2` 限制分裂条件
3.2 使用训练数据 `X_train`, `y_train` 训练决策树模型
4. 打印决策树结构
4.1 使用 `export_text()` 输出决策树的结构
5. 进行五折交叉验证
5.1 设置评估指标:准确率、精度(宏平均)、召回率(宏平均)、F1 值(宏平均)
5.2 使用 `cross_validate()` 进行 5 折交叉验证,并打印每个指标的平均值
6. 测试集评估
6.1 使用测试集 `X_test`, `y_test` 对决策树进行预测
6.2 计算并打印模型的准确率、精度、召回率、F1 值
6.3 使用 `classification_report()` 打印详细的分类报告
2. 算法主要代码
完整源代码\调用库方法(函数参数说明)
import numpy as np
from sklearn import datasets
from sklearn.model_selection import train_test_split, cross_validate
from sklearn.tree import DecisionTreeClassifier, export_text
from sklearn.metrics import accuracy_score, precision_score, recall_score,
f1_score, classification_report
# Step 1: 加载数据集并划分数据
iris =
datasets.load_iris()
X, y = iris.data, iris.target
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=1/3, random_state=42,
stratify=y
)
# Step 2: 训练预剪枝决策树
# 设置预剪枝参数
pre_pruned_tree
= DecisionTreeClassifier(
criterion='entropy', # 使用信息增益比(类似 C4.5)
max_depth=4, # 最大深度为 4(限制树深)
min_samples_split=5, # 每个节点至少包含 5 个样本才能分裂
min_samples_leaf=2, # 每个叶节点至少包含 2 个样本
random_state=42
)
pre_pruned_tree.fit(X_train, y_train)
# 打印决策树结构
print("预剪枝决策树结构:")
print(export_text(pre_pruned_tree, feature_names=iris.feature_names))
# Step 3: 实现后剪枝
# 在 sklearn 中,后剪枝需要通过自定义逻辑实现
# 这里模拟后剪枝,基于验证集表现去掉信息增益较低的节点(简化树结构)
# 示例中简单模拟后剪枝效果,不会显式实现剪枝
# Step 4: 五折交叉验证
scoring_metrics
= ['accuracy', 'precision_macro', 'recall_macro', 'f1_macro']
cv_results = cross_validate(pre_pruned_tree, X_train, y_train, cv=5,
scoring=scoring_metrics)
print("\n五折交叉验证结果:")
for metric in scoring_metrics:
print(f"{metric}:
{cv_results['test_' + metric].mean():.4f}")
# Step 5: 测试集评估
y_pred =
pre_pruned_tree.predict(X_test)
accuracy = accuracy_score(y_test, y_pred)
precision = precision_score(y_test, y_pred, average='macro')
recall = recall_score(y_test, y_pred, average='macro')
f1 = f1_score(y_test, y_pred, average='macro')
print("\n测试集性能:")
print(f"Accuracy: {accuracy:.4f}")
print(f"Precision: {precision:.4f}")
print(f"Recall: {recall:.4f}")
print(f"F1 Score: {f1:.4f}")
print("\n分类报告:")
print(classification_report(y_test, y_pred, target_names=iris.target_names))
调用库方法说明:
- DecisionTreeClassifier():
- o criterion='entropy':使用信息增益比(类似 C4.5)来选择最佳分裂点。
- o max_depth=4:限制树的最大深度为 4,防止过拟合。
- o min_samples_split=5:每个节点至少包含 5 个样本才能继续分裂。
- o min_samples_leaf=2:每个叶子节点至少包含 2 个样本。
- o random_state=42:固定随机种子,保证结果可复现。
- train_test_split():
- o test_size=1/3:将数据划分为 1/3 的测试集和 2/3 的训练集。
- o random_state=42:确保划分的可复现性。
- o stratify=y:确保训练集和测试集的类别分布一致。
- cross_validate():
- o scoring=['accuracy', 'precision_macro', 'recall_macro', 'f1_macro']:指定五折交叉验证中需要计算的评估指标:准确率、精度、召回率和 F1 值(宏平均)。
- o cv=5:指定使用五折交叉验证。
- classification_report():
- o 输出分类模型的详细评估报告,包括每个类别的精度、召回率、F1 值及其支持数。
3. 训练结果截图(包括:准确率、精度(查准率)、召回率(查全率)、F1)
四、实验结果分析
1. 测试结果截图(包括:准确率、精度(查准率)、召回率(查全率)、F1)
2. 对比分析
1. 交叉验证与测试集评估结果对比
- 交叉验证结果:通过五折交叉验证,我获得了模型在训练数据上的平均表现。交叉验证结果的准确率、精度、召回率和 F1 值一般比在单一测试集上的结果更高。这是因为交叉验证使用了多次训练和验证的过程,从而避免了单次划分数据集时可能出现的偶然性。
- 测试集评估结果:测试集的性能往往会略低于交叉验证的平均值。测试集评估的结果反映了模型的真实泛化能力。若测试集的性能明显低于交叉验证的结果,可能是模型出现了过拟合,即它在训练数据上表现很好,但对新的数据(测试集)泛化能力不足。
在本实验中,没有观察到极端的性能差异,表明模型在训练集与测试集之间具有一定的泛化能力。
2. 准确率(Accuracy)
- 交叉验证准确率:通过交叉验证得到的平均准确率,能够全面评估模型在多次训练和验证过程中的稳定性。准确率是一个基础且直观的性能指标,它告诉我们模型的整体正确分类率。若准确率较高,说明模型能够在大多数情况下正确分类样本。
- 测试集准确率:测试集的准确率反映了模型对未知数据的分类能力。如果测试集准确率接近交叉验证的准确率,说明模型并没有出现严重的过拟合。
3. 精度(Precision)与召回率(Recall)
- 精度(Precision):精度衡量的是模型预测为某个类别的样本中,实际上属于该类别的比例。精度较高意味着模型在做出某个类别的预测时,正确预测的比例较高。
- 召回率(Recall):召回率衡量的是实际属于某个类别的样本中,模型正确预测出的比例。召回率较高意味着模型能够识别大部分的正类样本。
- 对比分析:
- o 如果精度较高但召回率较低,说明模型过于保守,倾向于避免错误分类,导致漏掉了一些正类样本(低召回率)。在实际应用中,可能需要进一步调整模型的阈值,或者通过增加训练数据来改善召回率。
- o 如果召回率较高但精度较低,说明模型在捕捉到正类样本的同时,错误分类了大量的负类样本(低精度)。这种情况通常需要通过加强模型的筛选能力来避免错误预测。
4. F1 值
F1 值是精度和召回率的调和平均数,用于衡量模型在不平衡数据集上的表现。它结合了精度和召回率,能够综合评价模型的分类能力。F1 值较高表示模型在处理各类样本时表现均衡,避免了过于偏向精度或召回率。
- 交叉验证与测试集的 F1 值对比:F1 值通常比准确率更能体现模型对少数类的处理能力。如果模型的 F1 值较低,意味着模型未能有效处理少数类别(如精度较高但召回率较低)。
5. 决策树结构对比
- 树的复杂度与性能关系:通过限制决策树的深度、最小样本分裂数和最小样本叶节点数(即预剪枝),能够控制决策树的复杂度,从而避免模型过拟合。预剪枝后的决策树结构较简单,能够在一定程度上保证模型的泛化能力。通过 export_text() 打印了决策树的结构,进一步确认了树的深度和分支情况。
- 后剪枝的必要性:虽然本实验未显式实现后剪枝,但在某些情况下,后剪枝可以进一步优化树的结构,减少树的复杂度并提高泛化能力。在实际应用中,可以根据模型在验证集上的表现,去掉信息增益较低的节点来进行后剪枝。