本篇是决策树系列的第二篇,介绍一下决策树的剪枝过程。过拟合是决策树构建过程中常见的问题,信息失衡、噪声等问题都会导致过拟合,剪枝则是提高决策树模型泛化能力的重要手段,下面对常用的剪枝方法作一些介绍。

1. 预剪枝

决策树系列第一篇《分类:决策树——树的生长》中提到过,树的生长是一种“完全”式的生长,终止条件也仅有“所有的样本属于同一类,或者所有的样本具有相同的属性值”这两条,但有时可以再增加一些终止条件,提前结束树的生长,这个过程相当于在一棵“完全”生长的树上剪去一些枝干,这就是预剪枝过程。例如,可以增加这样一条生长终止条件:当结点划分后度量参数(信息增益、增益率或者基尼指数)变化小于设定阈值时,则将该结点当作叶子结点,不予划分。

预剪枝过程简单,计算量也较小,但是它有两个缺点,一个是前面提到的终止生长时设定的阈值,该值通常难以确定,另一个则是会出现“欠拟合”现象,在当前结点上的划分效果不理想时,但其子女结点上的划分效果可能会比较理想,预剪枝过程容易发生这种情况。

一般预剪枝方法在实际中不会用到。

2 . 后剪枝

后剪枝是在决策树生长停止之后进行的剪枝,按照剪枝的方向,分为从上至下(top-bottom)和从下至上(bottom-top)。后剪枝方法有多种,除了剪枝方向的区别外,主要的区别在在于剪枝的条件,现依据剪枝条件的不同,介绍一下常用的几种后剪枝方法。

1.1 REP(Reduced Error Pruning)方法

REP方法是Quinlan教授提出的,采用从下至上(bottom-top)的剪枝方式。使用该方法时,需要将样本划分为训练集和验证集,然后从树底到树顶,将每个内部结点生成的子树用该结点代替,实现剪枝,用验证集来判断剪枝前后的误差,若剪枝后误差增大,则取消剪枝,反之则剪枝。

从剪枝的过程来看,REP方法是比较简单的,每个子树只需要访问一次,所以它的计算过程是线性的。该方法的缺点一个是需要将样本集划分为训练集与验证集,这在样本量不足够大时比较影响模型构建;另外一个是当验证集/训练集中包含的信息在训练集/验证集中未出现时,剪枝反而降低了模型泛化能力。

样本量不大时一般不使用REP剪枝方法。

1.2 PEP(Pessimistic Error Pruning)方法

PEP方法是Quinlan教授为了弥补REP方法需要单独的验证集的缺点而提出的剪枝方法,模型的构建、剪枝过程使用同一个样本集,该方法使用采用从上至下(top-bottom)的方式。由于剪枝时采用的同一样本集,因此更趋向于不剪枝,毕竟更多的子树能做更准确的分类,为此PEP方法中为每一个叶子结点引入了惩罚项 \Omega ,一般取 \Omega =1/2 。对于一棵二叉树来说, \Omega =1/2 意味着只要能够改善一个训练记录的分类,就应该划分结点;对于一棵m叉树来说, \Omega =1/2 意味着必须改善 \left | m/2 \right | 个训练记录的分类时才应该划分结点,其中 \left | m/2 \right | 表示大于 m/2 的最小整数。因此,在引入惩罚项后,更多的子树就不一定能做到更准确的分类了。

未引入惩罚项前,叶子结点 t_{i} 的误分类率 r(t_{i}) 定义为

e(t_{i}) 为该结点上的误分类数, n(t_{i}) 为该结点所包含的样本数。引入惩罚项后,其误差率定义为

假设一棵子树的叶子结点数为k,则该子树的误分类数 e(T) 与误分类率 r(T) 分别为

将该子树剪掉、用叶子结点代替后,其误分类数 e'(T)

e(T) 为未引入惩罚项前的误分类数。对于指定的子树,树上的样本数是确定的,因此可以用误分类数代替误分类率,按照REP方法中的剪枝策略,当满足

时即将子树剪掉。

引入了惩罚项后,剪枝条件还是比较严格的,拿二叉树来说,很容易做到改善一个训练样本的分类结果,从而取消剪枝。为此,Quinlan教授重新定义了剪枝的条件。在一颗子树上,一个样本的分类结果只有“正确”和“错误”两种,这实际上是一个伯努利过程,错误分类的概率为 p ,当子树上包含 k 个样本时,那么这 k 个样本的分类结果就服从概率为 p 的二项分布,期望为 kp ,方差为 kp(1-p) 。对于一棵包含 n 个样本的子树,其误分类率 r(T_{i}) 是可以统计出来的(即已知的,见式(4)),即

则该子树上被正确分类的样本的标准差为

尽管当前子树的误分类数为 e(T_{i}) ,但是参考其误分类数的标准差来看,对于一些待分类的样本,该子树的误分类数可能会达到

为此,Quinlan教授将子树的剪枝条件放宽为

PEP方法是后剪枝方法中唯一采用从上至下(top-bottom)剪枝的方法,因而其有着与预剪枝方法一样的优点,就是效率高,是后剪枝方法中精度较高的方法之一,并且不需要验证数据集。

1.3 CCP(cost-complexity Pruning)方法

CCP方法是Breiman等人提出的,是CART算法中采用的剪枝方法,剪枝时采用从下至上(bottom-top)的方式。

首先,定义子树的损失函数

式(9)中, T 表示任意的子树, C(T) 表示子树对训练数据的预测误差(如基尼指数、误分类率等,由于CART算法使用基尼指数作度量,因此这里一般使用基尼指数), |T| 表示子树的叶子结点数, \alpha 为子树的参数( \alpha \geqslant 0 ), C_{\alpha }(T) 为指定参数 \alpha 下子树 T 的整体损失。

先来定义最优子树: 最优子树是指在训练样本上损失函数最小的子树 。从式(9)中对子树的损失函数定义可以看到,当 \alpha 较大时子树叶子结点的个数(子树的复杂度)对损失函数的影响较大,最优子树偏小;当 \alpha 较小时子树的预测误差对损失函数影响较大,最优子树偏大。极端情况下,当 \alpha =0 时整体树是最优的,当 \alpha \rightarrow \infty 时根节点构成的单结点树是最优的。可以证明,对于一个给定的 \alpha 值,最优子树是唯一的,由于 \alpha 的取值范围为 [0,+\infty ] ,因此在 \alpha 增大的过程中可以得到一系列的最优子树。对于一个决策树,由于内部结点个数是一定的,因此 \alpha 可能在一个区间范围内对应的最优子树都是同一棵子树。接下来,考虑一下如何寻找给定 \alpha 值下的最优子树。

显然,通过递增 \alpha 值,然后遍历树上所有结点计算损失函数、得到最优子树的方式是不现实的, \alpha 值的连续变化导致这个计算复杂度难以估计,因此我们可以换一个思路来寻找最优子树。试想一下,既然我们的目的就是为了剪枝,那何不采用遍历树上所有内部结点(非叶子结点)、逐个剪枝,比较得到的子树的损失函数的方式来确定最优子树呢?这个计算复杂度只与内部结点个数相关。

具体的过程以树的任一内部结点 t 来说明,以结点 t 为根节点生成的子树,其损失函数为

以结点 t 替换子树、得到单结点树的损失函数为

\alpha =0及充分小时,有如下关系

随着 \alpha 逐渐增大,到某个值时存在如下关系

\alpha 再继续增大时,不等式(12)将反向。当等式(13)成立时

此时将该子树剪去(这里剪去的意思是用单一结点代替其生成的子树,后面不再说明)后损失函数不变,但是整体树的结点更少,因此应该执行剪枝。对结点 t 来说,当公式(14)成立时,剪枝前后损失函数不变的只是它本身,但整体树的损失函数由于 \alpha 的取值而发生变化,很显然 \alpha 越小,余下的树的损失函数越小,也越优(可以参照公式(9)理解)。有人可能会想,那我剪去叶子结点更多的子树可以吗?答案是不可以,因为这会改变余下的树的预测误差,由公式(12)可知反而会增大损失函数。

从下至上,对树的每一个内部结点按照公式(14)计算出 \alpha 值,选择其中最小 \alpha 值对应的结点,将以该结点生成的子树剪枝,完成本轮剪枝过程。

说完了单轮的剪枝过程,现在我们以整体树 T_{0} 为初始树说明CPP方法中完整的剪枝过程。树 T_{0} 经过第一轮剪枝后得到树 T_{1} ,第一轮剪枝结点对应的 \alpha 值为 \alpha_{1} (按照公式(14)计算出),那树 T_{1} 是不是一个全局的最优子树呢?不见得,就算不用验证集进行验证我们也可以这样说,因为树 T_{1} 只是 \alpha\alpha_{1} 时的最优子树,由前面所讲内容及公式(12)可知,实际上树 T_{1} 也是 \alpha[0,\alpha _{1}] 上的最优子树。如果只在树 T_{0} 上变化 \alpha 值,不管 \alpha 取多少,根据公式(12)、(13)、(14)所说明的内容,最优的子树仍然是树 T_{1} 。因此,我们可以以树 T_{1} 为初始树,继续下一轮剪枝,此时初始树的结构变了,这样可以得到最优子树 T_{2} 及对应的 \alpha_{2} (显然 \alpha _{2}>\alpha _{1} ),然后以树 T_{2} 为初始树继续这个过程,知道整体树 T_{0} 的根节点,最终我们会得到一系列最优子树 T_{0},T_{1},...,T_{n} ,这些最优子树是训练集上的最优子树。

在验证集上使用交叉验证法验证 T_{0},T_{1},...,T_{n} ,其中表现最好的子树将作为的剪枝结果。

1.4  EBP(Error-Base-Pruning)方法

EBP剪枝方法是C4.5算法中默认使用的剪枝方法,它采用的是一种从下至上的剪枝方式。