在机器学习领域,深度学习(Deep Learning \text {Deep Learning} Deep Learning )一直被神经网络统治着,而浅层学习(Shallow Learning \text {Shallow Learning} Shallow Learning )任然属于树模型的领地。一方面,尽管深度学习在大规模学习上表现强大,但它在小规模学习上的表现却差强人意;另一方面,集成树模型(RF \text {RF} RF 、GBDT \text {GBDT} GBDT 、XGBoost \text {XGBoost} XGBoost 等)因其模型解释度高、调参难度小、运行速度快、几乎不需要特征工程等优点,在中小规模数据集上完全碾压深度学习,而且对于“异质类数据”(比如风控场景中的年龄、收入、城市这类数据),即便在大规模数据集上,集成树模型也比深度学习表现更好。在实际应用中,Facebook、阿里巴巴等大企业都在使用结合LR的GBDT \text {GBDT} GBDT 作为点击率预估、广告推荐等重要业务的技术支撑,而XGBoost \text {XGBoost} XGBoost 更是在近些年的Kaggle算法大赛中屡屡绽放异彩。
本文介绍树模型的基础算法ID3、C4.5、CART,如果你想了解集成树模型(随机森林、梯度提升树等),可以参阅我的另两篇博文:
集成学习算法之:Bagging \text {Bagging} Bagging 方法与随机森林
集成学习算法之:Boosting \text {Boosting} Boosting 方法与AdaBoost \text {AdaBoost} AdaBoost 、GBDT \text {GBDT} GBDT
ID3 \text {ID3} ID3 决策树
ID3 \text {ID3} ID3 是一个起源很早的经典算法。它的思想基于信息论,以信息增益来度量特征选择,每次选择信息增益最大的特征进行分支,算法采用自顶向下的贪婪搜索遍历所有可能的决策树空间。
信息增益
“信息熵” 是度量样本集合纯度最常用的一种指标。假定当前样本集合 D D D 中第 k k k 类样本所占的比例为 p k ( k = 1 , 2 , … , ∣ Y ∣ ) p_{k}(k=1,2, \ldots,|\mathcal{Y}|) p k ( k = 1 , 2 , … , ∣ Y ∣ ) , 则 D D D 的信息熵定义为:
Ent ( D ) = − ∑ k = 1 ∣ Y ∣ p k log 2 p k \operatorname{Ent}(D)=-\sum_{k=1}^{|\mathcal{Y}|} p_{k} \log _{2} p_{k} Ent ( D ) = − k = 1 ∑ ∣ Y ∣ p k log 2 p k
信息熵Ent ( D ) \operatorname{Ent}(D) Ent ( D ) 的值越小,集合D D D 的确定性越高,纯度越高。假定离散属性 a a a 有 V V V 个可能的取值 { a 1 , a 2 , … , a V } \left\{a^{1}, a^{2}, \ldots, a^{V}\right\} { a 1 , a 2 , … , a V } ,若使用 a a a 来对样本集 D D D 进行划分,则会产生 V V V 个分支结点,其中第 v v v 个分支结点包含了 D D D 中所有在 属性 a a a 上取值为 a v a^{v} a v 的样本,记为 D v D^{v} D v ,计算出 D v D^{v} D v 的信息熵,再考虑到不同的分支结点所包含的样本数不同,给分支结点赋予权重 ∣ D v ∣ / ∣ D ∣ \left|D^{v}\right| /|D| ∣ D v ∣ /∣ D ∣ ,即样本数越多的分支结点的影响越大,于是可计算出用属性 a a a 对样本集 D D D 进行划分所获得的 “信息增益” (information gain):
Gain ( D , a ) = Ent ( D ) − ∑ v = 1 V ∣ D v ∣ ∣ D ∣ Ent ( D v ) \operatorname{Gain}(D, a)=\operatorname{Ent}(D)-\sum_{v=1}^{V} \frac{\left|D^{v}\right|}{|D|} \operatorname{Ent}\left(D^{v}\right) Gain ( D , a ) = Ent ( D ) − v = 1 ∑ V ∣ D ∣ ∣ D v ∣ Ent ( D v )
树的生成
以上面数据集为例(根据西瓜外观对西瓜好坏进行分类),共包含17 个训练样本。在决策树学习开始时,根结点包含 D D D 中的所有样例,其中正例占 p 1 = 8 17 p_{1}=\frac{8}{17} p 1 = 17 8 ,反例占 p 2 = 9 17 p_{2}=\frac{9}{17} p 2 = 17 9 ,于是,根据公式可计算出根结点的信息熵为:
Ent ( D ) = − ∑ k = 1 2 p k log 2 p k = − ( 8 17 log 2 8 17 + 9 17 log 2 9 17 ) = 0.998 \operatorname{Ent}(D)=-\sum_{k=1}^{2} p_{k} \log _{2} p_{k}=-\left(\frac{8}{17} \log _{2} \frac{8}{17}+\frac{9}{17} \log _{2} \frac{9}{17}\right)=0.998 Ent ( D ) = − k = 1 ∑ 2 p k log 2 p k = − ( 17 8 log 2 17 8 + 17 9 log 2 17 9 ) = 0.998
然后,我们要计算出当前属性集合 { \{ { 色泽, 根蒂, 敲声, 纹理, 脐部, 触感} 中每个属性的信息增益。以属性 “色泽”为例,它有 3 个可能的取值 :{ \{ { 青绿, 乌黑, 浅白 } 。若使用该属性对 D D D 进行划分则可得到 3 个子集,分别记为 D 1 D^{1} D 1 (色 泽=青绿 ) , D 2 ( ), D^{2}( ) , D 2 ( 色泽 = = = 乌黑 ) , D 3 ), D^{3} ) , D 3 (色泽=浅白)。子集 D 1 D^{1} D 1 包含编号为 { 1 , 4 , 6 , 10 , 13 , 17 } \{1,4,6,10,13,17\} { 1 , 4 , 6 , 10 , 13 , 17 } 的 6 个样例,其中正例占 p 1 = 3 6 p_{1}=\frac{3}{6} p 1 = 6 3 ,反例占 p 2 = 3 6 ; D 2 p_{2}=\frac{3}{6} ; D^{2} p 2 = 6 3 ; D 2 包含编号为 { 2 , 3 , 7 , 8 , 9 , 15 } \{2,3,7,8,9,15\} { 2 , 3 , 7 , 8 , 9 , 15 } 的 6 个样例,其中正、反例分别占p 1 = 4 6 , p 2 = 2 6 ; D 3 p_{1}=\frac{4}{6}, p_{2}=\frac{2}{6} ; D^{3} p 1 = 6 4 , p 2 = 6 2 ; D 3 包含编号为 { 5 , 11 , 12 , 14 , 16 } \{5,11,12,14,16\} { 5 , 11 , 12 , 14 , 16 } 的 5 个样例, 其中正、 反例分别占 p 1 = 1 5 , p 2 = 4 5 p_{1}=\frac{1}{5}, p_{2}=\frac{4}{5} p 1 = 5 1 , p 2 = 5 4 。根据公式可计算出用 “色泽”划分之后所获得的 3 个分支结点的信息熵为:
Ent ( D 1 ) = − ( 3 6 log 2 3 6 + 3 6 log 2 3 6 ) = 1.000 Ent ( D 2 ) = − ( 4 6 log 2 4 6 + 2 6 log 2 2 6 ) = 0.918 Ent ( D 3 ) = − ( 1 5 log 2 1 5 + 4 5 log 2 4 5 ) = 0.722 \begin{array}{l}
\operatorname{Ent}\left(D^{1}\right)=-\left(\frac{3}{6} \log _{2} \frac{3}{6}+\frac{3}{6} \log _{2} \frac{3}{6}\right)=1.000 \\
\operatorname{Ent}\left(D^{2}\right)=-\left(\frac{4}{6} \log _{2} \frac{4}{6}+\frac{2}{6} \log _{2} \frac{2}{6}\right)=0.918 \\
\operatorname{Ent}\left(D^{3}\right)=-\left(\frac{1}{5} \log _{2} \frac{1}{5}+\frac{4}{5} \log _{2} \frac{4}{5}\right)=0.722
\end{array} Ent ( D 1 ) = − ( 6 3 log 2 6 3 + 6 3 log 2 6 3 ) = 1.000 Ent ( D 2 ) = − ( 6 4 log 2 6 4 + 6 2 log 2 6 2 ) = 0.918 Ent ( D 3 ) = − ( 5 1 log 2 5 1 + 5 4 log 2 5 4 ) = 0.722
于是, 根据公式可计算出属性 “色泽” 的信息增益为:
Gain ( D , 色泽 ) = Ent ( D ) − ∑ v = 1 3 ∣ D v ∣ ∣ D ∣ Ent ( D v ) = 0.998 − ( 6 17 × 1.000 + 6 17 × 0.918 + 5 17 × 0.722 ) = 0.109 \begin{aligned}
\operatorname{Gain}(D, \text { 色泽 }) &=\operatorname{Ent}(D)-\sum_{v=1}^{3} \frac{\left|D^{v}\right|}{|D|} \operatorname{Ent}\left(D^{v}\right) \\
&=0.998-\left(\frac{6}{17} \times 1.000+\frac{6}{17} \times 0.918+\frac{5}{17} \times 0.722\right) \\
&=0.109
\end{aligned} Gain ( D , 色泽 ) = Ent ( D ) − v = 1 ∑ 3 ∣ D ∣ ∣ D v ∣ Ent ( D v ) = 0.998 − ( 17 6 × 1.000 + 17 6 × 0.918 + 17 5 × 0.722 ) = 0.109
Gain ( D , 根蒂 ) = 0.143 ; Gain ( D , 敲声 ) = 0.141 Gain ( D , 纹理 ) = 0.381 ; Gain ( D , 脐部 ) = 0.289 Gain ( D , 触感 ) = 0.006. \begin{array}{l}
\operatorname{Gain}(D, \text { 根蒂 })=0.143 ; \quad \operatorname{Gain}(D, \text { 敲声 })=0.141 \\
\operatorname{Gain}(D, \text { 纹理 })=0.381 ; \quad \operatorname{Gain}(D, \text { 脐部 })=0.289 \\
\operatorname{Gain}(D, \text { 触感 })=0.006 .
\end{array} Gain ( D , 根蒂 ) = 0.143 ; Gain ( D , 敲声 ) = 0.141 Gain ( D , 纹理 ) = 0.381 ; Gain ( D , 脐部 ) = 0.289 Gain ( D , 触感 ) = 0.006.
显然, 属性“纹理”的信息增益最大, 于是它被选为划分属性。下图给出了基于 “纹理”对根结点进行划分的结果, 各分支结点所包含的样例子集显示在结点中:
接下来,决策树算法将对每个分支结点做进一步划分,注意,此时起“纹理”将不再作为候选划分属性。
以上图第一 个分支结点(纹理=清晰)为例, 该结点包含的样例集合 D 1 D^{1} D 1 中有编号为 { 1 \{1 { 1 , 2 , 3 , 4 , 5 , 6 , 8 , 10 , 15 } 2,3,4,5,6,8,10,15\} 2 , 3 , 4 , 5 , 6 , 8 , 10 , 15 } 的 9 个样例,可用属性集合为 { \{ { 色泽, 根蒂, 敲声, 脐部, 触感 } \} } 。基于 D 1 D^{1} D 1 计算出各属性的信息增益:
Gain ( D 1 , 色泽 ) = 0.043 ; Gain ( D 1 , 根蒂 ) = 0.458 Gain ( D 1 , 敲声 ) = 0.331 ; Gain ( D 1 , 脐部 ) = 0.458 Gain ( D 1 , 触感 ) = 0.458. \begin{array}{l}
\operatorname{Gain}\left(D^{1}, \text { 色泽 }\right)=0.043 ; \quad \operatorname{Gain}\left(D^{1}, \text { 根蒂 }\right)=0.458 \\
\operatorname{Gain}\left(D^{1}, \text { 敲声 }\right)=0.331 ; \quad \operatorname{Gain}\left(D^{1}, \text { 脐部 }\right)=0.458 \\
\operatorname{Gain}\left(D^{1}, \text { 触感 }\right)=0.458 .
\end{array} Gain ( D 1 , 色泽 ) = 0.043 ; Gain ( D 1 , 根蒂 ) = 0.458 Gain ( D 1 , 敲声 ) = 0.331 ; Gain ( D 1 , 脐部 ) = 0.458 Gain ( D 1 , 触感 ) = 0.458.
“根蒂”、“脐部”、“触感” 3 个属性均取得了最大的信息增益,可任选其中之一作为划分属性。类似的,对每个分支结点进行上述操作,最终得到的决策树如下:
树的终止
前面讲完了ID3 \text {ID3} ID3 决策树的生成方法,那么,在树的结点不断分裂的过程中,什么时候该终止分裂?通常当一个结点满足下面三种情况时需要终止分裂:
当该结点所包含样本全属于同一类别时,终止该结点分裂(即使到该结点处还有属性未划分),将其标记为叶子结点,并将其类别设定为其下样本的类别。
当该结点处已经没有未划分的属性,或是该结点所包含的所有样本在剩余未划分属性上取值相同时,终止该结点分裂,将其标记为叶子结点,并将其类别设定为该结点所包含样本最多的类别。
当该结点所包含的样本集合为空时,终止该结点分裂,标记为叶子结点,将其类别设定为其父结点所包含样本最多的类别。
ID3 \text {ID3} ID3 算法缺点
没有剪枝策略,容易过拟合;
信息增益准则对可取值数目较多的特征有所偏好,类似“编号”的特征其信息增益接近于 1;
无法处理连续型变量的特征;
没有考虑缺失值
C4.5 \text {C4.5} C4.5 决策树
C4.5 \text {C4.5} C4.5 是ID3 \text {ID3} ID3 提出者本人针对ID3 \text {ID3} ID3 算法的缺点进行改进后的版本,主要体现在以下几个方面:
引入信息增益率作为属性划分标准
引入剪枝策略进行剪枝
对于连续特征进行离散化处理
处理缺失值
信息增益率
在前面 ID3 \text {ID3} ID3 决策树的生成过程中,我们有意忽略了表4.1中的“编号”这一列,而如果把“编号”也作为一个候选划分属性, 则根据公式可计算出它的信息增益为 0.998 0.998 0.998 ,远大于其他候选划分属性,这是因为“编号”作为划分属性时会产生 17 个分支,每个分支结点仅包含一个样本,一个样本当然只对应一个类别,那么“确定性”或者说“纯度”就会非常大。然而, 这样的决策树显然不具有泛化能力,无法对新样本进行有效预测。实际上,信息增益准则对可取值数目较多的属性有所偏好,为减少这种偏好可能带来的不利影响, C 4.5 C4.5 C 4.5 不直接使用信息增益,而是使用 “增益率” (gain ratio) 来选择最优划分属性:
Gain ratio ( D , a ) = Gain ( D , a ) IV ( a ) \operatorname{Gain}_{\operatorname{ratio}}(D, a)=\frac{\operatorname{Gain}(D, a)}{\operatorname{IV}(a)} Gain ratio ( D , a ) = IV ( a ) Gain ( D , a )
其中
IV ( a ) = − ∑ v = 1 V ∣ D v ∣ ∣ D ∣ log 2 ∣ D v ∣ ∣ D ∣ \operatorname{IV}(a)=-\sum_{v=1}^{V} \frac{\left|D^{v}\right|}{|D|} \log _{2} \frac{\left|D^{v}\right|}{|D|} IV ( a ) = − v = 1 ∑ V ∣ D ∣ ∣ D v ∣ log 2 ∣ D ∣ ∣ D v ∣
根据该公式,属性 a a a 的可能取值数目越多(即 V V V 越大),则 IV ( a ) \operatorname{IV}(a) IV ( a ) 的值通常会越大。例如,对于前面表 4.1 4.1 4.1 的西瓜数据集 2.0 2.0 2.0 ,有 I V ( \mathrm{IV}( IV ( 触感 ) = 0.874 ( V = 2 ) , I V ( )=0.874(V=2), \mathrm{IV}( ) = 0.874 ( V = 2 ) , IV ( 色泽 ) = 1.580 ( V = 3 ) )=1.580(V=3) ) = 1.580 ( V = 3 ) ,I V ( \mathrm{IV}( IV ( 编号 ) = 4.088 ( V = 17 ) )=4.088(V=17) ) = 4.088 ( V = 17 ) 。
需注意的是,增益率准则对可取值数目较少的属性有所偏好,因此,C4.5 \text {C4.5} C4.5 算法并不是直接选择增益率最大的候选划分属性,而是使用了一个启发式方法:先从候选划分属性中找出信息增益高于平均水平的属性,再从中选择增益率最高的属性。
剪枝处理
剪枝是C4.5 \text {C4.5} C4.5 算法对付 “过拟合”的手段。在中ID3 \text {ID3} ID3 中,为了尽可能正确分类训练样本,结点划分将过于庞杂,有时会造成决策树分支过多,这时就可能因训练样本学得 “太好”了,以致于把训练集自身的一些特点当作所有数据都具有的一般性质而导致过拟合。因此,可通过主动去掉一些分支来降低过拟合的风险。
如果要实现剪枝,那么在决策树生成之前,要先对数据集进行划分,一部分分为”训练集“,用来训练决策树,另一部分分为“验证集”,用来对决策树的泛化能力进行评估。还是以前面的西瓜数据集为例,划分后的数据集如下:
其生成的未剪枝决策树如下:
下面引入剪枝处理,剪枝通常分为“预剪枝”和“后剪枝”两种:
预剪枝
预剪枝就是决策树的生成过程中,在每个结点分裂之前对该结点分裂前后的泛化性能进行评估,如果分裂之后决策树在验证集上的预测准确率低于分裂前,也就是说当前结点的分裂不能提升决策树的泛化能力,那么就停止该结点的分裂并将其标记为叶结点,其类别标记为训练样本数最多的类别。
下图是引入预剪枝的决策树:
优点:预剪枝不仅可以降低过拟合的风险而且还可以大大减少训练时间
缺点:预剪枝是基于“贪心”策略,会带来欠拟合风险。
后剪枝
优点:和预剪枝相比,后剪枝在有效防止过拟合的同时还能保留决策树的泛化能力,不容易出现欠拟合。
缺点:大大增加了模型训练时间。
连续值处理
C4.5 \text {C4.5} C4.5 引入了连续值处理,方法是将连续特征离散化,假设连续特征 A 有m m m 个取值,C4.5 \text {C4.5} C4.5 将其排序并取每相邻两值的平均值共 m − 1 m-1 m − 1 个划分点,分别计算这m − 1 m-1 m − 1 个划分点作为二分点时的信息增益,并选择信息增益最大的点作为该连续特征的二元离散分类点。
以下面数据集为例:
对属性“密度”,在决策树学习开始时,根结点包含的 17 个训练样本在该属性上取值为17个不同的连续数值。根据上述方法,该属性的候选二分点为16个候选值: T 密度 = { 0.244 , 0.294 , 0.351 , 0.381 , 0.420 , 0.459 , 0.518 T_{\text {密度 }}=\{0.244,0.294,0.351,0.381,0.420,0.459,0.518 T 密度 = { 0.244 , 0.294 , 0.351 , 0.381 , 0.420 , 0.459 , 0.518 , 0.574 , 0.600 , 0.621 , 0.636 , 0.648 , 0.661 , 0.681 , 0.708 , 0.746 } 0.574,0.600,0.621,0.636,0.648,0.661,0.681,0.708,0.746\} 0.574 , 0.600 , 0.621 , 0.636 , 0.648 , 0.661 , 0.681 , 0.708 , 0.746 } 。对这些候选二分点分别计算信息增益,可得属性 “密度” 的最大信息增益为 0.262 0.262 0.262 ,对应于二分点 0.381 0.381 0.381 。同理对“含糖率”也进行离散化处理,最终,得到的决策树如下:
缺失值处理
C4.5 \text {C4.5} C4.5 引入了缺失值处理。现实数据中通常会遇到不完整样本数据,如果简单放弃不完整样本,仅仅使用无缺失值的样本进行学习,显然是对数据信息的极大浪费而。而要处理存在缺失值的数据集,就得解决以下两个问题:
如何在属性值存在缺失的情况下进行划分属性选择?
对于特定的属性结点,若某样本在该属性上的值缺失,如何对样本进行划分?
针对问题一,C4.5 \text {C4.5} C4.5 的做法是:对于存在缺失值特征,使用没有缺失的样本子集来计算信息增益,并对结果乘以该特征的无缺失样本所占比例;针对问题二,C4.5 \text {C4.5} C4.5 的做法是:将该样本以不同的权重值划分到所有子节点中,也就是以不同概率划分到每个子节点中,而它的概率则等于无缺失值样本在每个分支中所占的比例。
C4.5 \text {C4.5} C4.5 算法缺点
虽然C4.5 \text {C4.5} C4.5 算法相较于ID3 \text {ID3} ID3 已经有了很大改进提升,但它任然有以下不足之处:
剪枝策略可以再优化
它使用的是多叉树,但是二叉树效率更高
它只能用于分类,不能用于回归
它使用的熵模型拥有大量耗时的对数运算
CART \text {CART} CART 决策树
CART \text {CART} CART 全名是“C l a s s i f i c a t i o n a n d r e g r e s s i o n t r e e Classification \ and \ regression \ tree Cl a ss i f i c a t i o n an d re g ress i o n t ree ”(分类回归树),是一种性能强大的算法,著名的 GBDT \text {GBDT} GBDT 算法就是以它为基础的集成学习算法。
CART \text {CART} CART 相较于有C4.5 \text {C4.5} C4.5 着大幅改进,主要体现在以下几点:
它的结构是二叉树,运算速度比多叉树快
它既可以做分类,也可以做回归
它在做分类时,使用 Gini 系数作为属性划分标准,运算量比对数运算要小很多,速度更快
它基于代价复杂度方法进行剪枝,效果更好
基尼系数
信息熵包含对数,运算耗时很大,CART \text {CART} CART 在做分类时,引入了基尼系数来代替信息熵,基尼系数相当于熵模型的一节泰勒展开,是一种更高效的属性划分标准。它的计算如下:
Gini ( D ) = ∑ k = 1 K ∣ C k ∣ ∣ D ∣ ( 1 − ∣ C k ∣ ∣ D ∣ ) = 1 − ∑ k = 1 K ( ∣ C k ∣ ∣ D ∣ ) 2 \begin{aligned}
\operatorname{Gini}(D) &=\sum_{k=1}^{K} \frac{\left|C_{k}\right|}{|D|}\left(1-\frac{\left|C_{k}\right|}{|D|}\right) \\
&=1-\sum_{k=1}^{K}\left(\frac{\left|C_{k}\right|}{|D|}\right)^{2}
\end{aligned} Gini ( D ) = k = 1 ∑ K ∣ D ∣ ∣ C k ∣ ( 1 − ∣ D ∣ ∣ C k ∣ ) = 1 − k = 1 ∑ K ( ∣ D ∣ ∣ C k ∣ ) 2
Gini ( D ∣ A ) = ∑ i = 1 n ∣ D i ∣ ∣ D ∣ Gini ( D i ) \operatorname{Gini}(D \mid A)=\sum_{i=1}^{n} \frac{\left|D_{i}\right|}{|D|} \operatorname{Gini}\left(D_{i}\right) Gini ( D ∣ A ) = i = 1 ∑ n ∣ D ∣ ∣ D i ∣ Gini ( D i )
基尼指数反映了从数据集中随机抽取两个样本,其类别标记不一致的概率。因此基尼指数越小,则数据集确定性越高,纯度越高。由于CART \text {CART} CART 是二叉树,对于二分问题,假设集合D D D 在属性A A A 的条件下分为D 1 D_1 D 1 和D 2 D_2 D 2 两部分,那么属性A A A 的基尼系数计算为:
Gini ( D , A ) = ∣ D 1 ∣ ∣ D ∣ Gini ( D 1 ) + ∣ D 2 ∣ ∣ D ∣ Gini ( D 2 ) \operatorname{Gini}(D, A)=\frac{\left|D_{1}\right|}{|D|} \operatorname{Gini}\left(D_{1}\right)+\frac{\left|D_{2}\right|}{|D|} \operatorname{Gini}\left(D_{2}\right) Gini ( D , A ) = ∣ D ∣ ∣ D 1 ∣ Gini ( D 1 ) + ∣ D ∣ ∣ D 2 ∣ Gini ( D 2 )
二叉递归分裂
CART \text {CART} CART 算法采用二叉递归分裂,在树生成过程中,总是将当前样本集分割为两个子样本集,使得生成的决策树的每个非叶结点都只有两个分枝,整个决策树是结构简洁的二叉树,因此CART算法适用于样本特征的取值为“是”或“非”的场景。
而对于多个离散值的特征,CART \text {CART} CART 会进行二分切割,并选择基尼系数最小的切割方式。如某特征值具有[ ′ y o u n g ’ , ’ m i d d l e ’ , ’ o l d ’ ] ['young’,’middle’,’old’] [ ′ yo u n g ’ , ’ mi dd l e ’ , ’ o l d ’ ] 三个取值,那么二分切割会有如下3种可能性:[ ( ′ y o u n g ′ ) , ( ′ m i d d l e ′ , ′ o l d ′ ) ] 、 [ ( m i d d l e ′ ) , ( ′ y o u n g ′ , ′ o l d ′ ) ] 、 [ ( ′ o l d ′ ) , ( ′ y o u n g ′ , ′ m i d d l e ′ ) ] [('young'), ('middle', 'old')]、[(middle'), ('young', 'old')]、[('old'), ('young', 'middle')] [ ( ′ yo u n g ′ ) , ( ′ mi dd l e ′ , ′ o l d ′ )] 、 [( mi dd l e ′ ) , ( ′ yo u n g ′ , ′ o l d ′ )] 、 [ ( ′ o l d ′ ) , ( ′ yo u n g ′ , ′ mi dd l e ′ )] ,然后分别计算上述List做分叉时的基尼系数,选取最优的分割方式。
同时,CART \text {CART} CART 没有规定树的终止准则,也就是说树会一直生长到最大。因此剪枝尤为重要,后面会讲它的剪枝策略。
CART \text {CART} CART 回归树
回归和分类的本质区别在于输出结果是连续型还是离散型。CART \text {CART} CART 不仅能做分类树,也可以做回归树,做回归树时其适用场景是:结果标签值虽然是连续分布的,但是可以划分群落,即:群落内相似,群落间不同。
CART \text {CART} CART 回归树的损失函数:误差平方和
在之前学习的决策树中,我们使用信息熵或基尼系数作为损失函数,但在回归树中,由于结果标签是连续型数值,信息熵和基尼系数不再适用。CART \text {CART} CART 回归树的损失函数通常使用的是“误差平方和”:
min j , s [ min c 1 ∑ x i ∈ R 1 ( j , s ) ( y i − c 1 ) 2 + min c 2 ∑ x i ∈ R 2 ( j , s ) ( y i − c 2 ) 2 ] \min _{j, s}\left[\min _{c_{1}} \sum_{x_{i} \in R_{1}(j, s)}\left(y_{i}-c_{1}\right)^{2}+\min _{c_{2}} \sum_{x_{i} \in R_{2}(j, s)}\left(y_{i}-c_{2}\right)^{2}\right] j , s min ⎣ ⎡ c 1 min x i ∈ R 1 ( j , s ) ∑ ( y i − c 1 ) 2 + c 2 min x i ∈ R 2 ( j , s ) ∑ ( y i − c 2 ) 2 ⎦ ⎤
上式中,y i y_i y i 为训练样本中x i x_i x i 对应的实际y i y_i y i 值, c 1 c_{1} c 1 为 D 1 D_{1} D 1 数据集样本对应的y y y 的平均值,c 2 c_{2} c 2 为 D 2 D_{2} D 2 数据集样本对应的y y y 的平均值。
CART \text {CART} CART 回归树的生成
对给定训练集 D
依次遍历每个变量的取值, 寻找最优切分变量 j 与切分点 s, 进而求解:
min j , s [ min c 1 ∑ x i ∈ R 1 ( j , s ) ( y i − c 1 ) 2 + min c 2 ∑ x i ∈ R 2 ( j , s ) ( y i − c 2 ) 2 ] \min _{j, s}\left[\min _{c_{1}} \sum_{x_{i} \in R_{1}(j, s)}\left(y_{i}-c_{1}\right)^{2}+\min _{c_{2}} \sum_{x_{i} \in R_{2}(j, s)}\left(y_{i}-c_{2}\right)^{2}\right] j , s min ⎣ ⎡ c 1 min x i ∈ R 1 ( j , s ) ∑ ( y i − c 1 ) 2 + c 2 min x i ∈ R 2 ( j , s ) ∑ ( y i − c 2 ) 2 ⎦ ⎤
接着用选定的对 (j, s) 划分区域并决定相应的输出值:
R 1 ( j , s ) = { x ∣ x ( j ) ≤ s } , R 2 ( j , s ) = { x ∣ x ( j ) > s } c ^ m = 1 N m ∑ x i ∈ R m ( j , s ) y i , x ∈ R m , m = 1 , 2 \begin{array}{c} R_{1}(j, s)=\left\{x \mid x^{(j)} \leq s\right\}, R_{2}(j, s)=\left\{x \mid x^{(j)}>s\right\} \\ \hat{c}_{m}=\frac{1}{N_{m}} \sum_{x_{i} \in R_{m}(j, s)} y_{i}, x \in R_{m}, m=1,2 \end{array} R 1 ( j , s ) = { x ∣ x ( j ) ≤ s } , R 2 ( j , s ) = { x ∣ x ( j ) > s } c ^ m = N m 1 ∑ x i ∈ R m ( j , s ) y i , x ∈ R m , m = 1 , 2
R 1 ( j , s ) R_{1}(j, s) R 1 ( j , s ) , R 2 ( j , s ) R_{2}(j, s) R 2 ( j , s ) 分别代表的是左子节点和右子节点, 而对两个节点上的估计值 c ^ m \hat{c}_{m} c ^ m 采用相应子 节点上目标值的均值来表示(注意这里划分区间时是一直按照平方误差损失最小划分的, 但 c ^ m \hat{c}_{m} c ^ m 采用均值是因为此时的损失函数为平方误差, 当损失函数变化时便不是均值了)。
继续对两个子区域调用步骤1、步骤2,直到满足停止条件(比如子节点上样本个数过少或者决策树已经达到指定的深度)。
将输入空间划分为 M 个区域 R 1 , R 2 , ⋯ , R M R_{1}, R_{2}, \cdots, R_{M} R 1 , R 2 , ⋯ , R M , 生成决策树:
f ( x ) = ∑ m = 1 M c ^ m I ( x ∈ R m ) f(x)=\sum_{m=1}^{M} \hat{c}_{m} I\left(x \in R_{m}\right) f ( x ) = m = 1 ∑ M c ^ m I ( x ∈ R m )
f(x) 便是我们学习到的CART决策树, I\left(x \in R_{m}\right) 表示相应样本属于的区域,在相应区域其值 为1, 否则为 0 。
最终,训练得到的回归树的叶结点包含多个y值,那么该如何输出预测值?方法依旧是找到使该叶结点的损失函数最小的值,作为预测值输出。而对于这里的“误差平方和”作为损失函数而言,由于其求导后可以直接作为误差,因此平均值就是使损失函数最小的值,只需要取平均值输出即可。
基于代价复杂度剪枝
由于CART \text {CART} CART 没有规定树的终止准则,树会一直生长到最大,因此剪枝尤为重要。CART \text {CART} CART 采用“基于代价复杂度”的剪枝策略,这种方法最后会生成一系列大小不同的树,每个树都是将最大树的某些子树替换为叶结点而得到的,其中最小的一棵树只含有一个叶结点,最终在验证集上使用交叉验证来评估所有树的性能,并选择分类性能最佳的树。
具体算法步骤:
首先我们将最大树称为T 0 T_0 T 0 ,我们希望减少树的大小来防止“过拟合”,但又担心去掉太多子树后会“欠拟合”,于是我们定义了一个损失函数来使二者达到平衡:
C α ( T ) = C ( T ) + α ∣ T ∣ C_{\alpha}(T)=C(T)+\alpha|T| C α ( T ) = C ( T ) + α ∣ T ∣
T T T :任意子树;
C ( T ) C(T) C ( T ) :该子树在训练集上的预测误差(分类用基尼系数,回归用误差平方和),用来衡量子树对训练数据的拟合程度;
∣ T ∣ |T| ∣ T ∣ :该子树的叶结点个数,用来衡量子树的复杂度;
α \alpha α :正则化惩罚参数,用来平衡拟合程度和树复杂度之间的关系
我们的最终目的就是让损失函数C α ( T ) C_{\alpha}(T) C α ( T ) 最小,从公式可以看出,随着正则化参数α \alpha α 的增大,树模型的复杂度∣ T ∣ |T| ∣ T ∣ 就会被迫减小、剪枝量增加,于是拟合度下降、预测误差C ( T ) C(T) C ( T ) 逐渐增大,所以损失函数C α ( T ) C_{\alpha}(T) C α ( T ) 的大小直观上无法确定。因此我们引入“误差增加率”。
误差增加率 :
g ( t ) = C ( t ) − C ( T t ) ∣ T t ∣ − 1 g(t)=\frac{C(t)-C\left(T_{t}\right)}{\left|T_{t}\right|-1} g ( t ) = ∣ T t ∣ − 1 C ( t ) − C ( T t )
t t t :任意内部单结点
T t T_t T t :结点t t t 包含的子树
C ( t ) C(t) C ( t ) :以t t t 为叶结点(剪掉t t t 子树)的预测误差
C ( T t ) C(T_t) C ( T t ) :子树T t T_t T t 的预测误差
∣ T t ∣ |T_t| ∣ T t ∣ :子树T t T_t T t 的叶结点个数
对公式的理解:
误差增加率用来衡量“剪枝行为”的“收益”或者“性价比”。
对于分子,表示剪枝前后的误差增量,当然我们希望它越小越好;对于分母,表示剪掉的子树大小,我们希望它越大越好(树模型复杂度更小)。因此我们希望上式总体越小越好,这样剪枝的“受益”最大,“性价比”最高
接下来,对最大树T 0 T_0 T 0 ,分别计算每个内部结点的“误差增加率”,选择“误差增益率”最小的结点,剪掉其分支,剪枝后的树标记为T 1 T_1 T 1 ;接下来对T 1 T_1 T 1 每个结点的“误差增加率”,选取最下,剪枝,标记为T 2 T_2 T 2 ;重复这一步骤直到最后一棵树T n T_n T n 只有一个叶结点,这样得到的一系列树:T 0 , T 1 , T 2 , T 3 , … , T n T_{0}, T_{1}, T_{2}, T_{3}, \ldots, T_{n} T 0 , T 1 , T 2 , T 3 , … , T n ,分别是各不同数量结点下的最优子树,同时也分别是正则化参数α \alpha α 从0 0 0 增大到∞ \infty ∞ 时在每个区间 [ α i , α i + 1 ) \left[\alpha_{i}, \alpha_{i+1}\right) [ α i , α i + 1 ) 上的最优子树。最终,在验证集上对每个子树进行评估(交叉验证打分),选择其中的最优子树。
有问题欢迎留言交流。
最后,如果你对Python、数据挖掘、机器学习等内容感兴趣,欢迎关注我的博客。