决策树算法

本文介绍了数据挖掘中重要的决策树算法,包括C4.5和CART。这两种算法因其计算简单且结果易理解而被广泛使用。文章详细阐述了决策树的工作原理,如信息增益、信息增益率和基尼指数等评价标准,以及剪枝策略,如预剪枝和后剪枝。此外,还对比了C4.5与CART的区别,CART采用二叉树结构和基尼指数来构建决策树,并利用验证集进行剪枝。

在Journal of knowledge and Information Systems,  2007 上出现过一篇文章。 “Top 10 algorithms in Data Mining”。 其中这篇文章列出了数据挖掘中最常用的10大算法, 分别是: C4.5, K-means, SVM, Apriori, Expectation Maximization, PageRank, Adaboost, KNN(K近邻), Naive Bayes, and CART。 值得注意的是, 这十大算法中有两大算法属于决策树算法(Decision Tree), 分别是C4.5和CART。 这也是为啥从决策树算法讲起。  

决策树可以用于分类, 预测等任务。 有很多的决策树算法。 不光有适合离散的属性值, 同时也适用于连续的值的分类(例如CART(classification and regression tree)算法)。 

例如如下例子, 一个餐馆已经满员了, 这时一个新的客人过来吃饭, 他是否会在餐馆内等待别人吃完空出位置这件事情采集到的样本:


下面是根据上述12个样本而建的一个决策树(注意可能不唯一)如下:


决策树算法的优点: 计算简单,  最终得到分类结果的过程可以被人直观的理解。 即使数据集中有的样本有missing values 也是okay的, 决策树一概可以做。

缺点: 就是容易过拟合。 但是, 我们可以通过修剪(pruning)的办法去避免过拟合(overfitting)。主要有两种办法:

(1) pre-pruning(前期剪枝): 也就是在我们的决策树完美拟合训练样本集之前, 就通过某种度量去阻止进一步的grow我们的tree。 ID3采用的就是这种办法。

(2) post-pruing(后期剪枝):  第一步就是建一个能够完美拟合我们的训练样本集(即允许树过拟合数据)。 然后进行后期剪枝, 得到具有较好的泛化能力的决策树. C4.5和CART采用的是这个办法。

说白了, 剪枝就是regularization(规则化)的一种特殊形式。

一. ID3

ID3和CART大约在同时被独立的发明于20世纪80年代。 ID3算法虽然没有被列入十大数据挖掘的十大算法, 但是其后来的改进版本(或者说是后继)C4.5 却被荣幸的列入数据挖掘十大算法。  ID3和C4.5决策树算法均是Quinlan 发明的。 所以在介绍C4.5之前, 有必要介绍一下C4.5的祖先ID3。

基本的ID3算法是通过自顶向下的, 贪心的搜索出给定的数据集的最佳分裂属性, 来构造决策树进行学习的。  树的每一个节点都是当前看起来是最佳的 分裂到达这个节点的样本集的属性。 那么问题来了, 判断最佳属性的度量标准是什么呢? 下面, 我们定义一个叫做信息增益(information gain)的统计属性, 用来衡量给定的属性去分开训练样本集的能力。 ID3在增长树的每一步都是使用这个信息增益来贪心的从候选属性集中选择当前看来是最佳的分裂属性。  ID3决策树的修剪是易于奥坎姆剃刀原理(Occam's razor), 具体的, ID3算法前期剪枝的策略是是(1)优先选择较短的树而不是较长的树去grow。(2)选择那些信息增益高的属性距离根节点较近的树, 即那些信息增益高的属性更靠近根节点的树优先。奥卡姆剃刀认为优先选择拟合数据的最简单的假设, 因为这个假设具有更高的泛化能力。 

(1)信息增益(information)的定义

信息的度量是用entropy(熵)去计算的。

对于一个离散具有J维的概率分布如下:

                                             

则这个分布的entropy的计算公式如下:

 

从公式不难看出, 随着向量P的某一维度概率趋近于1, 或者说某个事件发生的概率趋近为1, 那么对应的这个分布的信息熵也变成了0, 也就是毫无信息了。 这就是我们想要达到的状态。 我们就是要将数据中的信息降下来, 变成看起来确定的结果。 注意, 在数据挖掘中, 我们是讨厌不确定性。 理想的状态是把不确定的变成确定的。

为了进一步的了解信息熵, 下面举一个例子。

ex1: 如果给定的二维分布(对应着分类任务中的类标号C1, C2): P = [1/2, 1/2], 则这个二维分布的信息熵为: H[p, 1-p] = -p log(p) - (1-p) log(1-p):

即信息为1 bit。

   ex2: 给定P = [0.99, 0.1], 则这个分布的信息增益为:


信息量变小了。 也就是我们以概率为0.99的确定的信心相信C1的发生。 所以信息量当然变小了。

有了上述概念后, 我们来看看信息增益:

给定了我们数据集之后, 我们需要根据数据集在属性集上一个一个属性的测试, 选出具有最大信息增益的属性A作为当前决策树节点的的分裂属性。

例如, 如下的数据集S在属性A上的分裂情况如下:


我们假设数据集S具有#pos个positive的样本, #neg个negative的样本。 在属性集上分裂情况如上。 我们假设branch j具有 #pos_j个positives和 #neg_j个negative个negatives。

那么branch j的训练分布的概率为:


那么, 属性集S在属性A上的信息增益(information gain)的计算如下:


回到上述的饭店那个例子。 

当我们分别选择(测试)Patrons, Type 作为分裂属性, 得到如下两个分裂的结果图:


对应的信息增益分别如下:


不难看出, 选择Patrons作为分裂属性的信息增益最大(是的上一个节点的信息降低), 所以属性Patrons的分裂能力远远大于Type属性的分裂能力。

 (2) 信息增益率(Gain Ratio)

使用信息增益作为判断一个属性的分裂能力有失公允。 因为她倾向于能够产生多个分支的属性。 例如, 一个极端的例子, 选择的一个属性(比如, 因为错误的原因 , 选择样本的编号1, 2, 3)作为分裂属性, 每个branch都有一个样本, 如下:

我们在计算样本集在属性A上的信息的时候, 得到如下:

于是我们的算法就选择了属性A作为最佳分裂属性。 显然是错误的。

如何避免呢?? 答案就是采用信息增益率(Gain Ratio)。 定义如下:

其中SplitInfo的定义如下:


该值代表训练数据集S在属性A上测试的J个输出的J个分区产生的信息。 我们希望SplitInfo越小越小, 也就是希望∑里面的每一项越大越好。 即我们希望S_j 越大越好。 换句话说, 我们选择的属性是使得每一个分区尽可能有更多的样本。

我们选择信息增益率最大的属性作为最佳分裂属性。  

ID3选择信息增益作为分裂能力度量, 而C4.5选择的是信息增益率作为分裂能力的度量。 但是现在这个界限变得blur了。 毕竟ID3也可以选择信息增益率作为分裂能力的度量啊。 有了C4.5, 还有谁会选择ID3呢。 毕竟ID3只能在教学的时候为了引入C4.5而做的一个铺垫啊。


就这样, 我们根据信息增益的标准(或者使用信息增益率), 递归的对数据集进行分裂。 每一次都重复前面的过程的选择一个新的属性来分割训练样本子集。 已经被树的高的节点测试的属性被排除在外, 以便保证给定的任何属性在树的任意路径上最多仅出现一次。 对于每一个新的叶子节点继续分裂过程, 直至满足下面两个条件的任何一个, 即终止继续分裂:

(1) 所有的属性已经被这条路径包括

(2) 到达这个节点的所有的训练样本都有相同的label。 即每一次分裂开始前(包括最开始的根节点), 我们都会计算当前的训练样本集的信息熵, 这个信息熵为0, 就意味着所有的训练样本都有相同的label。

ID3的算法的伪代码如下:C 表示类标号, 离散的。 S表示训练样本集。 R表示属性集(当然也是离散的)。


    

但是, ID3 算法有很多的局限性,例如:

(1) 无法确定树的增长的深度

(2)无法处理取值连续的属性

(3) 使用信息增益作为属性的选择标准时容易偏向于分支较多的属性。

正是因为ID3的这些局限性, 造成了C4.5---这个ID3的升级版 被发明的motivation。


二. C4.5

ID3的升级版, 即C4.5, 在ID3的基础上, 做了如下修改:

(1)使用信息增益率作为选择最佳分裂属性。

(2)利用C4.5建造一棵决策树, 伪代码如下:


关于C4.5中的剪枝。

C4.5算法先创建好一个决策树, 然后开始剪枝操作。 C4.5算法采用的是一种称为悲观剪枝的方法。  因为它使用训练集错误率, 对子树剪枝做出决策。 由于训练集

评估的正确率或者错误率过于乐观, 所以具有较大的偏差。 所以悲观剪枝方法通过加上一个惩罚来调节从训练集上得到的错误率, 以抵消出现的偏差。 也就是说, 使用训练集去生成决策树, 又使用训练集进行剪枝。

对于建造得到的决策树, C4.5递归的去判断是否应该在一个属性上进行prue, 有如下三种选择。

选择一: 不管这棵树

选择二: 用一个叶子节点去替换掉树的一部分。 对于到达这个叶子节点的训练样本的采用majority vote的机制作为其label。

通过剪枝后, 我们的树变得更加的紧凑。

C4.5通过计算上述两种选择造成的错误率概率的上界判断执行哪一个选择。 当然是选择错误率上界小的那一个选择。 

定义如下:

错误率上界的计算公式如下:


C4.5的默认的参数a为4.5。上述公式的p代表上界。

例如, 如下的一个split为:


下面, 我们首先计算p_0.25, 对应的值分别是0.206, 0.143, 0.75。 对应每个分支(从左到右)。 计算公式为:

(1-p)^6 = 0.25(其中N = 6, M = 0)

(1 - p)^9 = 0.25(N = 9, M = 0)

(1 - p) = 0.25 (N = 1, M = 0)

选择一得到的这棵树的概率上界是:


选择二得到的计算上界的过程为:

N = 6 + 9 + 1 = 16 examples

M = 1

所以:

(1 - p)^16 + 16 p * (1 - p)^15 = 0.25

得到p = 0.157。 

所以上界为:


由于选择二的错误概率上界变小了, 所以我们使用叶子节点替换掉这一部分。


三. CART 

   深入的理解CART树是值得的。 毕竟十大算法中也有CART的一席之地呀。

     CART算法全称Classification and Regression Trees。 CART算法的一个特点就是每一次是选择的是Binary split, 而不是Multiway split。  也就是说, CART生成的决策树是一棵二叉树。 CART使用的分割标准不同于C4.5和ID3, 而是采用的是基尼指数(Gini Index)。

CART算法有两个关键的思想:

(1)对于独立的属性变量空间进行递归的分割(recursive partition)

(2)使用验证集(validation set)进行树的剪枝(pruning)。

基尼指数是度量在训练数据集的不纯度的, 定义如下:

给定样本集A, 我们用C代表类, 其中k = 1, 2, 3, ...C。 其中C是总的类的个数。

那么样本集的不纯度(基尼指数)为:


其中p_k表示样本集中类k所占的比重。 

不难看出, 如果I(A) = 0表示样本集A中的样本均属于同一类。 当A中的样本已均匀的比例属于这K个类, 表示基尼指数最大。 最大值为 (C - 1) / C。

为了详细的理解CART, 下面我们举一个例子。

 假设预测的label 变量为y, (相互)独立的属性变量为x1, x2, x3, ..., xp。 递归的分割就是将这个p维的X空间化分成不重叠的矩形。 划分的过程是递归的进行的。 步骤如下:

(1)首先选择一个变量xi,  变量xi的一个值si(这个值能够使得分割后的样本集具有最小的不纯度), 被选定作为划分p维空间的超平面。 即把样本集分成了xi > si和 xi <= si 两部分了, 然后对两部分分别选择一个变量xj(也可能还是xi变量)和对应的值sj按照相同的方式, 划分两个子部分。 最终, 我们得到越来越小的矩形, 小矩形里面的数据也越来越纯了(度量纯度的变量是基尼指数)。  当然完全纯也可能无法达到, 因为有时候两个数据样本的属性值完全一样, 但是类标号却不同。但是我们起码要达到尽可能的纯。

(2)进行剪枝。

剪枝时CART树的第二个关键思想。 CART树使用的是验证集(validation set)去对用训练样本集grow出来的决策树进行剪枝。 这是一个创新之处。 还记得吗, CART和ID3均发明于80年代。  在此之前(80年代以前), 避免生成的树过拟合的办法就是采用CHAID(使用chi-square test的统计学测试)去避免树过度的grow。 然而CART使用验证集, 是一个很大的创新。

CART第一步的最后几次分割的时候, 其实基本上矩形中也没有多少样本点了。 所以我们可以直觉上认为最后几步只是捕捉到训练样本集中的噪声, 毫无意义。修剪的具体操作就是连续的选择一个决策节点(decision node), 然后把这个节点定义为叶子节点, 所以把这个节点的子树就被砍掉了。 修剪的过程是决策树对于validation set上的missclassification error和修剪后树的decision nodes(不是叶子节点)的个数的trade off。 这样, 我们期望我们修剪后得到的树能够真正的捕捉到数据中的pattern了。  

修剪过程使用了一个被称为cost complexity(代价复杂度)的树的准侧。 CART利用这个准侧连续产生一系列的大小的树,直至只产生只有根节点的树(只有一个根节点的树的分类规则是多数投票机制产生的类标号作为预测新的样本(验证集中)的类)。 最后, 我们从这个树的序列中选择一棵在验证集上具有最小分类误差的树输出即可, 这就是我们最终得到的CART。 这棵在验证集上具有最小分类误差的树被称为“The minimum error Tree”(最小误差数)。

CART算法使用的cost complexity就是 决策树在在验证集上产生的分类误差 加上 一个对树的size的惩罚项。  惩罚系数记为a。 代价复杂准则公式为:


其中, Err(T)表示树T在验证集上的分类误差, L(T)表示树T的叶子节点的数目。 

特别的, a = 0, 表示不对树的size进行惩罚, 这样我们得到的一棵树是unpruned tree。

我们从0开始一直增大a到很大的值的时候, 即最终a很大的时候, 得到的最佳的树就是只有单个节点(根节点)的树了。 最终我们得到一组size逐渐递减的至只有一个节点的一系列树, 然后从这些树中选择一个在验证集上具有最小的分类误差的那棵树即可, 这棵树被称为最小误差树。

举个例子:

一个riding mower(割草机) 的制作商要对一个城市的那些家庭需要riding mower进行归类。 收集到如下24个样本集。

 

散点图如下:


如果我们选择CART算法,那么就需要找打那个能够产生最小的不纯度的分割的变量和其对应的值了。

我们需要计算出每一个变量(x1, x2)所有可能的分裂的值(取中点值, 我们采用的办法就是先对x1相应的值排序, 然后取出相邻样本的x1的中点值)如下:


让后计算每一个I(A)的不纯度, 选出具有最小的不纯度对应的变量和变量值。 

不难看出, 应该选择x2 = 19:


同理, in the same manner, 递归进行分割, 最终产生如下图:


我们得到如下对应的CART树:


不难看出, 按照这种方式生成的CART是一个这样一棵二叉树, 即叶子节点数目 = 决策节点数目 + 1。 上图中叶子接节点里标记的百分数对应着训练集中到达该节点的百分比。

按照上述算法训练, tree grow的过程中, 过程中, 训练误差如下:


接下来进入修剪过程:

按照修剪方法, a从0逐渐增大, 得到如下的测试log:


不难看出, 随着决策节点数量的降低, 在验证数据集上的误差也有下降的趋势, 直至14.85%, 此时树的大小为10个节点。 然后误差开始上升, 我们选择具有最小误差对应的最小节点数的树作为我们的Minimum error tree。 



但是, 最佳的修剪后的到的树却是5个节点, 为什么?? 因为其实最小误差也是一个随机量。这个随机量的标准差定义为:


其中Emin表示最小误差, Nval表示验证样本集的大小。 Emin = 0.1485, Nval = 202, 所以标准差为0.025。 所以最佳修剪得到的树的决策节点只有5个, 对应的树如下:






   




 

  



评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值