24.11.5
实验三::C4.5(带有预剪枝和后剪枝)算法实现与测试
一、实验目的
深入理解决策树、预剪枝和后剪枝的算法原理,能够使用 Python 语言实现带有预剪枝和后剪枝的决策树算法 C4.5 算法的训练与测试,并且使用五折交叉验证算法进行模型训练与评估。
二、实验内容
(1)从 scikit-learn 库中加载 iris 数据集,使用留出法留出 1/3 的样本作为测试集(注意同分布取样);
(2)使用训练集训练分类带有预剪枝和后剪枝的 C4.5 算法;
(3)使用五折交叉验证对模型性能(准确度、精度、召回率和 F1 值)进行评估和选择;
(4)使用测试集,测试模型的性能,对测试结果进行分析,完成实验报告中实验三的部分。
三、算法步骤、代码、及结果
- 算法伪代码
加载 Iris 数据集
将数据集划分为训练集和测试集 (train_test_split)
初始化预剪枝决策树(设置 max_depth 和 min_samples_split),并训练模型
打印预剪枝模型的树深度
使用成本复杂度剪枝(后剪枝),选择合适的 ccp_alpha 参数,训练后剪枝模型
打印后剪枝模型的树深度
使用五折交叉验证评估预剪枝模型和后剪枝模型的平均准确度
使用测试集评估预剪枝模型和后剪枝模型的性能,打印分类报告 - 算法主要代码
完整源代码\调用库方法(函数参数说明)
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.model_selection import cross_val_score
from sklearn.metrics import classification_report
from sklearn.tree import DecisionTreeClassifier
from sklearn.metrics import make_scorer, f1_score
加载 Iris 数据集
iris = load_iris()
X = iris.data
y = iris.target
按照同分布划分数据集 (1/3 测试集,2/3 训练集)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=1/3, random_state=42, stratify=y)
train_test_split主要参数:
sklearn.model_selection.train_test_split(*arrays, test_size=None, train_size=None, random_state=None, shuffle=True, stratify=None)
arrays:待划分的特征矩阵 X 和标签向量 y
test_size:测试集比例,默认为 None
取值范围:(0, 1) 表示比例;整数表示测试集样本数;若为 None,则自动计算
train_size:训练集比例,默认为 None。若 test_size 和 train_size 均为 None,则默认 test_size=0.25
random_state:随机种子,整型值使得结果可复现
shuffle:布尔值,是否在划分前打乱数据,默认为 True
stratify:按特定分布划分数据。通常为标签 y,保证训练集和测试集中类别分布一致
print(f"训练集样本数: {len(X_train)}, 测试集样本数: {len(X_test)}")
预剪枝:限制深度和分裂条件
tree_prepruned = DecisionTreeClassifier(max_depth=5, min_samples_split=4, random_state=42)
tree_prepruned.fit(X_train, y_train)
DecisionTreeClassifier主要参数:
DecisionTreeClassifier(*, criterion='gini', splitter='best', max_depth=None, min_samples_split=2, ...)
criterion:衡量分裂质量的指标
"gini"(默认):Gini 不纯度
"entropy":信息增益
splitter:特征分裂方式
"best"(默认):选择最优分裂特征
"random":随机选择分裂特征
max_depth:决策树最大深度,限制树的深度以实现预剪枝, 默认值:None(树的深度不受限制)
min_samples_split:分裂节点所需的最小样本数, 默认值:2(至少有两个样本时可以分裂)
random_state:随机种子
ccp_alpha:后剪枝的复杂度参数, 默认值:0.0(不进行后剪枝)
查看模型结构
print(f"决策树深度(预剪枝): {tree_prepruned.get_depth()}")
使用成本复杂度剪枝 (后剪枝)
path = DecisionTreeClassifier(random_state=42).cost_complexity_pruning_path(X_train, y_train)
ccp_alphas = path.ccp_alphas
选择一个合理的 alpha 并训练后剪枝模型
tree_postpruned = DecisionTreeClassifier(random_state=42, ccp_alpha=ccp_alphas[-2])
tree_postpruned.fit(X_train, y_train)
print(f"决策树深度(后剪枝): {tree_postpruned.get_depth()}")
五折交叉验证
scorer = make_scorer(f1_score, average="weighted") # 以 F1 值为例
预剪枝模型的交叉验证得分
prepruned_scores = cross_val_score(tree_prepruned, X_train, y_train, cv=5, scoring='accuracy')
print(f"预剪枝模型五折交叉验证的平均准确度: {prepruned_scores.mean():.4f}")
后剪枝模型的交叉验证得分
postpruned_scores = cross_val_score(tree_postpruned, X_train, y_train, cv=5, scoring='accuracy')
print(f"后剪枝模型五折交叉验证的平均准确度: {postpruned_scores.mean():.4f}")
cross_validate主要参数:
sklearn.model_selection.cross_validate(estimator, X, y=None, *, scoring=None, cv=None, n_jobs=None, verbose=0, fit_params=None, return_train_score=False, return_estimator=False, error_score=nan)
estimator:用于训练的模型,如 LogisticRegression()
X:特征矩阵
y:标签向量
scoring:评估指标,默认为 None,即使用模型默认评分标准
可选单个指标(如 'accuracy')或列表(如 ['accuracy', 'precision_macro'])
cv:交叉验证折数,默认值 5
n_jobs:并行计算的线程数,默认为 None
-1 表示使用所有可用CPU
return_train_score:是否返回训练集分数,默认为 False
测试预剪枝模型
y_pred_prepruned = tree_prepruned.predict(X_test)
report_prepruned = classification_report(y_test, y_pred_prepruned, target_names=iris.target_names, zero_division=1)
print("预剪枝模型测试集性能:\n", report_prepruned)
测试后剪枝模型
y_pred_postpruned = tree_postpruned.predict(X_test)
report_postpruned = classification_report(y_test, y_pred_postpruned, target_names=iris.target_names, zero_division=1)
print("后剪枝模型测试集性能:\n", report_postpruned)
classification_report主要参数:
sklearn.metrics.classification_report(y_true, y_pred, *, labels=None, target_names=None, sample_weight=None, digits=2, output_dict=False, zero_division='warn')
y_true:真实标签
y_pred:预测标签
target_names:类别标签的名称
digits:结果小数位数,默认为 2
output_dict:是否以字典形式返回,默认为 False
- 训练结果截图(包括:准确率、精度(查准率)、召回率(查全率)、F1)
四、心得体会
通过本次实验,我深入理解了决策树算法,特别是C4.5算法及其核心机制,包括信息增益率的计算和树结构生成。同时,我学习了预剪枝和后剪枝的原理及其在防止模型过拟合中的重要作用。在实践中,我使用Python实现了带有预剪枝和后剪枝的C4.5决策树算法,并通过五折交叉验证对模型进行了训练与评估。这不仅巩固了我的理论知识,还提升了我对复杂模型进行优化和评估的能力。