机器学习之决策树

2020/11/23

摘要

决策树算法在机器学习中算是很经典的一个算法系列。它既可以作为分类算法,也可以作为回归算法,同时也特别适合集成学习比如随机森林。决策树模型是一类算法的集合,在数据挖掘十大算法中,具体的决策树算法占有两席位置,即C4.5和CART算法。

决策树分类的思想类似于找对象。现想象一个女孩的母亲要给这个女孩介绍男朋友,于是有了下面的对话:

女儿:多大年纪了?

母亲:26。

女儿:长的帅不帅?

母亲:挺帅的。

女儿:收入高不?

母亲:不算很高,中等情况。

女儿:是公务员不?

母亲:是,在税务局上班呢。

女儿:那好,我去见见。

这个女孩的决策过程就是典型的分类树决策。相当于通过年龄、长相、收入和是否公务员对将男人分为两个类别:见和不见。假设这个女孩对男人的要求是:30岁以下、长相中等以上并且是高收入者或中等以上收入的公务员,那么这个可以用下图表示女孩的决策逻辑:

决策树(decision tree)是一个树结构(可以是二叉树或非二叉树)。其每个非叶节点表示一个特征属性上的测试,每个分支代表这个特征属性在某个值域上的输出,而每个叶节点存放一个类别。使用决策树进行决策的过程就是从根节点开始,测试待分类项中相应的特征属性,并按照其值选择输出分支,直到到达叶子节点,将叶子节点存放的类别作为决策结果。

决策树是在已知各种情况发生概率((各个样本数据出现中,不同特征出现的概率))的基础上,通过构建决策树来进行分析的一种方式。常用算法有ID3、C4.5、CART。

目前决策树已经成功运用于医学、制造产业、天文学、分支生物学以及商业等诸多领域。之前介绍的K-近邻算法可以完成很多分类任务,但是它最大的缺点就是无法给出数据的内在含义,决策树的主要优势就在于数据形式非常容易理解。决策树算法能够读取数据集合,构建类似于上面的决策树。决策树很多任务都是为了数据中所蕴含的知识信息,因此决策树可以使用不熟悉的数据集合,并从中提取出一系列规则,机器学习算法最终将使用这些机器从数据集中创造的规则。专家系统中经常使用决策树,而且决策树给出结果往往可以匹敌在当前领域具有几十年工作经验的人类专家。

算法

分类解决离散问题,回归解决连续问题。

  1. 分类树是基于概率来构建的,采用信息增益、信息增益率、基尼系数来作为树的评价指标。
  2. 回归数是基于平均值来构建的,采用均方差作为树的评价指标。决策树:信息论;逻辑回归、贝叶斯:概率论。

构造决策树的关键步骤是分裂属性。所谓分裂属性就是在某个节点处按照某一特征属性的不同划分构造不同的分支,其目标是让各个分裂子集尽可能地“纯”。尽可能“纯”就是尽量让一个分裂子集中待分类项属于同一类别。分裂属性分为三种不同的情况:

  1. 属性是离散值且不要求生成二叉决策树。此时用属性的每一个划分作为一个分支。
  2. 属性是离散值且要求生成二叉决策树。此时使用属性划分的一个子集进行测试,按照“属于此子集”和“不属于此子集”分成两个分支。
  3. 属性是连续值。此时确定一个值作为分裂点split_point,按照>split_point和<=split_point生成两个分支。

构造决策树的关键性内容是进行属性选择度量,属性选择度量是一种选择分裂准则,它决定了拓扑结构及分裂点split_point的选择。属性选择度量算法有很多,如ID3,C4.5等,一般使用自顶向下递归分治法,并采用不回溯的贪心策略(只考虑当前数据特征的最好分割方式,不能回溯操作,只能从上往下分割)。

决策树构建过程(步骤):

  1. 将所有的特征看成一个一个的节点;
  2. 遍历所有特征,遍历到其中某一个特征时:遍历当前特征的所有分割方式,找到最好的分割点,将数据划分为不同的子节点,计算划分后子节点的纯度信息;
  3. 在遍历的所有特征中,比较寻找最优的特征以及最优特征的最优划分方式,纯度越高,则对当前数据集进行分割操作;
  4. 对新的子节点继续执行2-3步,直到每个最终的子节点都足够纯。

决策树算法构建的停止条件:

  1. 当子节点中只有一种类型的时候停止构建(会导致过拟合)
  2. 当前节点种样本数小于某个值,同时迭代次数达到指定值,停止构建,此时使用该节点中出现最多的类别样本数据作为对应值(比较常用)

决策树三大算法

ID3算法:

策树ID3算法的信息论基础:

机器学习算法其实很古老,我们代码中经常使用的 if, else其实就已经在用到决策树的思想了。只是你有没有想过,有这么多条件,用哪个条件特征先做if,哪个条件特征后做if比较优呢?怎么准确的定量选择这个标准就是决策树机器学习算法的关键了。1970年代,一个叫昆兰的大牛找到了用信息论中的熵来度量决策树的决策选择过程,方法一出,它的简洁和高效就引起了轰动,昆兰把这个算法叫做ID3。在看ID3算法是怎么选择特征之前。首先需要知道一些信息论中的基本概念:

这个是熵和信息增益的基础概念,是对一个抽象事物的命名,无论用不用‘信息’来命名这种抽象事物,或者用其他名称来命名这种抽象事物,这种抽象事物是客观存在的。信息论是量化处理信息的分支科学。我们可以在划分数据之前使用信息论量化度量信息的内容。集合信息的度量方式称为香农熵或者简称为熵,这个名字来源于信息论之父克劳德•香农。熵定义为信息的期望值,在明晰这个概念之前,我们必须知道信息的定义。如果带分类的事物集合可以划分为多个类别当中,则某个类(xi)的信息(量)定义如下:

I(x)用来表示随机变量的信息,p(xi)指是当xi发生时的概率。当事件xi发生的概率p(xi)很小,但是它却发生了,那这个信息量相当大,比如买彩票中奖了,那么这个信息量肯定是很大的。相反,对于大概率事件,人们习以为常,那么这个事件的信息量就很小。这就体现在上述公式中。

:熵度量了事物的不确定性,越不确定的事物,它的熵就越大。具体的,随机变量X的熵的表达式如下:

其中n代表X的n种不同的离散取值。

熟悉了一个变量X的熵,很容易推广到多个个变量的联合熵,这里给出两个变量X和Y的联合熵表达式:

有了联合熵,又可以得到条件熵的表达式H(X Y),条件熵类似于条件概率,它度量了我们的X在知道Y以后剩下的不确定性。表达式如下:

刚才提到H(X)度量了X的不确定性,条件熵H(X Y)度量了我们在知道Y以后X剩下的不确定性,那么H(X)-H(X Y)呢?从上面的描述大家可以看出,它度量了X在知道Y以后不确定性减少程度,这个度量我们在信息论中称为互信息,记为I(X,Y)。在决策树ID3算法中叫做信息增益。ID3算法就是用信息增益来判断当前节点应该用什么特征来构建决策树。信息增益大,则越适合用来分类。原则:每次需要分裂时,计算每个属性的增益率,然后选择信息增益率最大的属性进行分裂。
左边的椭圆代表H(X),右边的椭圆代表H(Y),中间重合的部分就是我们的互信息或者信息增益I(X,Y), 左边的椭圆去掉重合部分就是H(X Y),右边的椭圆去掉重合部分就是H(Y X)。两个椭圆的并就是H(X,Y)。

信息熵:是度量样本纯度(不确定度)最常用的一种指标。所谓样本纯度,相反而言之就是凌乱程度。如一个数据集U中的样本都属于同一类,那么这时样本纯度最高而凌乱程度最低。如果当前样本集合 D 中第 k 类样本所占的比例为 pk ,则 D 的信息熵定义为:

其中D表示样本集合, y 样本中类别的数目, pk表示第k种分类占集合的比例。Ent(D)的值越小,D的纯度越高。熵度量了事物的不确定性,越不确定的事物,它的熵就越大。

信息增益:指的是使用某一个属性a进行划分后,所带来的纯度提高的大小(百话了解就是在划分数据集之前和之后信息发生的变化)。一般而言,信息增益越大,意味着使用属性a来进行划分所获得的“纯度提升”越大。用属性 a 对样本集 D 进行划分所获得的信息增益:

信息增益 = 根节点的信息熵 - 所有分支节点的信息熵的加权和。或者说信息增益 = 信息熵 - 条件熵。(信息熵是代表随机变量的复杂度(不确定度),条件熵代表在某一个条件下,随机变量的复杂度(不确定度)。

上图的描述是使用属性a对样本集合D进行划分,因为a有V个取值{a1,a2,…,aV},因此决策树会有V个分支。划分后每一个节点中样本的数量为属性a=ak的样本的数量。样本集合中,属性 a 上取值为 av 的样本集合,记为 Dv。权值为划分后属性a=ak节点中样本的数量与划分前节点中的样本数量的比值,即概率。概率确保了权重的和为1。

信息增益表示得知属性 a 的信息而使得样本集合不确定度减少的程度。在决策树算法中,我们的关键就是每次选择一个特征,特征有多个,那么到底按照什么标准来选择哪一个特征。这个问题就可以用信息增益来度量。如果选择一个特征后,信息增益最大(信息不确定性减少的程度最大),那么我们就选取这个特征。

决策树ID3算法的思路:上面提到ID3算法就是用信息增益大小来判断当前节点应该用什么特征来构建决策树,用计算出的信息增益最大的特征来建立决策树的当前节点。这里我们举一个信息增益计算的具体的例子。比如我们有15个样本D,输出为0或者1。其中有9个输出为1, 6个输出为0。 样本中有个特征A,取值为A1,A2和A3。在取值为A1的样本的输出中,有3个输出为1, 2个输出为0,取值为A2的样本输出中,2个输出为1,3个输出为0, 在取值为A3的样本中,4个输出为1,1个输出为0。

对应的信息增益为 :

如果没明白,再看一个更加具体的例子(必懂):

正例(好瓜)占 8/17,反例占 9/17 ,根结点的信息熵为:

计算当前属性集合{色泽,根蒂,敲声,纹理,脐部,触感}中每个属性的信息增益。色泽有3个可能的取值:{青绿,乌黑,浅白}:

D1(色泽=青绿) = {1, 4, 6, 10, 13, 17},正例 3/6,反例 3/6 D2(色泽=乌黑) = {2, 3, 7, 8, 9, 15}, 正例 4/6,反例 2/6 D3(色泽=浅白) = {5, 11, 12, 14, 16}, 正例 1/5,反例 4/5

3个分支结点的信息熵(条件熵):

那么可以知道属性色泽的信息增益是:

同理,我们可以求出其它属性的信息增益,分别如下:

于是我们找到了信息增益最大的属性纹理,它的Gain(D,纹理) = 0.381最大。于是我们选择的划分属性为纹理,如下:

因为 “纹理” 有3个取值,因此决策树会有3个分支。于是,我们可以得到了三个子结点,对于这三个子节点,我们可以递归的使用刚刚找信息增益最大的方法进行选择特征属性,比如:D1(纹理=清晰) = {1, 2, 3, 4, 5, 6, 8, 10, 15},第一个分支结点可用属性集合{色泽、根蒂、敲声、脐部、触感},基于 D1各属性的信息增益,分别求的如下:

于是我们可以选择特征属性为根蒂,脐部,触感三个特征属性中任选一个(因为他们三个相等并最大),其它俩个子结点同理,然后得到新一层的结点,再递归的由信息增益进行构建树即可。

到这里为止,我们已经知道了构建树的算法。但是信息增益准则其实是对可取值数目较多的属性有所偏好!现在假如我们把数据集中的“编号”也作为一个候选划分属性。我们可以算出“编号”的信息增益是0.998。因为每一个样本的编号都是不同的(由于编号独特唯一,条件熵为0了,每一个结点中只有一类,纯度非常高啊),也就是说,来了一个预测样本,你只要告诉我编号,其它特征就没有用了,这样生成的决策树显然不具有泛化能力。ID3算法虽然提出了新思路,但是还是有很多值得改进的地方。

决策树ID3算法的不足:
  1. ID3没有考虑连续特征,比如长度,密度都是连续值,无法在ID3运用。这大大限制了ID3的用途。
  2. ID3采用信息增益大的特征优先建立决策树的节点。就是上面说的信息增益准则其实是对可取值数目较多的属性有所偏好!在相同条件下,取值比较多的特征比取值少的特征信息增益大。比如一个变量有2个值,各为1/2,另一个变量为3个值,各为1/3,其实他们都是完全不确定的变量,但是取3个值的比取2个值的信息增益大。
  3. ID3算法对于缺失值的情况没有做考虑
  4. 没有考虑过拟合的问题。

ID3 算法的作者昆兰基于上述不足,对ID3算法做了改进,这就是C4.5算法,也许你会问,为什么不叫ID4,ID5之类的名字呢?那是因为决策树太火爆,他的ID3一出来,别人二次创新,很快 就占了ID4, ID5,所以他另辟蹊径,取名C4.0算法,后来的进化版为C4.5算法。下面我们就来聊下C4.5算法。

C4.5算法:

区别

分裂属性选择的评判标准是决策树算法之间的根本区别。区别于ID3算法通过信息增益选择分裂属性,C4.5算法通过信息增益率选择分裂属性。

C4.5算法对ID3算法主要做了一下几点改进:

  1. 能够处理离散型和连续型的属性类型,即将连续型的属性进行离散化处理;
  2. 通过信息增益率选择分裂属性,克服了ID3算法中通过信息增益倾向于选择拥有多个属性值的属性作为分裂属性的不足;
  3. 构造决策树之后进行剪枝操作;
  4. 能够处理具有缺失属性值的训练数据。
决策树C4.5算法的不足:
  1. 由于决策树算法非常容易过拟合,因此对于生成的决策树必须要进行剪枝。剪枝的算法有非常多,C4.5的剪枝方法有优化的空间。思路主要是两种,一种是预剪枝,即在生成决策树的时候就决定是否剪枝。另一个是后剪枝,即先生成决策树,再通过交叉验证来剪枝。后面讲CART树的时候会专门讲决策树的减枝思路,主要采用的是后剪枝加上交叉验证选择最合适的决策树。
  2. C4.5生成的是多叉树,即一个父节点可以有多个节点。很多时候,在计算机中二叉树模型会比多叉树运算效率高。如果采用二叉树,可以提高效率。
  3. C4.5只能用于分类,如果能将决策树用于回归的话可以扩大它的使用范围。
  4. C4.5由于使用了熵模型,里面有大量的耗时的对数运算,如果是连续值还有大量的排序运算。如果能够加以模型简化可以减少运算强度但又不牺牲太多准确性的话,那就更好了。

这4个问题在CART树里面部分加以了改进。所以目前如果不考虑集成学习话,在普通的决策树算法里,CART算法算是比较优的算法了。scikit-learn的决策树使用的也是CART算法。

CART算法:

CART算法对于C4.5算法的大部分不足做了改进,比如模型是用较为复杂的熵来度量,使用了相对较为复杂的多叉树,只能处理分类不能处理回归等。CART是一棵二叉树。既可以做回归,也可以做分类。首先,我们要明白,什么是回归树,什么是分类树。两者的区别在于样本输出,如果样本输出是离散值,那么这是一颗分类树。如果果样本输出是连续值,那么那么这是一颗回归树。当CART是分类树时,采用GINI值作为节点分裂的依据;当CART是回归树时,采用样本的最小方差作为节点分裂的依据。分类树的作用是通过一个对象的特征来预测该对象所属的类别,而回归树的目的是根据一个对象的信息预测该对象的属性,并以数值表示。

CART分类树算法的最优特征选择方法:

在ID3算法中我们使用了信息增益来选择特征,信息增益大的优先选择。在C4.5算法中,采用了信息增益比来选择特征,以减少信息增益容易选择特征值多的特征的问题。但是无论是ID3还是C4.5,都是基于信息论的熵模型的,这里面会涉及大量的对数运算。能不能简化模型同时也不至于完全丢失熵模型的优点呢?有!CART分类树算法使用基尼系数来代替信息增益比,基尼系数代表了模型的不纯度,基尼系数越小,则不纯度越低,特征越好。这和信息增益(比)是相反的。

什么是基尼值:

基尼值 Gini(D) 反映了从数据集中随机抽取两个样本,其类别标记不一致的概率。当数据集的纯度越高,每次抽到不同类别标记的概率越小。打个比方,在一个袋子里装100个乒乓球,其中有99个白球,1个黄球,那么当我们随机抽取两个球的时候,很大概率是抽到两个白球。所以数据集D的纯度可以用基尼值来度量,其定义如下:

基尼值越小,数据集D纯度越高。

什么是基尼指数:

基尼指数是针对于属性定义的,其反映的是,使用属性a进行划分后,所有分支中(使用基尼值度量的)纯度的加权和。属性a的基尼指数定义如下:

具体的,在分类问题中,假设有K个类别,第k个类别的概率为pk, 则基尼系数的表达式为:

如果是二类分类问题,计算就更加简单了,如果属于第一个样本输出的概率是p,则基尼系数的表达式为:

对于个给定的样本D,假设有K个类别, 第k个类别的数量为C

特别的,对于样本D,如果根据特征A的某个值a,把D分成D1和D2两部分,则在特征A的条件下,D的基尼系数表达式为:

大家可以比较下基尼系数表达式和熵模型的表达式,二次运算是不是比对数简单很多?尤其是二类分类的计算,更加简单。但是简单归简单,和熵模型的度量方式比,基尼系数对应的误差有多大呢?二分类模型中,熵、Gini系数、分类误差的比较情况(左下图);二类分类,基尼系数和熵之半(二分之一熵)的曲线如下(右下图):

从上图可以看出,基尼系数和熵之半的曲线非常接近,仅仅在45度角附近误差稍大。因此,基尼系数可以做为熵模型的一个近似替代。而CART分类树算法就是使用的基尼系数来选择决策树的特征。同时,为了进一步简化,CART分类树算法每次仅仅对某个特征的值进行二分,而不是多分,这样CART分类树算法建立起来的是二叉树,而不是多叉树。这样一可以进一步简化基尼系数的计算,二可以建立一个更加优雅的二叉树模型。

CART回归树算法的最优特征选择方法:

回归树,采用样本方差衡量节点纯度, 方差越大,节点越不纯,表示该节点的数据越分散,预测的效果就越差,所以方差越小,则不纯度越低,特征越好。如果一个节点的所有数据都相同,那么方差就为0,此时可以很肯定得认为该节点的输出值;如果节点的数据相差很大,那么输出的值有很大的可能与实际值相差较大。

回归方差计算公式:

因此,无论是分类树还是回归树,CART都要选择使子节点的GINI值或者回归方差最小的属性作为分裂的方案。即最小化:

分类树:

回归树:

CART树算法对于连续特征和离散特征处理的改进:

CART如何分裂成一棵二叉树?节点的分裂分为两种情况,连续型的数据离散型的数据。CART对连续型属性的处理与C4.5差不多,CART分类树算法通过最小化分裂后的GINI值CART回归树算法样本方差寻找最优分割点,将节点一分为二。

首先对于CART分类树连续值的处理问题(注意事特征,不是输出),其思想和C4.5是相同的,都是将连续的特征离散化。唯一的区别在于在选择划分点时的度量方式不同,C4.5使用的是信息增益比,则CART分类树使用的是基尼系数。具体的思路如下,比如m个样本的连续特征A有m个,从小到大排列为a1,a2,…,am,则CART算法取相邻两样本值的平均数,一共取得m-1个划分点,其中第i个划分点Ti表示为:

如果没懂,再来看一个超具体的案例(针对离散型属性的分类和回归CART二叉树):

针对上面的数据,以属性“职业”为例,一共有三个离散值,“学生”、“老师”、“上班族”。该属性有三种划分的方案,分别为{“学生”}、{“老师”、“上班族”},{“老师”}、{“学生”、“上班族”},{“上班族”}、{“学生”、“老师”},分别计算三种划分方案的子节点GINI值或者样本方差,选择最优的划分方法,如下图所示:

第一种划分方法:{“学生”}、{“老师”、“上班族”}:

预测是否已婚(分类):

预测年龄(回归):

第二种划分方法:{“老师”}、{“学生”、“上班族”}:

预测是否已婚(分类):

预测年龄(回归):

第三种划分方法:{“上班族”}、{“学生”、“老师”}:

预测是否已婚(分类):

预测年龄(回归):

综上,如果想预测是否已婚,则选择{“上班族”}、{“学生”、“老师”}的划分方法,如果想预测年龄,则选择{“老师”}、{“学生”、“上班族”}的划分方法。

CART总结:
  1. CART是一棵二叉树,每一次分裂会产生两个子节点,对于连续性的数据,直接采用与C4.5相似的处理方法,对于离散型数据,选择最优的两种离散值组合方法。
  2. CART既能是分类数,又能是二叉树。如果是分类树,将选择能够最小化分裂后节点GINI值的分裂属性;如果是回归树,选择能够最小化两个节点样本方差的分裂属性。
  3. CART跟C4.5一样,需要进行剪枝,采用CCP(代价复杂度的剪枝方法)。
决策树CART算法的不足:
  1. 无论是ID3, C4.5还是CART,在做特征选择的时候都是选择最优的一个特征来做分类决策,但是大多数,分类决策不应该是由某一个特征决定的,而是应该由一组特征决定的。这样决策得到的决策树更加准确。这个决策树叫做多变量决策树(multi-variate decision tree)。在选择最优特征的时候,多变量决策树不是选择某一个最优特征,而是选择最优的一个特征线性组合来做决策。这个算法的代表是OC1。
  2. 如果样本发生一点点的改动,就会导致树结构的剧烈改变。这个可以通过集成学习里面的随机森林之类的方法解决。   

决策树的剪枝:

由于决策时算法很容易对训练集过拟合,而导致泛化能力差。(如果我们用这个决策树来对训练集进行分类的话,那么这颗树的表现非常好。但是在测试集上的表现就远没有在训练集上的表现好,这就是过拟合问题。)为了解决这个问题,我们需要对CART树进行剪枝,即类似于线性回归的正则化,来增加决策树的泛化能力。

树的剪枝就是剪掉树的一些枝叶,考虑大决策树的枝代表着逻辑判断,也代表着分类后的子集。决策树的剪枝就是删掉一些不必要的逻辑判断,并且将子集合并。这样确实会造成在训练集上子集不纯的现象,但是因为我们最终目标是模型在测试集上的效果,所以牺牲在训练集上的效果换取解决测试集的过拟合问题这样的做法也是值得的。决策树剪枝可以分为两类,预剪枝(Pre-Pruning)和后剪枝(Post-Pruning)。

PrePrune:预剪枝,及早的停止树增长;PostPrune:后剪枝,在已生成过拟合决策树上进行剪枝,可以得到简化版的剪枝决策树。

预剪枝:就是在生成决策树的同时进行剪枝。正常决策树的生成是只要有信息增益就要进行分支,换句话可以说所有决策树的构建方法,都是在无法进一步降低熵的情况下才会停止创建分支的过程,为了避免过拟合,可以设定一个阈值,熵减小的数量小于这个阈值,即使还可以继续降低熵,也停止继续创建分支。预剪枝就是设定一个阈值,比如只有在信息增益大于这个阈值的时候(也即是在分类后的信息混乱程度减小程度大于一定标准的时候)才进行分类。如果在信息增益过小的情况下,即使存在信息增益的现象,也不会对其进行分支。预剪枝的思想比较简单,但在实际应用中,预剪枝的表现并不是很好。所以,目前我们基本都是使用后剪枝方法。

预剪枝依据

  • 作为叶结点或作为根结点需要含的最少样本个数
  • 决策树的层数
  • 结点的经验熵小于某个阈值才停止

后剪枝:就是在决策树构造完成后进行剪枝。剪枝的过程是对拥有相同父节点的一组节点进行检查,如果将其合并,熵增小于某一阈值,那么这一组节点可以合并一个节点。如果将其合并后熵增大于这个阈值,那么说明将其分枝是合理的。后剪枝就是删除一些子树,然后用其叶节点代替。这个叶节点代表的子集不一定都是“纯”的。那么,这个叶子节点所标识的类别通过大多数原则确定。大多数原则就是指这个叶节点所代表的子集中大多数的类别来表示这个叶节点。剪枝的过程是对拥有同样父节点的一组节点进行检查,判断如果将其合并,熵的增加量是否小于某一阈值。如果确实小,则这一组节点可以合并一个节点,其中包含了所有可能的结果。后剪枝是目前最普遍的做法。

常用的后剪枝算法有五种,REP、PEP、MEP、CCP算法和后规则修剪方法。如果训练数据较少,PEP算法表现出良好的预测精度,随着数据规模的增大,使用REP和CCP剪枝方法得到的决策树的分类性能和预测精度明显提高。详解以下常用的三种:

Reduced-Error Pruning(REP,错误率降低剪枝)

这个思路很直接,完全的决策树不是过度拟合么,我再搞一个测试数据集来纠正它。REP方法是通过一个新的验证集来纠正树的过拟合问题。对于完全决策树中的每一个非叶子节点的子树,我们将它替换成一个叶子节点,该叶子节点的类别我们用子树所覆盖训练样本中存在最多的那个类来代替(大多数原则来确定),这样就产生了一个新的相对简化决策树,然后比较这两个决策树在验证集中的表,如果新的决策树在验证集中的正确率较高(测试数据集中的错误比较少),那么该子树就可以替换成叶子节点,从而达到决策树剪枝的目的。该算法是从下往上依次遍历所有的子树,直至没有任何子树可以替换使得在验证集上的表现得以改进时,算法就可以终止。

假设上图是我们生成的决策树,我们要对其进行剪枝,使用REP算法。

  1. 将节点4删掉替换成8和9,测试在验证集上的表现,若表现更好,则将节点4删掉并替换成8和9的并集,若表现不好则保留原树的形状
  2. 将节点2删掉替换成8、9和5,测试在验证集上的表现
  3. 将节点3删掉替换成6和7,测试在验证集上的表现

REP剪枝方法决定是否修剪这个结点步骤如下:

  1. 删除以此结点为根的子树
  2. 使其成为叶子结点
  3. 赋予该结点关联的训练数据的最常见分类
  4. 当修剪后的树对于验证集合的性能不会比原来的树差时,才真正删除该结点

REP是最简单的后剪枝方法之一,不过在数据量比较少的情况下,REP方法趋于过拟合而较少使用。这是因为训练数据集合中的特性在剪枝过程中被忽略,所以在验证数据集合比训练数据集合小的多时,要注意这个问题。由于验证集合没有参与决策树的创建,所以用REP剪枝后的决策树对于测试样例的偏差要好很多,能够解决一定程度的过拟合问题。

Pessimistic Error Pruning(PEP,悲观剪枝):

上文的REP方法思想简单且易于使用,不过最大的问题在于它需要一个新的验证集来修正我们的决策树。PEP方法也是根据剪枝前后的错误率来决定是否剪枝,和REP不同之处在于:PEP不需要新的验证集,而是完全使用训练数据来生成决策树,又用这些训练数据来完成剪枝,并且PEP是自上而下剪枝的。将该结点的某子节点不需要被剪枝时被剪掉;另外PEP方法会有剪枝失败的情况出现。由于我们还是用生成决策树时相同的训练样本,那么对于每个节点剪枝后的错分率一定是会上升的,因此在计算错分率时需要加一个惩罚因子0.5。PEP后剪枝技术是由大师Quinlan提出的。它不需要像REP(错误率降低修剪)样,需要用部分样本作为测试数据,。决策树生成和剪枝都使用训练集, 所以会产生错分。

PEP剪枝算法是在C4.5决策树算法中提出的, 把一颗子树(具有多个叶子节点)用一个叶子节点来替代,比起REP剪枝法,它不需要一个单独的测试数据集。PEP算法是唯一使用Top-Down剪枝策略,这种策略会导致与先剪枝出现同样的问题,虽然PEP方法存在一些局限性,但是在实际应用中表现出了较高的精度,。两外PEP方法不需要分离训练集合和验证集合,对于数据量比较少的情况比较有利。再者其剪枝策略比其它方法相比效率更高,速度更快。因为在剪枝过程中,树中的每颗子树最多需要访问一次,在最坏的情况下,它的计算时间复杂度也只和非剪枝树的非叶子节点数目成线性关系。

Cost-Complexity Pruning(CCP、代价复杂度):

代价复杂度选择节点表面误差率增益值最小的非叶子节点,删除该非叶子节点的左右子节点,若有多个非叶子节点的表面误差率增益值相同小,则选择非叶子节点中子节点数最多的非叶子节点进行剪枝。CART就是采用CCP(代价复杂度)剪枝方法,CART剪枝分为剪枝成子树序列,并通过交叉验证选取最优子树。也就是说,CART树的剪枝算法可以概括为两步,第一步是从原始决策树生成各种剪枝效果的决策树,第二步是用交叉验证来检验剪枝后的预测能力,选择泛化预测能力最好的剪枝后的数作为最终的CART树。

CCP算法为子树Tt定义了代价和复杂度,以及一个衡量代价与复杂度之间关系的参数α。代价指的是在剪枝过程中因子树Tt被叶节点替代而增加的错分样本,复杂度表示剪枝后子树Tt减少的叶结点数,α则表示剪枝后树的复杂度降低程度与代价间的关系,表面误差率增益值定义为:

其中,R(t)表示节点t的错误代价,R(t)=r(t)∗p(t);r(t)表示节点t的错分样本率,p(t)表示节点t中样本占全部样本的比例, N 表示子树T​t中的叶节点数。

从原始决策树生成各种剪枝效果的决策树的具体步骤:

  1. 令决策树的非叶子节点为{T1,T2,T3,……,Tn}
  2. 计算所有非叶子节点的表面误差率增益值α={α1,α2,α3,……,αn}
  3. 选择表面误差率增益值αi最小的非叶子节点Ti(若多个非叶子节点具有相同小的表面误差率增益值,选择节点数最多的非叶子节点)
  4. 对Ti进行剪枝

决策树算法总结:

决策树学习的关键就是如何选择最优划分属性。三种算法主要区别:CART构建的一定是二叉树,ID3,C4.5构建的不一定是二叉树。分类树是基于概率来构建的,采用信息增益、信息增益率、基尼系数来作为树的评价指标。回归数是基于平均值来构建的,采用均方差作为树的评价指标。

算法 支持模型 树结构 特征选择 连续值处理 缺失值处理 剪枝
ID3 分类 多叉树 信息增益 不支持 不支持 不支持
C4.5 分类 多叉树 信息增益比 支持 支持 支持
CART 分类,回归 二叉树 基尼系数,均方差 支持 支持 支持

决策树优化策略:

  1. 决策树欠拟合:没有将不同的数据类别划分开,原因:决策树深度太浅导致。解决方案:1.增加树的深度。2.使用集成算法,Boosting算法(GBDT)
  2. 决策树过拟合:学习能力太强,将噪音数据特征也学习到数据分割中了,原因:决策树深度太深导致。解决方案:1.剪枝(调整API中的参数)2.使用集成算法:Bagging算法(随机森林)

决策树算法的优点:

  1. 简单直观,易于理解和解释,可以可视化分析,容易提取出规则
  2. 基本不需要预处理,不需要提前归一化,处理缺失值
  3. 既可以处理离散值也可以处理连续值。很多算法只是专注于离散值或者连续值
  4. 能够处理不相关的特征
  5. 可以处理多维度输出的分类问题。
  6. 可以交叉验证的剪枝来选择模型,从而提高泛化能力。
  7. 对于异常点的容错能力好,健壮性高。
  8. 测试数据集时,运行速度比较快,在相对短的时间内能够对大型数据源做出可行且效果良好的结果。

决策树算法的缺点:

  1. 决策树算法非常容易过拟合,导致泛化能力不强。可以通过设置节点最少样本数量和限制决策树深度来改进。
  2. 决策树会因为样本发生一点点的改动,就会导致树结构的剧烈改变。这个可以通过集成学习之类的方法解决。
  3. 寻找最优的决策树是一个NP难的问题,我们一般是通过启发式方法,容易陷入局部最优。可以通过集成学习之类的方法来改善
  4. 如果某些特征的样本比例过大,生成决策树容易偏向于这些特征。这个可以通过调节样本权重来改善。
  5. 决策树容易忽略数据集中属性的相互关联

其他实例

实例1

我们今天是否去打网球(play)主要由天气(outlook)、温度(temperature)、湿度(humidity)、是否有风(windy)来确定。样本中共14条数据。

NO. Outlook temperature humidity windy play
1 sunny hot high FALSE no
2 sunny hot high TRUE no
3 overcast hot high FALSE yes
4 rainy mild high FALSE yes
5 rainy cool normal FALSE yes
6 rainy cool normal TRUE no
7 overcast cool normal TRUE yes
8 sunny mild high FALSE no
9 sunny cool normal FALSE yes
10 rainy mild normal FALSE yes
11 sunny mild normal TRUE yes
12 overcast mild high TRUE yes
13 overcast hot normal FALSE yes
14 rainy mild high TRUE no
ID3

ID3算法是使用信息增益来选择特征的。

信息增益的计算方法

信息增益的计算方法如下:

  1. 计算数据集D的经验熵

    其中 D 是数据集中所有样本个数,k是目标变量的类别数, Ck 是该分类下的样本个数。
  2. 遍历所有特征,对于特征A:

    计算特征A对数据集D的经验条件熵H(D A)
    计算特征A的信息增益g(D,A)=H(D)-H(D A)

    选择信息增益最大的特征作为当前分裂特征。

计算是否打球的经验熵
在本例子中,目标变量D就是play是否打球,即yes打球和no不打球。 D =14。K就是目标变量play是否打球的分类数,有两类yes打球和no不打球。yes打球这个分类下有9个样本,而no不打球这个分类下有5个样本,所以信息熵H(D)=H(play)=-((9/14)log(9/14)+(5/14)log(5/14))= 0.651756561173

注意本文中log(x)均按照以e为底的。

计算outlook天气特征的信息增益

计算outlook天气特征对数据集D的经验条件熵为:

其中 D 是数据集中所有样本个数,j是当前特征的不同取值个数, Dj 是第j个取值的样本个数, H(Dj)是该取值的样本的基于目标变量的信息熵。

具体计算如下:

特征A(天气)有三个不同的取值{sunny、overcast、rainy},即v=3,根据特征A(天气)的取值,将数据集D划分为三个子集:

其中sunny的子集中有5个样本,2个打球(play=yes),3个不打球(play=no);

Overcast的子集中有4个样本,都为打球(play=yes)

Rainy的子集中有5个样本,3个打球(play=yes),2个不打球(play=no)。

每个子集可以分别计算熵,具体公式如下

H(D|A)=H(play|outlook)=(5/14)sunny熵 + (4/14)overcast熵+ (5/14)rainy熵
      =(5/14)(-(2/5)log(2/5)-(3/5)log(3/5)) + (4/14)(-(4/4)log(4/4)) + (5/14)(-(3/5)log(3/5)-(2/5)log(2/5))
	  = 0.480722619292

所以天气特征的信息增益为:

g(D,A)=g(D,outlook)=H(D)-H(D|A)= 0.17103394188

计算temperature温度特征的信息增益

计算temperature特征的经验条件熵。特征A(temperature温度)有三个不同的取值{hot,mild,cool},则v=3。根据特征的取值,将数据集D划分为三个子集:

其中hot的子集中有4个样本,2个打球(play=yes),2个不打球(play=no);

Mild的子集中有个6样本,4个打球(play=yes),2个不打球(play=no);

Cool的子集中有4个样本,3个打球(play=yes),1个不打球(play=no)。具体公式如下:

H(D|A)=H(play|temperature)
      =(4/14)hot熵+(6/14)*mild熵+(4/14)*cool熵
	  =(4/14)(-(2/4)log(2/4)-(2/4)log(2/4)) + (6/14)(-(4/6)log(4/6)-(2/6)log(2/6)) + (4/14)(-(3/4)log(3/4)-(1/4)log(1/4))
	  = 0.631501022177

所以temperature温度特征对应的信息增益为

g(D,A)=g(D,temperature)=H(D)-H(D|A)= 0.0202555389952

计算humidity湿度特征的信息增益

计算humidity湿度特征的经验条件熵。特征A(humidity)有两个不同的取值{high,normal},v=2。根据特征的取值将数据集D划分为两个子集:

其中high的子集,有7个样本,3个打球(play=yes),4个不打球(play=no);

Normal的子集,有7个样本,6个打球(play=yes),1个不打球(play=no)。每个子集可以分别计算熵,具体公式如下:

H(D|A)=H(play|humidity)=(7/14)high熵+(7/14)normal熵
      =(7/14)(-(3/7)log(3/7)-(4/7)log(4/7)) + (7/14)(-(6/7)log(6/7)-(1/7)log(1/7))
	  =0.546512211494

所以特征humidity湿度的信息增益为:

g(D,A)= g(D,humidity)=H(D)-H(D|A)= 0.105244349678

计算windy是否刮风的信息增益

计算windy是否刮风特征的经验条件熵。特征A(windy)有两个不同的取值{TRUE,FALSE},v=2。根据特征的取值将数据集D划分为两个子集:

其中TRUE的子集,有6个样本,2个打球(play=yes),4个不打球(play=no);

FALSE的子集,有8个样本,6个打球(play=yes),2个不打球(play=no)。每个子集可以分别计算熵,具体公式如下:

H(D|A)=H(play|humidity)
      =(6/14)TRUE熵+(8/14)FALSE熵
	  =(6/14)(-(2/6)log(2/6)-(4/6)log(4/6)) + (8/14)(-(6/8)log(6/8)-(2/8)log(2/8)) 
	  =0.594126154766

所以特征humidity湿度的信息增益为:

g(D,A)=g(D,windy)=H(D)-H(D|A)= 0.057630406407

确定root节点

对比上面四个特征的信息增益,

g(D,A)=g(D,outlook) = 0.17103394188

g(D,A)=g(D,temperature) = 0.0202555389952

g(D,A)= g(D,humidity) = 0.105244349678

g(D,A)=g(D,windy) = 0.057630406407

可以看出outlook的信息增益最大,所以选择outlook作为决策树的根节点。

特征A(天气)有三个不同的取值{sunny、overcast、rainy},即v=3,根据特征A(天气)的取值,将数据集D划分为三个子集:

其中sunny的子集中有5个样本,2个打球(play=yes),3个不打球(play=no);

Overcast的子集中有4个样本,都为打球(play=yes)

Rainy的子集中有5个样本,3个打球(play=yes),2个不打球(play=no)。

每个子集可以分别计算熵。

sunny熵= -(2/5)log(2/5)-(3/5)log(3/5)>0

overcast熵=-(4/4)*log(4/4)=0

rainy熵=-(3/5)log(3/5)-(2/5)log(2/5)>0

上面overcast熵=0,也就是这部分已经分好类了,都为打球,所以直接就可以作为叶子节点了,不需要再进行分类了。

而sunny熵、rainy熵都大于0,还需要按照上面根节点选方式继续选择特征。

计算outlook为sunny的数据集
No. Outlook天气 temperature温度 humidity湿度 windy是否有风 play
1 sunny hot high FALSE no
2 sunny hot high TRUE no
8 sunny mild high FALSE no
9 sunny cool normal FALSE yes
11 sunny mild normal TRUE yes
  1. 计算outlook这个分支样本的信息熵 yes打球这个分类下有2个样本,而no不打球这个分类下有3个样本, 所以信息熵
H(D)=H(play)
    =-((2/5)log(2/5)+(3/5)log(3/5))
	=0.673011667009

注意本文中log(x)均按照以e为底的。

  1. 计算temperature特征的信息增益

    计算temperature特征的经验条件熵。特征A(temperature温度)有三个不同的取值{hot,mild,cool},则v=3。根据特征的取值,将数据集D划分为三个子集:

    其中hot的子集中有2个样本, 2个不打球(play=no);

    Mild的子集中有个2样本,1个打球(play=yes),1个不打球(play=no);

    Cool的子集中有1个样本,1个打球(play=yes)。具体公式如下:

     H(D|A)=H(play|temperature)
           =(2/5)hot熵+(2/5)*mild熵+(1/5)*cool熵
         =(2/5)(-(2/2)log(2/2)) + (2/5)(-(1/2)log(1/2)-(1/2)log(1/2)) + (1/5)(-(1/1)log(1/1))
         =-(2/5)log(1/2)
         =0.277258872224
    

    所以temperature温度特征对应的信息增益为g(D,A)=g(D,temperature)=H(D)-H(D|A)= 0.395752794785

  2. 计算humidity湿度特征的信息增益

    计算humidity湿度特征的经验条件熵。特征A(humidity)有两个不同的取值{high,normal},v=2。根据特征的取值将数据集D划分为两个子集:

    其中high的子集,有3个样本, 3个不打球(play=no);

    Normal的子集,有2个样本,2个打球(play=yes)。每个子集可以分别计算熵,具体公式如下:

    H(D|A)=H(play|humidity)
          =(3/5)high熵+(2/5)normal熵
        =(3/5)(-(3/3)log(3/3)) + (2/5)(-(2/2)*log(2/2))
        =0
    

    所以特征humidity湿度的信息增益为:g(D,A)= g(D,humidity)=H(D)-H(D|A)= 0.673011667009

    湿度特征划分,已经将信息熵将为0,所以我感觉就不用继续计算了,直接把湿度作为分裂的特征即可。

参考网址

https://www.cnblogs.com/bonheur/p/12469858.html

目录