决策树剪枝




本文以西瓜数据集为例演示决策树使用信息增益剪枝的过程

在这里插入图片描述
为了评价决策树模型的表现,我们将数据划分训练集(橘色)和验证集(蓝色)

西瓜数据集下载:传送门

关于西瓜数据集训练集和验证集的划分、决策树模型的训练与评估见文末附录

1、为什么要剪枝


如果我们让决策树一直生长,最后得到的决策树可能会很庞大。为了尽可能正确的分类训练样本,模型会对原始数据充分学习,这就会造成分支过多,进而产生过拟合的问题

过拟合是指模型在训练集上表现的很好,但是在测试集上表现的很差,即模型泛化性差。可以通过剪枝主动去掉一些分支来降低过拟合的风险,并使用留出法进行剪枝前后决策树的优劣评估

也就是说,缓解决策树过拟合可以通过剪枝操作完成。而剪枝方式又可以分为:预剪枝和后剪枝

  • 预剪枝(Pre-Pruning):在决策树生长过程中,对每个结点在划分前进行估计,若当前结点的划分不能带来决策树泛化性能的提升,则停止划分并将当前结点标记为叶结点

  • 后剪枝(Post-Pruning):先从训练集生成一棵完整的决策树,然后自底向上地对非叶结点进行考察,若将该结点对应的子树替换为叶结点能带来决策树泛化性能的提升,则将该子树替换为叶结点

什么意思呢?下面以西瓜数据集为例说明。在西瓜数据集上生成的一颗完整(未剪枝)的决策树,如下图所示:

在这里插入图片描述

2、预剪枝


预剪枝过程为:将当前节点标记为叶节点,类别标记为训练样例中最多的类别

对于训练集D,首先计算其根节点的信息熵:

  • 训练集分为好瓜、坏瓜,所以|y|=2
  • 根结点包含10个训练样例,其中好瓜共计5个样例,所占比例为5/10
  • 坏瓜共计5个样例,所占比例为5/10

将数据带入信息熵公式,即可得到根结点的信息熵:

E n t ( D ) = − ∑ k = 1 2 p k log ⁡ 2 p k = − ( 5 10 log ⁡ 2 5 10 + 5 10 log ⁡ 2 5 10 ) = 1 Ent(D)= -\sum_{k=1}^{2} p_k\log_2 p_k \\ =-\left( \frac{5}{10}\log_2\frac{5}{10}+\frac{5}{10}\log_2\frac{5}{10} \right) =1 Ent(D)=k=12pklog2pk=(105log2105+105log2105)=1

以信息增益为例,分别计算出所有特征的信息增益,据此选出决策树的根节点

以色泽为例,其对应3个数据子集{青绿,乌黑,浅白},则计算色泽属性的信息增益为:
G a i n ( D , 色泽 ) = E n t ( D ) − ∑ v = 1 3 ∣ D v ∣ ∣ D ∣ E n t ( D ) = 1 − ( 4 10 ∗ 1.000 + 4 10 ∗ 0.918 + 2 10 ∗ 0 ) = 0.276 Gain(D,色泽)=Ent(D)-\sum_{v=1}^{3}\frac{|D^v|}{|D|}Ent(D) \\ =1-\left( \frac{4}{10} * 1.000+\frac{4}{10}*0.918+\frac{2}{10}*0 \right) =0.276 Gain(D,色泽)=Ent(D)v=13DDvEnt(D)=1(1041.000+1040.918+1020)=0.276

同理,计算其他属性的信息增益为:

G a i n ( D , 根蒂 ) = 0.115 G a i n ( D , 敲声 ) = 0.174 G a i n ( D , 纹理 ) = 0.174 G a i n ( D , 脐部 ) = 0.276 G a i n ( D , 触感 ) = 0.000 Gain(D,根蒂)=0.115 \\ Gain(D,敲声)=0.174 \\ Gain(D,纹理)=0.174 \\ Gain(D,脐部)=0.276 \\ Gain(D,触感)=0.000 \\ Gain(D,根蒂)=0.115Gain(D,敲声)=0.174Gain(D,纹理)=0.174Gain(D,脐部)=0.276Gain(D,触感)=0.000

由结果可知,色泽和脐部的信息增益最大,所以从这两个中随机选择一个,这里选择脐部来对数据集进行划分,这会产生三个分支:

在这里插入图片描述
但是因为是预剪枝,所以要判断是否应该进行这个划分。判断的标准就是看划分前后的泛化性能是否有提升,也就是如果划分后模型的泛化性能有提升,则划分;否则,不划分

预剪枝对脐部属性的划分过程为:划分前,所有样本都在根节点,将该结点标记为叶节点,其类别标记为训练样本数量最多的类别(划分后):

在这里插入图片描述
然后使用验证集对其进行性能评估(以好瓜为例):

  • 划分前:验证集中样本{4,5,8}被分类正确,得到验证集精度为3/7=42.9%
  • 划分后:根据未剪枝决策树节点②③④的样例数据,验证集{9,13}这两个编号的瓜原本都是坏瓜,结果都被化分成好瓜;其他都被划分对了。所以,得到验证集的精度为5/7=71.4%

通过比较,71.4%>42.9%,划分后模型的泛化性能有提升,因此,对脐部进行划分

同理,可以在对脐部划分的基础上,再对节点②③进行划分:

在这里插入图片描述
划分后决策树为:

在这里插入图片描述
通过对比未剪枝的决策树和经过预剪枝的决策树,我们不难发现:预剪枝使得决策树的很多分支都没有展开,这不仅降低了模型过拟合的风险,还显著减少了决策树的训练和测试时间开销。但是,另一方面,预剪枝决策树也可能带来欠拟合的风险

3、后剪枝


后剪枝过程为:自底向上,将当前子树节点标记为叶节点,类别标记为训练样例中最多的类别

在一棵完整(未剪枝)的决策树中(见第1节),对于子树节点⑥,若将该子树节点标记为叶节点,其类别标记为训练样本数量最多的类别(剪枝后):

在这里插入图片描述
将子树标记为叶节点的过程称为后剪枝。同理,还要判断是否应该标记(剪枝)。判断的标准就是看剪枝前后的泛化性能是否有提升,也就是如果剪枝后模型的泛化性能有提升,则剪枝;否则,不剪枝

还是使用验证集对其进行性能评估(以好瓜为例):

  • 剪枝前:验证集中样本{4,5,8}被分类正确,得到验证集精度为3/7=42.9%
  • 剪枝后:根据未剪枝决策树节点⑥的样例数据,{青绿,乌黑}都是好瓜,验证集中样本{5,8,13}被分类错误;其他都被分类对了。所以,得到验证集的精度为4/7=57.1%

通过比较,57.1%>42.9%,划分后模型的泛化性能有提升,因此,对子树节点⑥进行剪枝

同理,对子树节点②进行后剪枝,剪枝后的决策树为:

在这里插入图片描述
通过对比预剪枝,我们能够发现,后剪枝过程是在构建一棵完整决策树之后进行的,且要自底向上对树中的所有非叶节点进行逐一考察,因此,训练时间开销要比未剪枝决策树和预剪枝决策树都大。但是后剪枝决策树通常比预剪枝决策树保留了更多的分支,一般情况下,后剪枝决策树的欠拟合风险更小,泛化性能往往也要优于预剪枝决策树

4、决策树剪枝总结


对于决策树的预剪枝和后剪枝,我们通常根据以下两点来进行评估:

1)泛化性能:

  • 预剪枝:过拟合风险降低,欠拟合风险增加
  • 后剪枝:过拟合风险降低,欠拟合风险基本不变
  • 泛化性能:后剪枝通常优于预剪枝

2)时间开销:

  • 预剪枝:训练时间开销降低,测试时间开销降低
  • 后剪枝:训练时间开销增加,测试时间开销降低
  • 时间开销:后剪枝通常小于预剪枝

5、附录


决策树分类在西瓜数据集上的应用如下

1)加载数据集

import pandas as pd
import matplotlib.pyplot as plt

# 加载数据集
path = r'C:\Users\cc\Desktop\watermelon_dataset\watermelon_3.csv'
data = pd.read_csv(path)
data.drop(columns=['编号', '密度', '含糖率'], inplace=True)
print(data.head().to_string())
'''
   色泽  根蒂  敲声  纹理  脐部  触感 好瓜
0  青绿  蜷缩  浊响  清晰  凹陷  硬滑  是
1  乌黑  蜷缩  沉闷  清晰  凹陷  硬滑  是
2  乌黑  蜷缩  浊响  清晰  凹陷  硬滑  是
3  青绿  蜷缩  沉闷  清晰  凹陷  硬滑  是
4  浅白  蜷缩  浊响  清晰  凹陷  硬滑  是
'''

2)数据预处理

from sklearn.preprocessing import OrdinalEncoder

# 序列编码
enc = OrdinalEncoder()
arr = enc.fit_transform(data)
data = pd.DataFrame(arr, columns=data.columns)
print(data.head().to_string())
'''
    色泽   根蒂   敲声   纹理   脐部   触感   好瓜
0   2.0   2.0   1.0    1.0   0.0   0.0   1.0
1   0.0   2.0   0.0    1.0   0.0   0.0   1.0
2   0.0   2.0   1.0    1.0   0.0   0.0   1.0
3   2.0   2.0   0.0    1.0   0.0   0.0   1.0
4   1.0   2.0   1.0    1.0   0.0   0.0   1.0
'''

3)划分训练集和验证集

# 特征
X = data.iloc[:, 0: -1]
# 标签
y = data.iloc[:, -1]
# 划分训练集和验证集
X_train = X.drop(index=[4, 5, 8, 9, 11, 12, 13])
y_train = y.drop(index=[4, 5, 8, 9, 11, 12, 13])
X_test = X.iloc[[4, 5, 8, 9, 11, 12, 13], :]
y_test = y.iloc[[4, 5, 8, 9, 11, 12, 13]]

4)拟合模型与评估

from sklearn.tree import DecisionTreeClassifier

# 决策树分类器
clf = DecisionTreeClassifier()
# 训练模型
clf.fit(X_train, y_train)
# 在验证集上评分
print(clf.score(X_test, y_test))   # 0.42857142857142855

5)绘制决策树

from sklearn.tree import plot_tree

# 决策树可视化
plt.rcParams["font.family"] = "SimHei"
plot_tree(clf, feature_names=data.columns, filled=True, rounded=True)
plt.show()

使用信息增益或基尼系数划分生成的决策树如图所示:

在这里插入图片描述



参考文章:
https://blog.csdn.net/zfan520/article/details/82454814
https://blog.csdn.net/u012328159/article/details/79285214


  • 15
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值