决策树(decision tree)是一种基本的分类与回归算法,从名字就可以看出,该模型呈现树状结构,起始决策树就是一系列if-then规则的集合,通过对一系列条件的判断,最终输出一个模型预测的结果。下面给出决策树的模型图:
通过图片我们来了解几个概念:
1. 决策树中的节点分为两种:1.内部节点(椭圆形的)2.叶节点(矩形的)
2. 决策树由有向边和节点组成
3. 每个内部节点表示一个特征,每个叶节点表示一个分类结果
假定我们给出了训练数据集:
一个特征向量 x 中有n个不同的特征,那么在决策树的内部节点中,我们到底选择哪一个特征对数据集进行切分呢?下面介绍的信息增益和信息增益比的概念就是选择特征的标准。
在介绍信息增益之前,我们先来介绍一下熵的概念。熵这个概念是从物理学中引用过来的,表示一个系统的混乱程度,熵越大,表示系统越混乱。熵的定义式如下:
2.1节中介绍了信息增益的概念,那么信息增益比的概念就比较好理解了
前面讲了很多概念,但是没讲在实际使用时,给定了数据集D的情况下,应该怎样计算信息增益。下面就来介绍一下如何计算分类问题中的熵:
信息增益算法
首先定义一些变量:数据集为 D ,|D|表示数据集中样本的数量,有 K 个类Ck, (k=1,2,⋯,K) , |Ck| 表示属于类 Ck 的样本数量, ∑Kk=1|Ck|=|D| 。特征A有n个不同的取值,根据每个样本中特征A的取值,将 D 划分为n个子集D1,D2,⋯,Dn, |Di| 是 Di 的样本数量, ∑ni=1|Di|=|D| 。记子集 Di 中属于类 Ck 的样本集合为 Dik ,即 Dik=Di∩Ck , |Dik| 为 Dik 的样本数量,于是信息增益的算法如下
输入:训练数据集D和特征A
输出:特征A对训练数据集D的信息增益 g(D,A)
(1) 计算数据集D的熵H(D)
H(D)=−∑k=1K|Di||D|log2|Ck||D|
(2) 根据特征A对数据集D的条件熵 H(D|A)
H(D|A)=∑i=1n|Di||D|H(Di)=−∑i=1n|Di||D|∑k=1K|Dik||Di|log2|Dik||Di|
(3) 计算信息增益
g(D,A)=H(D)−H(D|A)
同理,当计算信息增益比时,按照上述方法将g(D,A)和H(D)计算出来后,相除即可得到 gR(D,A) 。
前面我们介绍了如何计算信息增益,也就知道了如何选择决策树中每个节点进行分类的特征,下面来具体的介绍三种决策树生成算法。
算法核心思想:在决策树的各个节点上应用信息增益准则选择特征,递归的构建决策树。
具体方法:从根节点开始,对节点计算所有可能的特征的信息增益,选择信息增益最大的特征作为节点的特征,然后使用该特征对训练集进行分类,并建立子节点,再对子节点和子节点的训练数据集进行信息增益计算,递归的调用这种方法建立决策树。算法停止条件是,直到所有的特征信息增益很小,或者没有特征可以选择,就终止算法,得到决策树。
ID3算法相当于用极大似然概率进行模型的选择。这里谈一下我对这句话的理解:A的极大似然函数是 P(D|A) ,使似然函数极大相当于在给定了特征A时,分类完毕的数据集D属于某一类的可能性变得最大,那么其条件熵 H(D|A) 就取得了极小值(观察条件熵的计算式可以很明显的看出),那么信息增益 g(D,A) 也就取得了极大值。而ID3算法又是通过选择信息增益最大的哪个特征作为节点的分类特征,所以ID3算法建立决策树和用极大似然概率进行模型选择是等价的。
ID3算法
输入:训练数据集D,特征集A,阈值 ε
输出:决策树 T
(1) 若D中所有实例属于同一类Ck,则 T 为单节点树,并将Ck作为该节点的类标记,返回 T
(2) 若A=∅,则T为单节点树,并将D中样本数最大的类 Ck 作为该节点的类标记,返回T
(3) 否则,计算A中各特征对D的信息增益,选择信息增益最大的特征A
(4) 如果 Ag 的信息增益小于阈值 ε ,则置 T 为单节点树,并将D中样本数最大的类Ck作为该节点的类标记,返回 T
(5) 否则,对Ag的每一个可能值 ai ,依 Ag=ai 将D分割为若干非空子集 Di ,将 Di 中样本数最大的类作为标记,构建子节点,由节点及其子节点构成树 T ,返回T
(6) 对第i个子节点,以 Di 为训练集,以 A−Ag 为特征集,递归地调用(1)~(5),得到子树 Ti ,返回 Ti
这里说一下算法中需要注意的地方:
C4.5算法本质上和ID3没有特别大的差异,只是将选择特征的标准从信息增益变成了信息增益比,其余部分全部相同。
因此这里不再给出详细的算法步骤。
剪枝的定义:在决策树学习中将已经生成的决策树进行简化的过程称为剪枝(pruning)。剪枝从已生成的树上裁掉一些子树或叶节点,并将其根节点作为新的叶节点,从而简化分类树模型。
剪枝的核心思想:剪枝操作往往通过极小化决策树的损失函数(loss function)或代价函数(cost function)来实现。
这里我们给出一些变量和损失函数的定义:
设树 T 的叶节点个数为|T|, t 是树T的叶节点,该叶节点上有 Nt 个样本,其中属于第k类的样本有 Ntk 个, k=1,2,⋯,K , Ht(T) 为决策树 T 中第t个叶节点上数据集的熵(计算方法和前面计算信息增益时计算熵的方法是相同的), α≥0 是正则化参数,则决策树的损失函数定义如下:
Cα(T)=∑t=1|T|NtHt(t)+α|T|
其中熵为:
Ht(t)=−∑k|Ntk||Nt|log2|Dtk||Dt|
观察一下损失函数表达式,可以发现它是分为两部分的,第一部分是计算整棵树的熵的,第二部分是正则化项,用来约束决策树的复杂度的。 α 越大, Cα(T) 越大,而我们需要让损失函数尽可能的小,于是就让 |T| 尽可能的小,这就起到了简化决策树的作用。
树的剪枝算法
输入:生成算法产生的整个树 T ,参数α
输出:修剪后的子树 Tα
(1) 计算每个节点的熵
(2) 递归地从树的叶节点向上回缩。设一组叶节点回缩到其父节点之前与之后的整体树分别是 TB 和 TA ,其对应的损失函数值分别是 Cα(TB) 与 Cα(TA) ,如果
Cα(TB)≤Cα(TA)
则进行剪枝,即将父节点变为新的子节点。
(3) 返回(2),直至不能继续为止,得到损失函数最小的子树 Tα
将上述算法加速:介绍完上面的算法我们发现,其实剪枝前后熵的变化只和被剪枝的那个子树和正则项有关,而正则项又是一个线性的,因此我们完全可以只计算局部子树的熵,而不用把整棵树的熵全算出来,这样进一步加快了算法的速度。这样的想法可以使用类似于动态规划的算法实现!
在使用ID3和C4.5算法产生决策树之后,就可以用这个剪枝算法将决策树模型简化。
CART的全称是分类与回归树(Classificatioin and Regression Tree),CART同样由特征选择、树的生成及剪枝组成,既可以用于分类也可以用于回归。
CART与前面两种算法生成的决策树的最大不同在于:CART是二叉树,而前两种算法生成的决策树中,一个节点可能下面有很多分叉。CART等价与递归的二分每个特征,即将输入空间划分为有限个单元,每个单元有一个对应的输出值或分类结果。
在上面的介绍中,我们知道CART其实是把输入空间划分成了有限个单元,假设将输入空间划分为了M个单元 R1,R2,⋯,RM ,并且每个单元都由一个固定的输出值 cm ,于是回归树模型可以表示为:
最小二乘回归树生成算法
输入:训练数据集D
输出:回归树 f(x)
在训练数据集所在的输入空间中,递归地将每个区域划分为两个子区域并决定每个子区域的输出值,构建二叉决策树:
(1) 选择最优的切分变量j和切分点s,求解
minj,s[minc1∑xi∈R1(j,s)(yi−c1)2+minc1∑xi∈R2(j,s)(yi−c2)2]
遍历变量j,对固定的切分变量j扫描切分点s,选择使上式达到最小值的(j,s)对
(2) 用选定的(j,s)对划分区域并决定相应的输出值:
R1(j,s)={x|x(j)≤s},R1(j,s)={x|x(j)>s}
c^m=1Nm∑xi∈Rm(j,s)yi,x∈RM,m=1,2
(3) 继续对两个子区域调用步骤(1),(2),直至满足停止条件
(4) 将输入空间划分为M个区域 R1,R2,⋯,RM ,生成决策树
f(x)=∑m=1Mc^mI(x∈Rm)
观察该算法可以发现,该算法的核心思想是让决策树对数据集D中的样本进行拟合,并使预测误差的平方最小。
介绍完了生成算法,我们再来介绍CART决策树的剪枝算法
同样,这里我们还是要使用损失函数 Cα(T) ,但是回归树的损失函数和分类树的损失函数定义略有不同:
相同点是:它们拥有同样的结构:损失函数=损失项 C(T) +正则化项 α|T|
详细的回归树剪枝算法在《统计学习方法》的5.5.2节中已经介绍的非常清楚,此处不再赘述。但是在这里说一下我的想法:
到此,可以发现CART的剪枝算法和3.3节中介绍的剪枝算法有一个巨大的不同点:
分类树和回归树在选择最优特征时使用的标准也不同,分类树使用基尼指数作为选择最优特征的标准。下面来介绍一下基尼指数的定义:
在分类问题中,假设有K个类,样本点属于第k类的概率为 pk ,则概率分布的基尼指数定义为:
Gini(p)=∑k=1Kpk(1−pk)=1−∑k=1Kp2k
对于二分类问题来说,若样本点属于第一个类的概率是 p ,则概率分布的基尼指数为
Gini(p)=2p(1−p)
对于给定的样本集合,其基尼指数为
Gini(D)=1−∑k=1K(|Ck||D|)2
这里, Ck 是D中属于第k类的样本子集,K是类的个数
由于CART决策树是二叉树,因此样本集合D会被特征A切分为 D1 和 D2 两部分,即
D1={(x,y)∈D|A(x)=a},D2=D−D1
则某个节点在特征A的条件下,集合D的基尼指数定义为
Gini(D,A)=|D1||D|Gini(D1)+|D2||D|Gini(D2)
为什么这里又用基尼指数而不使用节点的熵了呢?
因为基尼指数和熵都表示同样的物理意义,及系统的混乱程度,因此是使用哪一个都可以的。基尼指数越大,样本集合的不确定性就越大,那么这个特征A的分类能力就越差。
这里给出熵,基尼指数和分类误差率之间的关系图:
本质上CART分类树的生成算法和ID3,C4.5没有特别大的区别,都是计算每个特征对应的熵或者基尼指数,然后选择分类特性最好的特征,切分数据集,再递归上边的操作。
CART分类树生成算法在《统计学习方法》的算法5.6已经讲的很清楚了,此处不再赘述。
CART分类树的剪枝算法
和前面的回归树一样,我们也是采用了使损失函数最小化的原则来对过于复杂的决策树进行剪枝。损失函数也是分为损失项和正则项两项,只是分类树的损失项计算的是剪枝前和剪枝后的基尼指数,回归树计算的是预测误差的平方值,其余的部分全都相同,算法的每个步骤也都没有变化。可以参考上面回归树的剪枝算法,把损失函数换一下即可。
提升(boosting)方法是一种常用的统计学习方法,它的基本思路是:既然一个分类器的效果不好,那么我就学习多个分类器,让第i个分类器去重点学习第i-1个分类器没有正确分类的那些样本,最后将这些小的分类器线性组合,组合成一个大的分类器,让它们共同对样本进行分类。
提升算法的代表就是Adaboost算法,下面我们来介绍一下Adaboost算法
Adaboost算法的核心思想有两个:
Adaboost算法在《统计学习方法》的第八章,算法8.1中介绍的很清楚,次数不再重复,只是谈一下我对算法的一些认识:
到这里可能会有疑问,boost算法有没有更一般化的模型呢?
答案是有的!
其实Adaboost是前向分布算法的特例,前向分步算法的模型是由基本分类器组成的加法器,损失函数是指数函数。它的推导在《统计学习方法》第8.3.2节已经介绍的很清楚了,这里不再赘述。
并且通过推导还给出了Adaboost算法训练误差的上界:
1N∑i=1NI(G(xi)≠yi)≤exp(−2Mγ2)
式中,N是训练集D中的样本数量, G(xi) 是我们训练好的分类器,M是组成 G(xi) 的子分类器的数量, γ 是一个常数。
这个不等式告诉我们,随着子分类器数量M的增加,分类器的训练误差乘指数下降,这是个很好的性质,说明可以通过增大M来提高分类正确率!
但是要注意的是,当M已经够大时,分类错误率的下降是有限的,但训练分类器所化的时间乘线性增长,因此还需要在M和错误率中间做一个折中。
第4节介绍了普通分类器的提升算法,而决策树本质上也是一个分类器,因此也有对应的提升算法。并且分类树和回归树都由相应的提升算法。
首先先来看一下提升树的模型:
fM(x)=∑m=1MT(x;Θm)
式中 T(x;Θm) 表示决策树; Θm 为决策树的参数,比如每个节点的切分特征,切分点这类参数;M为树的个数
通过和Adaboost的模型进行对比可以发现,提升树模型最大的不同就是表达式中缺了权重 αm ,这意味着每棵树对于最终输出的贡献是相同的。
具体的回归树算法见《统计学习方法》中的算法8.3
要特别注意的是:Adaboost中,每轮循环是要调整样本的权重的,而这里,回归问题的提升树的每轮循环学习的是预测残差( rmi=yi−fm−1(xi) ),因此提升树模型中才没有参数 αm 。
有了前面提升树的相关知识,理解GBDT就方便多了。提升树中,每轮循环学习的是残差,而GBDT中,只是将残差换成了负梯度而已,其他的步骤全都相同,详细算法在《统计学习方法》中的算法8.4。
这里说一下我觉得在回归树的GBDT算法中需要注意的几点:
由于书上只介绍了回归树的损失函数,这里再补充一下GBDT分类树的算法:
GBDT的剪枝算法:前面光说了怎么产生提升树模型,但是其实在每轮训练子决策树的时候,训练完成后还应该有剪枝操作,原理和第3.3节中介绍的相同。