继上篇文章决策树之 ID3 与 C4.5,本文继续讨论另一种二分决策树 Classification And Regression Tree,CART 是 Breiman 等人在 1984 年提出的,是一种应用广泛的决策树算法,不同于 ID3 与 C4.5, CART 为一种二分决策树, 每次对特征进行切分后只会产生两个子节点,而ID3 或 C4.5 中决策树的分支是根据选定特征的取值来的,切分特征有多少种不同取值,就有多少个子节点(连续特征进行离散化即可)。CART 设计回归与分类,接下来将分别介绍分类树与回归树。
回归树与模型树
首先简单回忆线性回归:是对于数据集 $D = left {(x_i,y_i) ight }_{i=1}^N$ ,线性回归的模型为:$ ar{y}_i = heta ^T x_i $,损失函数可以记做:
[L( heta) = frac{1}{N}sum_i( y_i - ar{y}_i )^2]
或者向量形式(参考NG),对于 $Y = X heta$ ,损失函数为 $frac{1}{2}(X heta-y)^T(X heta-Y) $,对 $ heta$ 求导,即得:
[ heta = (X^TX)^{-1}X^TY]
Liner Regression 已经很强大,可以处理线性数据集,对于非线性数据集,可以考虑增加特征的办法,比如引入高次特征或者进行特征组合来增加模型的非线性能力。如果数据集不是很大,可以考虑不加特征的局部加权回归,这里需要考虑一个概念,即 Parametric 算法与 Non-Parametric 算法,简单介绍一下,Parametric 算法会用训练集训练数据得到模型参数,用做之后的预测;Non-Parametric 算法则并不会学习得到通用的参数,而是根据需求拟合模型。所以线性回归可以认为是一种 Parametric 学习算法,那么局部加权回归可以认定为非参数方法,因为局部加权只考虑离待预测样本 $x$ 近的那些点,所以对于待测样本,都要遍历数据集进行运算,速度会很慢,局部加权回归还对损失函数进行了一些改进:
[L( heta) = frac{1}{N}sum_iw_i(ar{y}_i - y_i)]
[w_i = exp left (frac{x_i-x}{2 au ^2} ight ) ]
这里 $ au$ 控制了权值变化的速率,每个样本 $x_i$ 都有一个权值,权值根据 $ au$ 来调整大小,离样本点 $x_i$ 越近的样本其权值却大,局部加权回归的预测模型同线性回归。值得注意的问题还有特征归一化与正则化,这里不展开了,关于局部加权回归与线性回归的图形分别如下:
线性回归是一个关于全局数据的模型,用一个唯一的目标优化来优化全数据集。当数据并呈现分段特性的时候,比如如下图所示的数据,全局共享一个优化目标显然不是一个很好的选择。这时可以对数据集进行划分,分而治之明显是一个不错的选择。下图所示的数据可以划分为 5 个分片分别进行处理,分片之后可以对每个分片做一个线性模型,这种情况称之为模型树;也可以简单的对分片后的数据取均值,这种情况就是普通的回归树。接下来分别对回归树与模型树进行介绍。
回归树采用均方误差作为损失函数,树生成时会递归的按最优特征与最优特征下的最优取值对空间进行划分,直到满足停止条件为止,停止条件可以人为设定,比如说设置某个节点的样本容量小于给定的阈值 $c$ ,或者当切分后的损失减小值小于给定的阈值小于给定的 $varepsilon $,则停止切分,生成叶节点。
对于生成的回归树,每个叶节点的类别为落到该叶节点数据的标签的均值,假设特征空间被划分为 $M$ 个部分,即现在有 $M$ 个叶节点分别为 $R_1,R_2,…,R_M$ , 对应的数据量分别为 $N_1,N_2,…,N_M$ ,则叶节点的预测值分别为:
[c_m = frac{1}{N_m}sum_{x_i in R_m} y_i ag{*}]
回归树为一颗二叉树,每次都是按特征下的某个取值进行划分,每一个内部节点都是做一个对应特征的判断,直至走到叶节点得到其类别,构建这棵树的难点在于如何选取最优的切分特征与切分特征对应的切分变量。回归树与模型树既可以处理连续特征也可以处理离散特征,对于连续特征,若这里按第 $j$ 个特征的取值 $s$ 进行切分,切分后的两个区域分别为:
[R_1(j,s) = left { x_i|x_i^j le s ight } R_2(j,s) = left { x_i|x_i^j > s ight }]
若为离散特征,则找到第 j 个特征下的取值 s :
[R_1(j,s) = left { x_i|x_i^j = s ight } R_2(j,s) = left { x_i|x_i^j e s ight }]
根据 $(*)$ 分别计算 $R_1$ 与 $R_2$ 的类别估计 $c_1$ 与 $c_2$, 然后计算按 $(j,s)$ 切分后得到的损失:
[min_{j,s} left [ sum _{x_i in R_1}(y_i –c_1)^2 + sum_{x_i in R_2} (y_i –c_2)^2 ight ]]
找到使损失最小的 $(j,s)$ 对即可,递归执行 $(j,s)$ 的选择过程直到满足停止条件为止。这里以连续特征为例,给出回归树的算法:
输入: 训练数据集 $D=left{ (x_1,y_1),(x_2,y_2),…,(x_N,y_N) ight}$
输出: 回归树 $T$
1)求解选择切分特征 $j$ 与 切分特征取值 $s$ ,$j$ 将训练集 $D$ 划分为两部分,$R_1$ 与 $R_2$ ,依照$(j,s)$ 切分后如下:
[R_1(j,s) = left { x_i|x_i^j le s ight } R_2(j,s) = left { x_i|x_i^j > s ight }]
[c_1 = frac{1}{N_1}sum_{x_i in R_1} y_i c_2 = frac{1}{N_2}sum_{x_i in R_2} y_i ]
2)遍历所有可能的解$(j,s)$,找到最优的 $(j^*,s^*)$ ,最优的解使得对应损失最小,按照最优特征 $(j^*,s^*)$ 来切分即可。
[min_{j,s} left [ sum _{x_i in R_1}(y_i –c_1)^2 + sum_{x_i in R_2} (y_i –c_2)^2 ight ]]
3)递归条用 $1) sim 2)$ ,知道满足停止条件。
4)返回决策树 $T$.
回归树主要采用了分治策略,对于无法用唯一的全局线性回归来优化的目标进行分而治之,进而取得比较准确的结果,但分段取均值并不是一个明智的选择,可以考虑将叶节点设置为一个线性函数,这便是所谓的分段线性模型树。为什么模型树效果好呢,可以通过下图来观察,左边为回归树,右边为模型树,可以看到模型树的效果还是好一些。
模型树只需在回归树的基础上稍加修改即可,对于分到叶节点的数据,采用线性回归的最小均方损失来计算该节点的损失,具体的求解方法可以参考 《Machine Learning in Action》 这本书。
分类树
分类树是 CART 中用来分类的了,不同于 ID3 与 C4.5 ,分类树采用基尼指数来选择最优的切分特征,而且每次都是二分。
基尼指数是一个类似与熵的概念,对于一个有 $K$ 种状态对应的概率为 $p_1,p_2,…,p_K$ 的随机变量 $X$ ,其 $Gini$ 定义如下:
[Gini(X) = sum_k p_k (1-p_k) = 1-sum_k p_k^2]
根据公式可得到伯努利分布 $X sim Bernoulli(p)$ 的基尼系数为:
[Gini(X) = sum_k p_k (1-p_k) = 2p(1-p)]
对于训练数据集合 $D$ ,假设共有 $K$ 个类别,$C_k$ 代表第 $k$ 类的样本子集,$|C_k|$ 为 $C_k$ 的大小,$|D|$ 为 $D$ 的大小,则集合 $D$的基尼系数为:
[Gini(D) = sum_k frac{|C_k|}{|D|}(1-frac{|C_k|}{|D|}) = 1- sum_k left (frac{|C_k|}{|D|} ight )^2]
类似于 $ID3$ 中的信息增益,假设现在用特征 $A$ 对数据进行分割,若特征 $A$ 为离散特征,则根据 $A$ 的某一可能取值 $a$ 将 $D$ 分为 $D_1$ 与 $D_2$
[D_1 =left {D | A=a ight } D_2 = left {D | A e a ight } ]
其实就跟回归树一样,对于连续特征,也类似于回归树。接下来便得到类似于条件熵的一个量 $Gini(D,A)$ ,即在已知特征 $A$ 的条件下集合 $D$ 的基尼指数:
[Gini(D,A) = frac{|D_1|}{|D|}Gini(D_1) + frac{|D_2|}{|D|}Gini(D_2)]
$Gini(D,A)$ 取值越大,样本的不确定性也越大,这一点与熵类似,所以选择特征 $A$ 的标准是 $Gini(D,A)$ 的取值越小越好。接下来以离散特征为例,给出分类树算法:
输入:训练数据集 $D=left{ (x_1,y_1),(x_2,y_2),…,(x_N,y_N) ight}$ ,停止条件
输出:分类树 $T$
1)利用特征 $A$ 的取值 $a$ 将数据分为两部分,计算 $A=a$ 时的基尼系数:
[Gini(D,A) = frac{|D_1|}{|D|}Gini(D_1) + frac{|D_2|}{|D|}Gini(D_2)]
2)对整个数据集中所有的可能特征 $A$ 以及其可能取值 $a$ 选取基尼系数最小的特征 $A^*$ 与特征下的取值 $a^*$,来将数据集切分,将数据 $D_1$、$D_2$ 分到两个子节点中去。
3)对子节点递归的调用 $1) sim 2)$ ,直至满足停止条件
4)返回 CART 树 $T$
算法的停止条件可以是节点中的样本数不能小于给定阈值,或者样本集的基尼系数小于给定阈值,或者没有更多的特征。最后给出一个 CART 用于分类的图:
剪枝
CART 中同样需要对生成的树进行剪枝操作,来避免模型过度拟合训练数据,类似于ID3,剪枝时使用的损失函数如下:
[C_a(T) = C(T) + a|T|]
$C(T)$为树 $T$ 对训练数据的误差,可以用基尼系数或者均方损失来表示,$a ge 0$ 代表一个权衡训练数据损失 $C(T)$ 与总节点数 $|T|$ 的参数,$C_a(T)$ 代表了树 $T$ 的整体损失,对于固定的 $a $,一定存在一个确定的使得 $C_a(T)$ 最小的子树,当 $a$ 偏大时, $|T|$ 偏小,树 $T$ 的规模偏小,反之,树 $T$ 的规模偏大,Breiman 等人采用递归的方法对 CART 进行剪枝,将 $a$ 从小增大 $0=a_0 < a_1<…<a_n$ ,如此产生的区间 $a in [a_i,a_{i+1}) , i =1,2,…,n$ ,用对应此区间的 a 产生一系列的子树序列 $left{T_0,T_1,…,T_n ight}$ 这里 $T_{i+1}$ 总是由 $T_i$ 剪枝后产生。
剪枝是从 $T_0$ 开始的,对 $T_0$ 的任意内部节点 $t$ ,把节点 $t$ 看做叶节点计算其损失函数:
[C_a(t) = C(t) + a|1|]
然后计算以 $t$ 为根节点时,子树 $T_t$ 的损失函数
[C_a(T_t) = C(T_t)+ a|T_t|]
要不要把 $t$ 的子树 $T_t$ 归并到 $t$ 上呢,关键看这个损失了,如果单节点 $t$ 的损失小于或等于整个子树 $T_t$ 的损失,合并当然好了,啥时候 $C_a(t) = C_a(T_t)$ 呢?如下所示:
[C_a(t) = C_a(T_t) Rightarrow C(t) + a|1| = C(T_t)+ a|T_t| Rightarrow a=frac {C_t-C(T_t)}{|T_t|-1}]
明显的,只要满足以上条件, $T_t$ 与 $t$ 具有相同的损失,而且 $t$ 的节点少,所以进行剪枝,剪枝就是这么一个过程:
从 $T_0$ 开始,对于每一个内部节点 $t$ ,计算:
[g(t) = frac {C_t-C(T_t)}{|T_t|-1}]
$g(t)$ 表示剪枝后整体损失函数的减小的程度,在 $T_0$ 中剪掉 $g(t)$ 最小的树 $T_t $ ,将得到的树称作 $T_1$ ,同时将最小的 $g(t) $设置为 $a_1$ , $T_1$ 为区间$[a_1,a_2)$上的最优子树,如此剪下去,在这一过程中,不断增加 $a$ 的取值,产生新的区间,最终会得到一组决策树 $left{T_0,T_1,…,T_n ight}$ 对应一组确定的权衡参数 $left{a_0,a_1,…,a_n ight}$ ,通过验证集合中每颗树的总体误差,也就得到了最终的最优决策树 $T^*$ ,这里给出CART 剪枝算法:
输入:CART 生成树 $T_0$
输出:剪枝后的最优树 $T^*$
1)设 $k = 0$ , $T = T_0$ ,$a=+infty$
3) 自下而上的对内部节点 t 计算 :
[g(t) = frac {C_t-C(T_t)}{|T_t|-1} ]
[a = min(a,g(t))]
4) 自上而下的访问内部节点 $t$ , 对最小的 $g(t) = a$ 进行剪枝,并对叶节点 $t$ 以多数表决形式决定其类别,得到树 $T$
5) $k = k + 1$, $a_k = a $,$T_k = T$
6) 如果 $T$ 为非单节点树,回到 4).
7) 对于产生的子树序列 $left{T_0,T_1,…,T_n ight}$ 分别计算损失,得到最优子树 $T^* $ 并返回.
至此,关于CART 的内容全部介绍完毕,CART 剪枝还是不同于 ID3 与 C4.5 的 , 另外 CART 为二叉树,且可用于回归。
参考:http://www.stat.cmu.edu/~cshalizi/350-2006/lecture-10.pdf
《统计学习方法》
《Machine Learning in Action》