决策树及提升算法

来源:互联网 发布:网络优化工程师待遇 编辑:程序博客网 时间:2024/06/10 23:23

决策树及提升算法

1. 决策树模型

决策树(decision tree)是一种基本的分类与回归算法,从名字就可以看出,该模型呈现树状结构,起始决策树就是一系列if-then规则的集合,通过对一系列条件的判断,最终输出一个模型预测的结果。下面给出决策树的模型图:



通过图片我们来了解几个概念:
1. 决策树中的节点分为两种:1.内部节点(椭圆形的)2.叶节点(矩形的)
2. 决策树由有向边和节点组成
3. 每个内部节点表示一个特征,每个叶节点表示一个分类结果

假定我们给出了训练数据集:

D={(x1,y1),(x2,y2),,(xN,yN)}

其中xi是第i个特征向量,每个特征向量中有n个特征,yi是类标记,表示第i个特征向量xi属于第几类。决策树的学习目标就是尽可能的对训练数据集中的数据进行正确分类。决策树学习用损失函数表示这一目标,决策树学习的损失函数通常是正则化的极大似然函数(这一点在接下来的讲解中可以看到,损失函数很明显的分为了似然函数和正则化项两部分),而学习策略就是将损失函数最小化。
同时,我们又了解到从所有可能的决策树中找出最优的决策树是一个NP问题,因此我们只能通过启发式的算法找出次最优的决策树。
这里还应该注意到过拟合的问题,如果单纯的追求决策树对训练数据集的分类正确率,就会导致决策树的过拟合(对于训练数据集有着很高的分类正确率),泛化能力不好(对数据集之外的特征向量进行分类时,正确率低下)。这时的决策树复杂度过高,我们要对决策树进行剪枝操作,来降低其复杂度,提高泛化能力。这部分知识会一并放在第三部分中讲解。

2. 决策树特征选择

一个特征向量x中有n个不同的特征,那么在决策树的内部节点中,我们到底选择哪一个特征对数据集进行切分呢?下面介绍的信息增益信息增益比的概念就是选择特征的标准。

2.1 信息增益

在介绍信息增益之前,我们先来介绍一下的概念。熵这个概念是从物理学中引用过来的,表示一个系统的混乱程度,熵越大,表示系统越混乱。熵的定义式如下:

H(x)=i=1npilogpi

P(X=xi)=pi

H(x)的图像画出来可以看出,当pi间相等时,熵的数值达到最大,即此时系统是最混乱的。
再来给出条件熵的定义式:
H(Y|X)=i=1NpiH(Y|X=xi)

条件熵表示:当我们知道了X后,Y的不确定度。
到这里,我们就可以定义信息增益了:
g(D,A)=H(D)H(D|A)

g(D,A)表示特征A使训练数据集D的不确定度减小的程度。使信息增益越大的特征具有更强的分类能力,因此我们应该尽可能的优先使用使信息增益尽可能大的特征。

2.2 信息增益比

2.1节中介绍了信息增益的概念,那么信息增益比的概念就比较好理解了

gR(D,A)=g(D,A)HA(D)

它表示信息增益占分类前系统熵的比重,作用和信息增益一样,都是表示特征A使系统混乱程度下降的多少,应该优先选择使信息增益比最大的特征。

2.3 分类问题的信息增益算法

前面讲了很多概念,但是没讲在实际使用时,给定了数据集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=DiCk|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)

3. ID3、C4.5、CART算法

前面我们介绍了如何计算信息增益,也就知道了如何选择决策树中每个节点进行分类的特征,下面来具体的介绍三种决策树生成算法。

3.1 ID3算法

算法核心思想:在决策树的各个节点上应用信息增益准则选择特征,递归的构建决策树。
具体方法:从根节点开始,对节点计算所有可能的特征的信息增益,选择信息增益最大的特征作为节点的特征,然后使用该特征对训练集进行分类,并建立子节点,再对子节点和子节点的训练数据集进行信息增益计算,递归的调用这种方法建立决策树。算法停止条件是,直到所有的特征信息增益很小,或者没有特征可以选择,就终止算法,得到决策树。
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为训练集,以AAg为特征集,递归地调用(1)~(5),得到子树Ti,返回Ti

这里说一下算法中需要注意的地方:

  1. 第(6)步中的AAg表示节点的分类特征不能重复使用,如果前面已经将某个特征用于分类了,那么接下来这个特征就不能被使用了。
  2. ID3算法只有生成操作,而没有剪枝操作,这将造成生成的决策树模型过于复杂,产生过拟合现象,需要单独配合剪枝操作提高泛化能力。

3.2 C4.5的生成算法

C4.5算法本质上和ID3没有特别大的差异,只是将选择特征的标准从信息增益变成了信息增益比,其余部分全部相同。
因此这里不再给出详细的算法步骤。

3.3 剪枝操作

剪枝的定义:在决策树学习中将已经生成的决策树进行简化的过程称为剪枝(pruning)。剪枝从已生成的树上裁掉一些子树或叶节点,并将其根节点作为新的叶节点,从而简化分类树模型。
剪枝的核心思想:剪枝操作往往通过极小化决策树的损失函数(loss function)或代价函数(cost function)来实现。
这里我们给出一些变量和损失函数的定义:

设树T的叶节点个数为|T|t是树T的叶节点,该叶节点上有Nt个样本,其中属于第k类的样本有Ntk个,k=1,2,,KHt(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) 递归地从树的叶节点向上回缩。设一组叶节点回缩到其父节点之前与之后的整体树分别是TBTA,其对应的损失函数值分别是Cα(TB)Cα(TA),如果

Cα(TB)Cα(TA)

则进行剪枝,即将父节点变为新的子节点。
(3) 返回(2),直至不能继续为止,得到损失函数最小的子树Tα

将上述算法加速:介绍完上面的算法我们发现,其实剪枝前后熵的变化只和被剪枝的那个子树和正则项有关,而正则项又是一个线性的,因此我们完全可以只计算局部子树的熵,而不用把整棵树的熵全算出来,这样进一步加快了算法的速度。这样的想法可以使用类似于动态规划的算法实现!

在使用ID3和C4.5算法产生决策树之后,就可以用这个剪枝算法将决策树模型简化。

3.4 CART算法

CART的全称是分类与回归树(Classificatioin and Regression Tree),CART同样由特征选择、树的生成及剪枝组成,既可以用于分类也可以用于回归。
CART与前面两种算法生成的决策树的最大不同在于:CART是二叉树,而前两种算法生成的决策树中,一个节点可能下面有很多分叉。CART等价与递归的二分每个特征,即将输入空间划分为有限个单元,每个单元有一个对应的输出值或分类结果。

3.4.1 CART回归树的生成和剪枝

在上面的介绍中,我们知道CART其实是把输入空间划分成了有限个单元,假设将输入空间划分为了M个单元R1,R2,,RM,并且每个单元都由一个固定的输出值cm,于是回归树模型可以表示为:

f(x)=m=1McmI(xRm)

上式中,I(xRm)是指示函数,如果括号内为true的话,输出1,如果括号内为false,输出0。
那么怎么确定cm呢?这个由训练数据集D落在Rm内的样本对应的输出值的平均决定,计算式如下:
c^m=ave(yi|xiRm)

接下来就面临一个重点问题,怎么对输入空间进行切分,特征的取值是连续的,因此无法遍历到每个特征的所有取值,那么怎么办呢?我们使用启发式的方法,选择特征向量中的第j个特征x(j)和对应的取值s,作为切分变量和切分点,因为CART是二叉树结构,所以每个节点会将x(j)对应的输入空间切分为两部分:
R1(j,s)={x|x(j)s}R2(j,s)={x|x(j)>s}

然后遍历数据集D中的所有样本,寻找最优切分变量j和最优切分点s,即求解下面这个问题:
minj,s[minc1xiR1(j,s)(yic1)2+minc1xiR2(j,s)(yic2)2]

s的遍历就是遍历数据集D中所有样本的x(j)特征的取值,每次选定j和s后,都要计算一个相应的c1c2,遍历完成之后选出使上式取得最小值的j和s。通过不断的递归这个算法,直到满足停止条件,CART回归树就生成好了。

最小二乘回归树生成算法
输入:训练数据集D
输出:回归树f(x)
在训练数据集所在的输入空间中,递归地将每个区域划分为两个子区域并决定每个子区域的输出值,构建二叉决策树:
(1) 选择最优的切分变量j和切分点s,求解

minj,s[minc1xiR1(j,s)(yic1)2+minc1xiR2(j,s)(yic2)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=1NmxiRm(j,s)yixRMm=1,2

(3) 继续对两个子区域调用步骤(1),(2),直至满足停止条件
(4) 将输入空间划分为M个区域R1,R2,,RM,生成决策树
f(x)=m=1Mc^mI(xRm)

观察该算法可以发现,该算法的核心思想是让决策树对数据集D中的样本进行拟合,并使预测误差的平方最小。

介绍完了生成算法,我们再来介绍CART决策树的剪枝算法
同样,这里我们还是要使用损失函数Cα(T),但是回归树的损失函数和分类树的损失函数定义略有不同

  • 分类树的损失函数是计算树的熵的大小
  • 回归树的损失函数是计算树的预测误差的大小

相同点是:它们拥有同样的结构:损失函数=损失项C(T)+正则化项α|T|

详细的回归树剪枝算法在《统计学习方法》的5.5.2节中已经介绍的非常清楚,此处不再赘述。但是在这里说一下我的想法:

  • 算法的第(4)步对整体树T进行了更新,也就是说每轮循环中的决策树是不同的,并且内部节点越来越少,直至只由根节点和两个叶节点组成。
  • 算法的第(6)步中,应该是”返回到步骤(3)“而非”步骤(2)“,要不然可能在某轮循环中,min(α,g(t))的值就是α,那么在步骤(4)中就会出问题,因为不存在g(t)=α的内部节点,也就无法进行剪枝操作。

到此,可以发现CART的剪枝算法和3.3节中介绍的剪枝算法有一个巨大的不同点

  • 3.3节的剪枝算法中,损失函数里面的参数α是我们预先给定的,是个超参数,不能通过训练来获得一个较好的值。只能先通过交叉验证的方法获得一个较好的值,然后设置到损失函数中,再运行剪枝算法才能获得较好的结果。
  • CART算法中,参数α的值是在剪枝算法的循环中不断产生的,并且通过最后的交叉验证自动的选取了一个最优的值,这给算法的使用带来了很大的便利。

3.4.2 CART分类树的生成和剪枝

分类树和回归树在选择最优特征时使用的标准也不同,分类树使用基尼指数作为选择最优特征的标准。下面来介绍一下基尼指数的定义:

在分类问题中,假设有K个类,样本点属于第k类的概率为pk,则概率分布的基尼指数定义为:

Gini(p)=k=1Kpk(1pk)=1k=1Kp2k

对于二分类问题来说,若样本点属于第一个类的概率是p,则概率分布的基尼指数为
Gini(p)=2p(1p)

对于给定的样本集合,其基尼指数为
Gini(D)=1k=1K(|Ck||D|)2

这里,Ck是D中属于第k类的样本子集,K是类的个数
由于CART决策树是二叉树,因此样本集合D会被特征A切分为D1D2两部分,即
D1={(x,y)D|A(x)=a}D2=DD1

则某个节点在特征A的条件下,集合D的基尼指数定义为
Gini(D,A)=|D1||D|Gini(D1)+|D2||D|Gini(D2)

为什么这里又用基尼指数而不使用节点的熵了呢?
因为基尼指数和熵都表示同样的物理意义,及系统的混乱程度,因此是使用哪一个都可以的。基尼指数越大,样本集合的不确定性就越大,那么这个特征A的分类能力就越差。
这里给出熵,基尼指数和分类误差率之间的关系图:


本质上CART分类树的生成算法和ID3,C4.5没有特别大的区别,都是计算每个特征对应的熵或者基尼指数,然后选择分类特性最好的特征,切分数据集,再递归上边的操作。

CART分类树生成算法在《统计学习方法》的算法5.6已经讲的很清楚了,此处不再赘述。

CART分类树的剪枝算法
和前面的回归树一样,我们也是采用了使损失函数最小化的原则来对过于复杂的决策树进行剪枝。损失函数也是分为损失项和正则项两项,只是分类树的损失项计算的是剪枝前和剪枝后的基尼指数,回归树计算的是预测误差的平方值,其余的部分全都相同,算法的每个步骤也都没有变化。可以参考上面回归树的剪枝算法,把损失函数换一下即可。

4. Adaboost算法

提升(boosting)方法是一种常用的统计学习方法,它的基本思路是:既然一个分类器的效果不好,那么我就学习多个分类器,让第i个分类器去重点学习第i-1个分类器没有正确分类的那些样本,最后将这些小的分类器线性组合,组合成一个大的分类器,让它们共同对样本进行分类。
提升算法的代表就是Adaboost算法,下面我们来介绍一下Adaboost算法

Adaboost算法的核心思想有两个:

  1. 若一共设置M个分类器,那么算法在每轮循环中,会自动的根据上一个分类器的表现来改变训练样本的权重,让该分类器尽可能的将上次没有正确分类的样本来正确分类。
  2. 在最后组合的时候,每个分类器对最终的分类结果的贡献是不一样的,分类错误率越低的分类器,贡献越大,反之就越小。

Adaboost算法在《统计学习方法》的第八章,算法8.1中介绍的很清楚,次数不再重复,只是谈一下我对算法的一些认识:

  1. 算法的步骤(1)中,样本的初始化权重都一样,这是很自然的,由于没有前面分类器的分类误差,所以每个样本权重都一样
  2. 步骤(2)相当于是一个for循环,只有M个分类器都训练完成了才能退出
  3. 步骤(2)(b)中wmi表示的是:在训练第m个分类器时,第i个样本所占的权重
  4. 步骤(3)中的f(x)仅是各分类器输出的线性组合,输出的是一个数值而不是最终的分类结果
  5. 步骤(3)中的G(x)是在f(x)外边加了一个符号函数,因此G(x)的输出就是最终的分类结果

到这里可能会有疑问,boost算法有没有更一般化的模型呢?
答案是有的!
其实Adaboost是前向分布算法的特例,前向分步算法的模型是由基本分类器组成的加法器,损失函数是指数函数。它的推导在《统计学习方法》第8.3.2节已经介绍的很清楚了,这里不再赘述。
并且通过推导还给出了Adaboost算法训练误差的上界:

1Ni=1NI(G(xi)yi)exp(2Mγ2)

式中,N是训练集D中的样本数量,G(xi)是我们训练好的分类器,M是组成G(xi)的子分类器的数量,γ是一个常数。
这个不等式告诉我们,随着子分类器数量M的增加,分类器的训练误差乘指数下降,这是个很好的性质,说明可以通过增大M来提高分类正确率!
但是要注意的是,当M已经够大时,分类错误率的下降是有限的,但训练分类器所化的时间乘线性增长,因此还需要在M和错误率中间做一个折中。

5. 提升树与GBDT算法

第4节介绍了普通分类器的提升算法,而决策树本质上也是一个分类器,因此也有对应的提升算法。并且分类树和回归树都由相应的提升算法。
首先先来看一下提升树的模型:

fM(x)=m=1MT(x;Θm)

式中T(x;Θm)表示决策树;Θm为决策树的参数,比如每个节点的切分特征,切分点这类参数;M为树的个数
通过和Adaboost的模型进行对比可以发现,提升树模型最大的不同就是表达式中缺了权重αm,这意味着每棵树对于最终输出的贡献是相同的。

具体的回归树算法见《统计学习方法》中的算法8.3
特别注意的是:Adaboost中,每轮循环是要调整样本的权重的,而这里,回归问题的提升树的每轮循环学习的是预测残差(rmi=yifm1(xi)),因此提升树模型中才没有参数αm

有了前面提升树的相关知识,理解GBDT就方便多了。提升树中,每轮循环学习的是残差,而GBDT中,只是将残差换成了负梯度而已,其他的步骤全都相同,详细算法在《统计学习方法》中的算法8.4

这里说一下我觉得在回归树的GBDT算法中需要注意的几点:

  1. 算法8.4的步骤(1)中,c表示一个常数,也就是不论整棵数输入什么样的x,输出值都是cc是怎么取的呢?取使损失函数达到最小值的一个数值即可。这样可以是后面收敛的更快,提升算法的性能表现。
  2. 步骤(2)(a)的求导该怎么求?应该把f(x)看成一个整体,然后对损失函数L(y,f(x))求导,下面举个例子:L(yi,f(xi))=(yif(xi))2,那么对f(xi)求导即为2(yif(xi))。然后将数据集中具体的(xi,yi)带入计算即可得到相应的残差值。
  3. 注意步骤(2)(c)中cmj的计算还用的c和初始化时的那个c是不同的,其中的值是随着每轮循环都改变的。
  4. 最终学习出来的GBDT回归树和前面的提升树有着相同的形式,这也是因为两者都是对残差值进行学习的,而提升树中作差得到的残差值其实是梯度的一个特例。

由于书上只介绍了回归树的损失函数,这里再补充一下GBDT分类树的算法

  1. 分类树的损失函数定义为:L(y,f(x))=log(1+exp(yf(x))),其中y{1,1},这是二分类的情况。在训练完成之后,G(x)=sign(fM(x))=sign(Mm=1T(x;Θm))
  2. 求导的话仍然和回归树一样
  3. cmj=argmincxiRmjlog(1+exp(yi,fm1(xi)+c))

GBDT的剪枝算法:前面光说了怎么产生提升树模型,但是其实在每轮训练子决策树的时候,训练完成后还应该有剪枝操作,原理和第3.3节中介绍的相同。