目录
- 回归树的生成
- 回归树的定义
- 预测值的确定
- 特征空间的划分
- 算法流程
- 分类树的生成
- 分类树的对比总结
- 基尼指数的计算
- 算法流程
- CART剪枝
- ID3、C4.5 剪枝的不足
- ID3、C4.5 剪枝改进:CART 剪枝
- CART 剪枝的案例
- CART 剪枝过程图解
- CART 剪枝算法总结
分类与回归树(classification and regression tree,简称 CART)既可以用于分类,也可以用于回归。与 ID3 和 C4.5 算法(回顾
第十一课决策树)不同,CART 是
二叉决策树,内部结点特征的取值为是和否,左分支的取值为是,右分支的取值为否。
CART 算法包含特征选择、决策树的生成和决策树的剪枝三个部分,这个流程与 ID3、C4.5算法是一样的。回归树使用平方误差进行特征选择,而分类树使用基尼指数进行特征选择。
回归树的生成
回归树的定义
回归树属于决策树的一种,准确来说是用来解决回归问题的二叉决策树。既然是解决回归问题,那么回归树的预测值就是一个连续值。下面是回归树的简单图示:
从图中可以看出,已经构建好的回归树可以根据身高和年龄这两个特征来预测体重的取值。例如:输入的特征向量 [168,24] 满足:身高小于等于 175cm,年龄大于 18岁,故预测体重的取值为 58kg;
一棵回归树对应着特征空间的一个划分以及在划分的单元上的输出值。假设已将特征空间划分为 个单元 ,,…,,并且在每个单元 上有一个固定的输出值 ,则回归树模型可以表示为:
其中
上面的回归树将二维特征空间 [身高,年龄]
划分为 3 个单元,由于特征向量 [168,24] 属于 单元,故体重的预测值为 58:
预测值的确定
假设特征空间的划分已确定,如上图所示, 单元对应的预测值 应该尽量使其中的训练样本的预测损失最小。使用平方误差作为损失函数,假设 中有三个训练样本(值为) ,则预测值为 产生的损失为:
令损失函数的导数为零,可以求出损失函数取最小值时对应的预测输出值:
由此可知,划分单元 上的最优预测值为该单元中所有训练样本标记值的平均值:
其中,为中训练样本的数量
特征空间的划分
上面讨论了在特征空间的划分已确定的前提下,如何确定最优的预测值。下面是划分特征空间的具体方法。
特征空间的划分是递归地二分每个特征,从而将特征空间划分为有限个单元。要解决的问题有两个:
- 第一,选择哪个特征对样本进行划分?
- 第二,切分点如何选取?
还是体重预测的例子,从根节点开始对特征空间进行划分。在根节点选择了身高这个特征,切分点为 175,身高小于等于 175 的样本被划分到左子树,否则被划分到右子树。实际上也可以选择年龄这个特征对样本进行划分,并且切分点的取值也是可选的。问题来了,在回归树的某个结点进分裂(或者叫特征空间的划分)时,如何判断划分的好坏?
回归树的生成是递归地将训练样本二分到左右子树中,并且每个子树对应的划分单元都有一个固定的最优预测值(训练样本标记值的均值),所以我们可以使用左右子树中训练样本的平方误差和来衡量划分的好坏。
假设选择特征 和它取的值 作为划分变量和切分点,则左右子树对应的划分区域定义为:
根据如上划分, 和 中训练样本的平方损失和为 ,计算公式如下:
每次进行特征空间的划分时,只要遍历训练样本所有的特征和可能的取值,然后选择平方损失最小的特征和切分点即可
算法流程
输入:训练数据集
输出:回归树
在训练数据集所在的特征空间里,递归地将每个区域划分为两个子区域,并确定每个子区域的输出值,构建二叉决策树,训练过程如下:
- 1.使用如下公式选择当前结点最优的切分变量 和切分点 ,并确定左右分支的预测值;
是训练样本的第 个特征, 是该特征的某一个取值,在有限的训练样本中, 和 都是有限的,故可以遍历所有的组合,找到使得平方损失最小的切分变量(特征)和切分点,将样本划分到左右两个子区域中;
实例如下:
import numpy as np
# 构造一些训练样本
data = np.array([[2,6,9],
[2,8,4],
[3,3,8],
[3,6,7],
[5,3,5],
[5,8,2]])
# 提取训练样本的特征向量
X_train = data[:,:-1] # X_train.shape (6,2)
# 提取训练样本的标记值
y_train = data[:,-1]
# 寻找最优切分点
def find_split(X,label):
# 存储不同特征、切分点以及对应的训练样本损失
result = dict()
# 遍历每个特征的索引
for j in range(X.shape[1]):
# 遍历所选特征的不同取值
for s in set(X[:,j]):
# 初始化左右两个子区域和对应的预测损失
R1,R2,loss = dict(),dict(),0
# 遍历训练样本,根据特征切分点将样本划分到不同区域中
for x,y in zip(X,label):
if x[j]<=s:
R1[tuple(x)] = y
else:
R2[tuple(x)] = y
# 计算左右两个区域的预测值,并累加对应的平方损失值
if len(R1)!=0:
c1_hat = sum([y_i for y_i in R1.values()])/len(R1)
loss += sum([(y_i-c1_hat)**2 for y_i in R1.values()])
if len(R2)!=0:
c2_hat = sum([y_i for y_i in R2.values()])/len(R2)
loss += sum([(y_i-c2_hat)**2 for y_i in R2.values()])
# 存储当前特征索引和切分点以及对应的平方损失
result[loss] = (j,s)
# 返回平方损失最小时对应的特征索引和切分点取值
"""
min(dict)对字典的key进行操作:
print(min({1:"a",2:"b",3:"c"})) #1
print(min({"f":1,"b":2,"c":3})) #b
"""
return result[min(result)]
# 对当前结点中的训练数据,寻找最优的特征与切分点
>>> find_split(X_train,y_train)
# 输出结果表示 x1<=6 时,样本被划分到左子树中,否则被划分到右子树
(1, 6)
- 2.对左右两个子区域调用步骤1,直至满足停止条件。
- 3.将特征空间划分为 个区域 ,,…,,生成回归决策树:
CART算法中的回归树是通过最小化训练样本的平方损失得到的,因此又叫最小二乘回归树
分类树的生成
分类树的对比总结
分类决策树的生成算法有三种,除了第十一课决策树的 ID3 和 C4.5 算法,CART 算法也包含了分类树的生成算法;
使用 CART 算法生成分类决策树与 ID3、C4.5 算法的区别:
- 首先,CART 算法使用基尼指数选择最优特征,同时决定该特征的最优二值切分点;而 ID3 算法使用信息增益选择最优特征,C4.5 算法使用信息增益比选择最优特征;
- 其次,CART 算法生成的分类树是二叉决策树,而 ID3、C4.5 算法生成的分类树是多叉树
基尼指数的计算
基尼指数是离散变量概率分布的函数。在分类问题中,假设训练集样本类别取值的概率分布为 ,则对应的基尼系数可以通过如下公式进行计算:
其中,为样本类别数,为样本属于第类的概率;
如图所示, 表示训练样本的类别取值, 是对应的概率,计算样本类别的基尼指数为:
基尼指数越小,样本类别的不确定性就越小,例如上面例子中,如果 的概率为 1,其他两个类别的概率为 0 ,则 ,表示样本类别的不确定性为 0 ;
对于给定的训练样本集合 ,可以统计各类样本的占比,然后计算样本集合 关于样本类别的基尼指数:
其中,为样本类别数,为属于第类的样本子集;
对于某个离散特征 ,根据是否取某一个可能值 ,可以将样本集合 划分为两个子集:
在特征 的条件下,集合 的基尼指数定义为:
前面说过,CART 算法使用基尼指数选择最优特征,同时决定该特征的最优二值切分点;具体来说就是遍历不同的特征和所有可能的取值,然后选择基尼指数最小的特征和切分点
算法流程
输入:训练数据集 ,算法停止的条件
输出:CART 分类树
根据训练数据集
- 1.假设当前结点的训练集为 ,对于现有的每一个特征 和可能的取值 ,使用如下公式选出基尼指数最小的特征和切分点:
- 2.将训练样本划分到左右两个子结点中,根据多数表决的原则确定当前结点的预测值。下面是根据最优特征和最优切分点划分样本子集的方法:
- 3.对两个子结点递归地调用步骤1和2,直到满足算法停止的条件
算法停止的条件有:当前节点中的样本个数小于设定的阈值;当前结点的基尼指数小于设定的阈值(基本属于同一类样本);用于当前结点分裂的特征集合为空。
CART剪枝
ID3、C4.5 剪枝的不足
决策树的剪枝算法,其基本思想是:遍历决策树的内部结点,若剪枝后决策树的损失函数小于剪枝前的决策树,则对该内部结点进行剪枝,同时该内部结点变为叶子结点,剪枝过程的示意图如下:
决策树的损失函数
决策树的叶子节点越多,模型越复杂。决策树的损失函数考虑了模型复杂度;可以通过优化其损失函数来对决策树进行剪枝。决策树的损失函数计算过程如下:
- 计算叶子结点 的样本类别经验熵:
其中,为叶子节点 包含的训练样本个数,为叶子节点 中样本类别为 的样本个数;对于叶子结点 来说,其样本类别的经验熵越小, 中训练样本的分类误差就越小。当叶子结点 - 计算决策树 在所有训练样本上的损失之和 :
为叶子节点 包含的训练样本个数,是决策树 包含的叶子节点个数;对于叶子结点 中的每一个训练样本,其类别标记都是随机变量 - 计算考虑模型复杂度的的决策树损失函数:
为正则化系数,控制模型复杂度;决策树的叶子结点个数表示模型的复杂度,通过最小化上面的损失函数,一方面可以减少模型在训练样本上的预测误差,另一方面可以控制模型的复杂度,保证模型的泛化能力。
但是, 仅靠人工经验值的判断还是很难保证模型在特定数据场景下的泛化性能。
ID3、C4.5 剪枝改进:CART 剪枝
针对 ID3 和 C4.5 剪枝算法的不足,CART 算法做了如下改进:对于
现在问题是:
CART 剪枝算法的做法是在
CART 剪枝的案例
下面来看一个例子:
如上图所示,
对于整个决策树 ,它的损失为叶子结点经验损失的和,从前面决策树的损失函数表达式可知,正则化系数 越大,剪枝后的决策树结构就越简单,叶子结点数就越少。极端情况下,当 时,不剪枝;当
如下图所示,对 任意内部结点 (这里取7号结点)构成的子树 进行剪枝:
时,剪枝后的损失大于剪枝前,故不剪枝。对比上面的两个虚线框,由于剪枝前的 叶子结点更多一些,而每个叶子结点都会产生一个 的损失,故当 增大时, 的损失增大量要比 的多,当 为了方便对比,这里给出7号结点构成的子树 剪枝前后的损失:
令二者的损失相同,可以求出对应的 值:
当 大于 1 时,比如 ,对比两个虚线框中决策树的损失,只有正则化项增加了,且 比 多增加了 1个 将上面剪枝后的决策树记为 。对于 ,采取和 一样的处理方式,先计算内部结点剪枝前后结构风险相同的 值,当 大于等于这个临界值时,对 进行剪枝,如下图所示:
将上图 3 号结点剪枝后得到的子树记为 ,增大 ,达到临界点后对 继续剪枝:
直到剪枝后的决策树变成由根节点和两个叶子结点构成的子树为止,本例中记为 ,如图所示:
CART 剪枝过程图解
对于上述的剪枝过程,可以用一幅图来展示:
从图中可以看出,当 时,不剪枝;当 时,剪枝得到子树 ;当 时,剪枝得到子树 ;当 时,剪枝得到 ;其中, 为剪枝前后损失相同的临界点。需要注意的一点是:每次计算 的临界点时,是在未剪枝决策树的所有内部结点进行的,每个内部结点都可以计算出一个临界 值,但我们需要选择最小的那个;举例说明,如下图所示:
对于 ,我们需要根据图中 的计算公式,对所有的内部结点 1,2,3,7 计算出一个值,然后取最小值。为了方便展示与理解,假设在所有示例中,虚线框里的内部结点所计算出的
再回顾 CART 剪枝过程图,图中横坐标为超参数 ,纵坐标为决策树 的结构风险(损失)。从图中可以看出, 结构风险的取值范围是:[21,26], 结构风险的取值范围是:[26,30], 和 在
观察上图,还有一个规律: 的经验风险为 21,它有 5 个叶子结点,所有右边界的结构风险为 ; 的经验风险为 22,它有 4 个叶子结点,所以右边界的结构风险为 。所以对于图中不同的决策树,当决策树的结构固定时,引起结构风险发生变化的是横坐标 ;
假如将 和 同时从 处向右平移 个单位(),则二者结构风险中的正则化项将同时增加,其中 结构风险的正则化项增加 5 个, 结构风险的正则化项增加 4 个 。可见, 平移到 [1,2) 区间中的 结构风险是要大于 的,因而需要剪枝成为 ;
上述过程得到的是 在不同区间下剪枝后的子树,如示例中的 、、,这些子树是依次嵌套的。使用独立的验证集选出这些子树中经验损失(如平方误差、基尼指数)最小的子树,就是剪枝后的最优子树
CART 剪枝算法总结
输入:CART 算法生成的决策树
输出:剪枝后的最优子树
- 1.初始化 ,;
- 2.初始化 ,遍历 的内部结点 ,依次计算:
这里每遍历一个内部结点,都把其对应的 值记录下来,方便下一步和最小的 - 3.对 的内部结点 进行剪枝,得到剪枝后的决策树 ;且内部结点
- 4.令 , ,;
- 5.若 不是由根结点和两个叶子结点构成的树,则返回步骤2,否则令 ;
- 6.采用交叉验证法,在子树序列 ,,…, 中选择最优子树