决策树是一个非常优秀的机器学习算法,易于理解、可解释性强,既可作为分类算法,也可用于回归问题。本章主要介绍基本树模型:ID3、C4.5、CART树。
ID3树算法的思想是建立在奥卡姆剃刀的基础上:越是小型决策树越优于大的决策树。
在信息论上可知:信息熵越大,从而邦本纯度越低。ID3树的核心思想就是以信息增益来作为启发函数度量特征选择,选择信息增益最大的特征进行分裂。算法采用自顶向下的贪婪搜索遍历可能的决策空间。
主要步骤如下:
ID3使用的分类标准是信息增益,他表示得知特征A的信息而使得样本集合不确定性减少的程度。
数据集的信息熵:
H ( D ) = − ∑ k = 1 K ∣ C k ∣ ∣ D ∣ log 2 ∣ C k ∣ ∣ D ∣ H(D)=-\sum_{k=1}^{K} \frac{\left|C_{k}\right|}{|D|} \log _{2} \frac{\left|C_{k}\right|}{|D|} H(D)=−k=1∑K∣D∣∣Ck∣log2∣D∣∣Ck∣
其中 C k C_k Ck表示集合D中属于第k类样本的样本子集。
针对某个特征A,对于数据集D的条件熵 H ( D ∣ A ) H(D|A) H(D∣A)为:
H ( D ∣ A ) = ∑ i = 1 n ∣ D i ∣ ∣ D ∣ H ( D i ) = − ∑ i = 1 n ∣ D i ∣ ∣ D ∣ ( ∑ k = 1 K ∣ D i k ∣ ∣ D i ∣ log 2 ∣ D i k ∣ ∣ D i ∣ ) \begin{aligned} H(D \mid A) &=\sum_{i=1}^{n} \frac{\left|D_{i}\right|}{|D|} H\left(D_{i}\right) \\ &=-\sum_{i=1}^{n} \frac{\left|D_{i}\right|}{|D|}\left(\sum_{k=1}^{K} \frac{\left|D_{i k}\right|}{\left|D_{i}\right|} \log _{2} \frac{\left|D_{i k}\right|}{\left|D_{i}\right|}\right) \end{aligned} H(D∣A)=i=1∑n∣D∣∣Di∣H(Di)=−i=1∑n∣D∣∣Di∣(k=1∑K∣Di∣∣Dik∣log2∣Di∣∣Dik∣)
其中 D i D_i Di表示D中特征A取第i个值的样本子集, D i k D_{ik} Dik表示 D i D_i Di中属于第k类的样本子集。
信息增益 = 信息熵 - 条件熵:
Gain ( D , A ) = H ( D ) − H ( D ∣ A ) \operatorname{Gain}(D, A)=H(D)-H(D \mid A) Gain(D,A)=H(D)−H(D∣A)
信息增益越大表示特征A来划分所得的“纯度提升越大”。
C4.5算法最大的特点是客服了ID3对特征数目的片中的这一缺点,引入信息增益率来作为分类标准。
C4.5 相对于ID3的缺点对应有一下改进方式:
利用信息增益率可以客服信息增益的缺点,计算公式如下:
Gain ratio ( D , A ) = Gain ( D , A ) H A ( D ) H A ( D ) = − ∑ i = 1 n ∣ D i ∣ ∣ D ∣ log 2 ∣ D i ∣ ∣ D ∣ \begin{aligned} \text { Gain }_{\text {ratio }}(D, A) &=\frac{\operatorname{Gain}(D, A)}{H_{A}(D)} \\ H_{A}(D) &=-\sum_{i=1}^{n} \frac{\left|D_{i}\right|}{|D|} \log _{2} \frac{\left|D_{i}\right|}{|D|} \end{aligned} Gain ratio (D,A)HA(D)=HA(D)Gain(D,A)=−i=1∑n∣D∣∣Di∣log2∣D∣∣Di∣
H A ( D ) H_A(D) HA(D)称为特征A的固与值。
这里需要注意,信息增益率对可取值较少的特征有所偏好(分母越小,整体越大),因此 C4.5 并不是直接用增益率最大的特征进行划分,而是使用一个启发式方法:先从候选划分特征中找到信息增益高于平均值的特征,再从中选择增益率最高的。
为什么要剪枝:过拟合的树在泛化能力上表现非常差。
在节点划分前来确定是否继续增长,及早停止增长的主要方法有:
预剪枝不仅可以降低过拟合的风险而且还可以减少训练时间,但另一方面它是基于“贪心”策略,会带来欠拟合风险。
在已经生成的决策树上进行剪枝,从而得到简化版的剪枝决策树。
C4.5 采用的悲观剪枝方法,用递归的方式从低往上针对每一个非叶子节点,评估用一个最佳叶子节点去代替这课子树是否有益。如果剪枝后与剪枝前相比其错误率是保持或者下降,则这棵子树就可以被替换掉。C4.5 通过训练数据集上的错误分类数量来估算未知样本上的错误率。
后剪枝决策树的欠拟合风险很小,泛化性能往往优于预剪枝决策树。但同时其训练时间会大的多。
ID3和C4.5虽然在对训练样本集的学习中可以尽可能多的挖掘信息,但是其生成的决策树分支规模较大,CART算法的二分法可以简化决策树的规模,提高生成决策树的效率。
CART包含的基本过程有分裂,剪枝和选择。
CART 在 C4.5 的基础上进行了很多提升。
熵模型拥有大量耗时的对数运算,基尼指数在简化模型的同时还保留了熵模型的优点。基尼指数代表了模型的不纯度,基尼系数越小,不纯度越低,特征越好。这和信息增益(率)正好相反。
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∣∣Ck∣(1−∣D∣∣Ck∣)=1−k=1∑K(∣D∣∣Ck∣)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∣∣Di∣Gini(Di)
其中 k 代表类别。
基尼指数反映了从数据集中随机抽取两个样本,其类别标记不一致的概率。因此基尼指数越小,则数据集纯度越高。基尼指数偏向于特征值较多的特征,类似信息增益。基尼指数可以用来度量任何不均匀分布,是介于 0~1 之间的数,0 是完全相等,1 是完全不相等,此外,当 CART 为二分类,其表达式为: Gini ( D ∣ A ) = ∣ D 1 ∣ ∣ D ∣ Gini ( D 1 ) + ∣ D 2 ∣ ∣ D ∣ Gini ( D 2 ) \operatorname{Gini}(D \mid 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∣∣D1∣Gini(D1)+∣D∣∣D2∣Gini(D2)
我们可以看到在平方运算和二分类的情况下,其运算更加简单。当然其性能也与熵模型非常接近。
那么问题来了:基尼指数与熵模型性能接近,但到底与熵模型的差距有多大呢?
我们知道 ln ( x ) = − 1 + x + o ( x ) \ln (x)=-1+x+o(x) ln(x)=−1+x+o(x),所以
H ( X ) = − ∑ k = 1 K p k ln p k ≈ ∑ k = 1 K p k ( 1 − p k ) \begin{aligned} H(X) &=-\sum_{k=1}^{K} p_{k} \ln p_{k} \\ & \approx \sum_{k=1}^{K} p_{k}\left(1-p_{k}\right) \end{aligned} H(X)=−k=1∑Kpklnpk≈k=1∑Kpk(1−pk)我们可以看到,基尼指数可以理解为熵模型的一阶泰勒展开。这边在放上一张很经典的图:
上文说到,模型对于缺失值的处理会分为两个子问题:
对于问题 1,CART 一开始严格要求分裂特征评估时只能使用在该特征上没有缺失值的那部分数据,在后续版本中,CART 算法使用了一种惩罚机制来抑制提升值,从而反映出缺失值的影响(例如,如果一个特征在节点的 20% 的记录是缺失的,那么这个特征就会减少 20% 或者其他数值)。
对于问题 2,CART 算法的机制是为树的每个节点都找到代理分裂器,无论在训练数据上得到的树是否有缺失值都会这样做。在代理分裂器中,特征的分值必须超过默认规则的性能才有资格作为代理(即代理就是代替缺失值特征作为划分特征的特征),当 CART 树中遇到缺失值时,这个实例划分到左边还是右边是决定于其排名最高的代理,如果这个代理的值也缺失了,那么就使用排名第二的代理,以此类推,如果所有代理值都缺失,那么默认规则就是把样本划分到较大的那个子节点。代理分裂器可以确保无缺失训练数据上得到的树可以用来处理包含确实值的新数据。
采用一种“基于代价复杂度的剪枝”方法进行后剪枝,这种方法会生成一系列树,每个树都是通过将前面的树的某个或某些子树替换成一个叶节点而得到的,这一系列树中的最后一棵树仅含一个用来预测类别的叶节点。然后用一种成本复杂度的度量准则来判断哪棵子树应该被一个预测类别值的叶节点所代替。这种方法需要使用一个单独的测试数据集来评估所有的树,根据它们在测试数据集熵的分类性能选出最佳的树。
我们来看具体看一下代价复杂度剪枝算法:
首先我们将最大树称为 T 0 T_0 T0,我们希望减少树的大小来防止过拟合,但又担心去掉节点后预测误差会增大,所以我们定义了一个损失函数来达到这两个变量之间的平衡。损失函数定义如下:
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∣为子树 T T T的叶子节点个数, α \alpha α是参数, C ( T ) C(T) C(T)衡量训练数据的拟合程度, ∣ T ∣ |T| ∣T∣衡量树的复杂度, α \alpha α权衡拟合程度与树的复杂度。
那么如何找到合适的 α \alpha α来使得复杂度和拟合度达到最好的平衡点呢,最好的办法就是另 α \alpha α从 0 取到正无穷,对于每一个固定的 α \alpha α ,我们都可以找到使得 C α ( T ) C_\alpha(T) Cα(T) 最小的最优子树 T ( α ) T(\alpha) T(α) 。当 α \alpha α很小的时候, T 0 T_0 T0 是最优子树;当 α \alpha α最大时,单独的根节点是这样的最优子树。随着 α \alpha α增大,我们可以得到一个这样的子树序列: T 0 , T 1 , T 2 , T 3 , … , T n T_{0}, T_{1}, T_{2}, T_{3}, \ldots, T_{n} T0,T1,T2,T3,…,Tn,这里的子树 T i + 1 T_{i+1} Ti+1生成是根据前一个子树 T i T_{i} Ti剪掉某一个内部节点生成的。
Breiman 证明:将 α \alpha α从小增大, 0 = α 0 < α 0 < … < α n < ∞ 0=\alpha_{0}<\alpha_{0}<\ldots<\alpha_{n}<\infty 0=α0<α0<…<αn<∞,在每个区间 [ α i , α i + 1 ) \left[\alpha_{i}, \alpha_{i+1}\right) [αi,αi+1)中,子树 T i T_{i} Ti是这个区间里最优的。
这是代价复杂度剪枝的核心思想。
我们每次剪枝都是针对某个非叶节点,其他节点不变,所以我们只需要计算该节点剪枝前和剪枝后的损失函数即可。
对于任意内部节点 t,剪枝前的状态,有 ∣ T t ∣ \left|T_{t}\right| ∣Tt∣个叶子节点,预测误差是 C ( T t ) C\left(T_{t}\right) C(Tt);剪枝后的状态:只有本身一个叶子节点,预测误差是 C ( t ) C(t) C(t)。
因此剪枝前以 t 节点为根节点的子树的损失函数是:
C α ( T ) = C ( T t ) + α ∣ T ∣ C_{\alpha}(T)=C\left(T_{t}\right)+\alpha|T| Cα(T)=C(Tt)+α∣T∣剪枝后的损失函数是
C α ( t ) = C ( t ) + α C_{\alpha}(t)=C(t)+\alpha Cα(t)=C(t)+α通过 Breiman 证明我们知道一定存在一个 α \alpha α使得 C α ( T ) = C α ( t ) C_{\alpha}(T)=C_{\alpha}(t) Cα(T)=Cα(t),使得这个值为: α = C ( t ) − C ( T t ) ∣ T t ∣ − 1 \alpha=\frac{C(t)-C\left(T_{t}\right)}{\left|T_{t}\right|-1} α=∣Tt∣−1C(t)−C(Tt) α \alpha α 的意义在于, [ α i , α i + 1 ) \left[\alpha_{i}, \alpha_{i+1}\right) [αi,αi+1)中,子树 α \alpha α 是这个区间里最优的。当 C α ( T ) > C α ( t ) C_{\alpha}(T)>C_{\alpha}(t) Cα(T)>Cα(t)大于这个值是,一定有 [公式] ,也就是剪掉这个节点后都比不剪掉要更优。所以每个最优子树对应的是一个区间,在这个区间内都是最优的。
然后我们对 T i T_i Ti中的每个内部节点 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)=∣Tt∣−1C(t)−C(Tt) g ( t ) g(t) g(t)表示阈值,故我们每次都会减去最小的 T i T_i Ti 。
CART 的一大优势在于:无论训练数据集有多失衡,它都可以将其子冻消除不需要建模人员采取其他操作。
CART 使用了一种先验机制,其作用相当于对类别进行加权。这种先验机制嵌入于 CART 算法判断分裂优劣的运算里,在 CART 默认的分类模式中,总是要计算每个节点关于根节点的类别频率的比值,这就相当于对数据自动重加权,对类别进行均衡。
对于一个二分类问题,节点 node 被分成类别 1 当且仅当: N 1 ( node ) N 1 ( root ) > N 0 ( node ) N 0 ( root ) \frac{N_{1}(\text { node })}{N_{1}(\text { root })}>\frac{N_{0}(\text { node })}{N_{0}(\text { root })} N1( root )N1( node )>N0( root )N0( node )比如二分类,根节点属于 1 类和 0 类的分别有 20 和 80 个。在子节点上有 30 个样本,其中属于 1 类和 0 类的分别是 10 和 20 个。如果 10/20>20/80,该节点就属于 1 类。
通过这种计算方式就无需管理数据真实的类别分布。假设有 K 个目标类别,就可以确保根节点中每个类别的概率都是 1/K。这种默认的模式被称为“先验相等”。
先验设置和加权不同之处在于先验不影响每个节点中的各类别样本的数量或者份额。先验影响的是每个节点的类别赋值和树生长过程中分裂的选择。
CART(Classification and Regression Tree,分类回归树),从名字就可以看出其不仅可以用于分类,也可以应用于回归。其回归树的建立算法上与分类树部分相似,这里简单介绍下不同之处。
对于连续值的处理,CART 分类树采用基尼系数的大小来度量特征的各个划分点。在回归模型中,我们使用常见的和方差度量方式,对于任意划分特征 A,对应的任意划分点 s 两边划分成的数据集 D 1 D_1 D1 和 D 2 D_2 D2 ,求出使 D 1 D_1 D1 和 D 2 D_2 D2 各自集合的均方差最小,同时 [公式] 和 [公式] 的均方差之和最小所对应的特征和特征值划分点。表达式为: min a , s [ min c 1 ∑ x i ∈ D 1 ( y i − c 1 ) 2 + min c 2 ∑ x i ∈ D 2 ( y i − c 2 ) 2 ] \min _{a, s}\left[\min _{c_{1}} \sum_{x_{i} \in D_{1}}\left(y_{i}-c_{1}\right)^{2}+\min _{c_{2}} \sum_{x_{i} \in D_{2}}\left(y_{i}-c_{2}\right)^{2}\right] a,smin[c1minxi∈D1∑(yi−c1)2+c2minxi∈D2∑(yi−c2)2]
其中, c 1 c_1 c1 为 D 1 D_1 D1 数据集的样本输出均值, c 2 c_2 c2 为 D 2 D_2 D2 数据集的样本输出均值。
对于决策树建立后做预测的方式,上面讲到了 CART 分类树采用叶子节点里概率最大的类别作为当前节点的预测类别。而回归树输出不是类别,它采用的是用最终叶子的均值或者中位数来预测输出结果。
最后通过总结的方式对比下 ID3、C4.5 和 CART 三者之间的差异。
除了之前列出来的划分标准、剪枝策略、连续值确实值处理方式等之外,我再介绍一些其他差异:
更多请见:https://zhuanlan.zhihu.com/p/85731206