作者:Naren Ramakrishnan
Contents
1.1 简介
C4.5[30]是机器学习和数据挖掘领域解决分类问题的一”套“算法。用来做有监督学习:给定一个属性值数据集,每个样本都是一系列属性值和所属类别,C4.5学习从属性值到类别标记的映射关系,用来对新的、没有见过的样本做分类。例如,见Figure1.1,每一行表示某一天,属性值是指当天的天气情况,类别是指当天天气情况是否适合打高尔夫。因而,每一行表示一个样本,包含几个不同属性:天气概况outlook(值域范围包含三个值)、温度temperature(连续值)、湿度humidity(同样连续值)、是否有风windy(二值变量)和一个二值类别”可以打高尔夫?play golf“。Figure1.1中的所有数据构成了训练数据,我们的目的就是利用这些数据学习得到所需的映射关系,并利用这个学习结果对其他新样本做分类:给出属性值(天气情况)来判断类别(是否适合打高尔夫)。
Figure1.1 C4.5的输入数据集示例
C4.5,由J.Ross Quinlan构建,之所以这样叫是因为它是树生成方法ID3的基础上而来,而ID3则是”iterative dichotomizers“的第3种实现方式。决策树是一系列系统安排好的问题,每个问题询问一项属性(比如天气概况),并且根据属性值进入不同分支。在树的叶节点上将给出对类别变量的预测(在这里是”适合打高尔夫吗?“)。所以决策树就好像汽车手册上给出的查找汽车问题所在的定位过程一样。除了决策树的角度,C4.5也可以被视为逻辑规则的一种组合形式。另外,C4.5支持的剪枝后的规则通常使所获得的分类器并不能直接以决策树形式来理解。
回顾C4.5的发展历程,我们可以研究不同社区在类似人类思维方式的分类方法上是如何达成一致的。ID3在原始的由Friedman提出的决策树算法基础上独立演化而来,后来随着Breiman、Olshen和Stone的加入又进化为CART。但是,从CART[30]的众多引用来看,C4.5中的潜在规则设计受到CART解决类似问题的思路影响,比如属性的特殊类型的处理步骤。(基于此,因为内容有重叠,我们会尽量减少与CART章节的重复,并指出相关部分的关键区别)。在[25]和[36]中,Quinlan也坦陈CLS(Concept Learning System[16])框架在ID3和C4.5发展中的影响。今天C4.5已被See5/C5.0系统取代,这是一款Rulequest Research公司提供的商业化产品。
十大算法中包含两个基于决策树的算法证实了这种方法在数据挖掘领域中的广泛使用和受欢迎程度。决策树方法最初应用在标称值和类别值的领域,但是今天已经扩展到数值型、符号型和混合型属性领域。比如临床决策制定、生产制造、文档分析、生物信息学、空间数据建模(地理信息系统),实际上任何类间的决策边界可以以树形分解或者可以以规则解析的领域都能够利用决策树。
——————————————————————————————————————————————————
1.2 算法描述
C4.5并不是一”件“算法而是一”套“算法——C4.5,C4.5-no-pruning和C4.5-rules。我们首先介绍基本的C4.5后面介绍特殊的C4.5。
C4.5的工作方式如Algorithm1.1所示。所有的决策树生成方法都是从一个根节点开始,它代表的是整个给定的数据集,然后在每个节点处测试某个属性不断将数据分割成小的子集。这些子树代表的是原始数据集中满足特定属性的部分。这个过程一直持续,直到子集是”纯净的“,也就是子集中的所有样本属于同一类别,此时树的生长也结束了。
Figure1.2 根据Figure1.1的数据集以C4.5方法获得的决策树
Figure1.1是高尔夫分类问题的数据集。就像前面提到的,我们的目的是要预测某一天的天气是否适合打高尔夫。请记住,有些特征值是连续变量,而有些是类别型变量。
Figure1.2实例的是用Figure1.1的数据作为训练数据获得的C4.5方法下的决策树(默认设置)。我们来看看树的生成过程中的一些选择。
- 什么样的test是可用的?如图1.2所示,C4.5并不局限于二值test,允许test结果有两个以上结果。如果属性是二值型,test将导入两个分支。如果属性是类别型,test是多值的,但是不同的值将进入到一个更小的规则配置集合中,每个规则配置都将有一个预测类别结果。如果属性是数值型,那test又将是二值型,具有{<=theta?, >theta?}的形式,其中theta是属性对应的合适的划分阈值。
- 如何选择test?C4.5使用信息论度量比如gain(应用test之后类别标签的熵的差)或者gain ritio(一种用来纠正gain度量倾向于多输出test的方法)。默认的度量是gain ratio。每次tree-growing的时候,都将选取具有最佳度量的test。
From 维基百科:关于gain与gain ratio
可以看到gain与gain ratio的区别在于gain ratio = gain / intrinsic value。多了一个intrinsic value意义在于纠正gain作为test的度量时
会出现的一个问题:
举一个客户系统的例子,如果要对一个客户信息数据分类,其中有一项属性是每个客户的信用卡号,由于这和每个客户是一一对
应的,可想而知,使用该属性的test必然获得最大的gain,因为对此属性分类后,每个子树对应的是唯一的一个样本,这显然不是
我们分类想要的结果,也不具有普适性。
而当按照信用卡号做test分类时,intrinsic value同样是极大的,这可以看做是各个类数量分布的熵,这样就有效地抑制了选择信用
卡号这样的test作为最佳test。
**************************************************************************************************************************************************************
- test阈值该如何选择?如前所述,对于二值型和类别型属性,test的值很简单,就是可能出现的那些值。而对于数值型属性,则是对属性所有值进行排序,然后选择连续值之间使所用度量最大的分割,从而获得阈值。Fayyad and Irani[10]证明并不是所有的连续两个值都需要考虑。对于连续型变量的两个连续值Vi和Vi+1,如果Vi对应的所有样本与Vi+1对应的所有样本同属于一类,那么在它们之间的分割不会改善gain或者gain ratio。
- tree-growing何时结束?当分支中的所有样本是纯净的或者说都属于同一类的时候,节点的这个新分支被作为叶节点不再向下生长。另一种结束tree-growing的方式是样本数量小于某个阈值,这可以视为为了保证普适性而放弃了部分hard examples。
- 如何给定叶节点的class标记?叶节点包含的样本中占大部分的class标记作为该叶节点的标记。
我们将详细地理清如何从Figure1.1上获得Figure1.2所示的决策树。观察下,outlook是如何选为第一个test的。我们首先估计下class变量(playGolf?)的熵。这个变量有两个可能取得的值,概率分别为9/14(yes)和5/14(no)。class变量取得c值的概率分布为P1,P2,...Pc时,它的熵有如下格式:
因此playGolf?的熵为
或者准确说是0.940。这意味着要在通信时传递playGolf?这个变量需要至少0.940bits。C4.5的目标就是要问一些合适的问题让熵减小。我们轮流评估每个属性带来的熵的下降量。对于给定的某个变量,比如outlook,熵的下降量,用Gain(outlook)表示,表示如下:
其中,v是可能取值的集合(本例中,outlook可以取3个值),D表示整个数据集,Dv是outlook取值为v的样本集合,而|*|表示数据集的大小(其中的样本数量)。
计算可得Gain(outlook)=0。940-0.694=0.246。类似地,我们可以计算得到Gain(Windy)=0.940-0.892=0.048.计算出所有其他属性的值以后可以看出outlook是分支的最佳属性。观察到这是一种贪心选择,没有将后续决策的影响考虑在内。如前所述,tree-growing一直进行直到标准(比如子数据集的纯净度)达到。在上面的例子中,outlook取值为Overcast的分支上是一个纯净的子集,也就是说outlook项取该值的所有样本的class标记都为yes;因此,树不再在这个方向上生长。然而其他两个值上仍然是非纯净子集。因而算法将被迭代,不同的test项目和分割将被获得。
前面我们提到默认的分割度量实际上是gain ration而是不是gain。为了理解差异,试想我们将Figure1.1中的Day作为一个实数特征。进一步,我们把它当做标称型属性。当然,每一天都是独一无二的,所以Day并不是一个值得用来分支的属性。然后,由于有14个截然不同的取值,每一个对应的子集都是纯净的(一个过于细碎的只包含一个样本的子集),Day将会很不公平地被选作分支的最佳属性。因为gain偏向于可以有大量取值的属性,Quinlan提出用gain ratio来消除这种影响。属性a的gain ratio计算如下:
观察下,entropy(a)并不依赖于class信息,只是关注于属性a可能取值的分布,而gain(a)则是将class信息包含在内。(另外,请记住这里的所有计算都是针对所用的数据集)。例如,GainRatio(outlook) = 0.246/1.577 = 0.156。类似地,其他属性的gain ratio可以计算得到。这里将其他属性的计算交给读者,请自行验证此时outlook是否还是最佳的分支属性。
讨论到此,应当指出决策树并不能以这种简单的方式为所有决策边界建模。例如,尽管它能模拟任何二值函数,最终的树可能是相当的复杂。比如在大量二值属性上建模XOR操作。在这种情况下每一条路径中都需要对所有属性做测试,这棵树的尺寸将会呈指数级规模。另一个难题是所谓的”m-of-n“函数,class只与n个属性中的m个有关,但是并不清楚是哪m个属性。倾斜决策树,将在后面介绍,能够克服这些缺陷。除了这些困难,C4.5生成的决策树还有一个问题是由于在属性选择时的贪心选择导致子树的重复。除了穷举搜索最佳属性来生长出一个完全决策树,这个问题通常别无他法。
——————————————————————————————————————————————————————————————————————————
1.3 C4.5的新特征
1.3.1 剪枝(Tree Pruning)
为了避免过拟合剪枝是很有必要的。理解这一点,Quinlan在[30]中给出了一个数据集,每个样本包含10个二值型属性,每一项属性为0或者1的概率是相等的。class标记也是二值型:yes概率为0.25,no概率为0.75。原始数据集中有1000个样本,500个用于训练,其余500个作为测试。Quinlan发现C4.5产生了一个包含119个节点(!很惊讶吧)错误率高于35%的树,而一个更简单的树却可以获得更高的准确率。因而剪枝对改善分类器在新样本上的准确率是至关重要的。通常在完全生长出一棵树后进行剪枝,以由底向上的方式进行。
Quinlan所作的1986 MIT AI lab memo[26]罗列了以往研究中剪枝中的多项选择。CART算法使用cost-complexity pruning,它会产生一系列的树,每一个都是在前一个的基础上用叶节点取代一个或者多个子树而来。最后一个树只包含一个单一叶节点,预测某一个类别。用cost-complexity作为度量来决定哪些子树应该被一个预测最佳类别标记的叶节点替代。之后每一个树都在单独的测试集上评估,并根据在测试集上的可靠性度量来选择最佳的树。
Reduced error pruning是这种方法的简化版。和之前一样,也是使用独立的测试集,不过它是直接用完全生长的决策树来对测试集中的样本做分类。对每一个非叶节点的子树,都会评估用最佳叶节点取代这个子树是不是更有利。如果剪枝之后的树能够获得比剪枝之前更低的错误率,同时这个子树中不包含具有同样性质的子树,那这个子树就要被取代了。我们一直这样做直到替代将会增加测试集上的错误率为止。
Pessimistic pruning是C4.5的一项创新,它不再需要独立的测试集。它是通过训练集中的错分类数量来估计错误率。这种方法迭代地计算每个节点下面的分支中错分类的概率来计算某个节点的错误率。对一个有N个样本、E个error(即,包含在该叶节点中但又不属于该叶节点的class标记的样本数量)的叶节点而言,pessimistic pruning首先计算它的经验错误率为(E+0.5)/N。对一个包含L个叶节点的子树,SUM(E)和SUM(N)分别为相应的error数量和L个叶节点中的样本数量,整个子树的错误率为( SUM(E) + 0.5*L )/SUM(N)。现在设想用它的最佳叶节点代替该子树后,整个训练数据集中被该子树错分类的数量为J。当(J+0.5)与( SUM(E) + 0.5*L )的差值为后者的标准差之内时,子树将被替代。
**********************************************************************************************************************************************************
这里为了获得SUM(E)+0.5*L的方差,我试想了两种方式:
1) 将训练集分为多个子集,在每个子集上测试得到对应的SUM(E)+0.5*L,据此计算得到方差;在整个训练集上计算得到
SUM(E)+0.5*L,然后作比较。
2) 在所有的子树上都要做此替代评估,每个子树都有对应的SUM(E)+0.5*L,据此计算得到方差;然后根据方差和当前子
树的SUM(E)+0.5*L作比较。
仔细想来,应当是按照第2)种方式来做更好。
***********************************************************************************************************************************************************
这种方式可以拓展到基于所需confidence intervals(CIs)的剪枝。我们可以模拟叶节点的错误率e为伯努利变量,对于给定的置信度阈值CI,可以计算得到置信度为1-CI的错误率上限emax(e<emax)。(C4.5使用默认CI为0.25。)我们还可以以正态分布(对于N很大的情况)估计e,这时C4.5决定的期望误差率的上限为
其中z是根据设定的CI按照标准正态分布,也就是N(0,1),计算得到的。
接下来的内容就是剪枝的具体细节了。由底向上是肯定的。看一下Figure1.3,这里描述的是剪枝处理的中间一环,因而T1、T2和T3子树上的剪枝已经完成。Figure1.3右侧所示的3种情况将分别进行错误率评估。第一种情况是保留原来的子树;第二种情况是只保留子树中最常出现的结果(图中保留中间的分支);第三种情况是替代为一个叶节点,它的class标记是训练数据集在该子树上的所有样本中最常出现的class标记。这些按照由底向上的方式进行直到树的根节点。
1.3.2 善用连续型属性
Quilan在[31]中提出处理连续型属性的更佳方式。这是由连续型属性相对于离散型所具有的优势而来的,他们可以有更多的可能的决策边界,这对离散型属性来说不是那么公平。当然,一种方式是用gain ratio来取代gain。然而,在此我们将面临一个难题:gain ratio也会受到连续型属性的分割阈值的影响。特别地,当阈值将所有样本几乎均分时,gain ratio是极小的(因为属性的熵是gain ratio的分母)。因此Quinlan提出仍然使用原来的gain来选择阈值,但是用gain ratio来选择最佳属性。另一种方法是基于Risannen的MDL(minimum description length)规则。 Quinlan还提出在树的复杂度和性能之间的tradeoff。这里复杂度的计算包含编码树的cost加上树的例外(即训练样本里树不能做分类的数量)。以往测试显示这种方法使得树并没有过度倾向于连续型属性。
1.3.3 处理缺失值
缺失的属性值在学习阶段和之后的新样本分类阶段都需要特殊处理。Quinlan[28]罗列了一系列需要考虑的相关问题。如下文所述,有三个主要问题:(i) 在选择最佳split的属性时,一些样本有缺失属性值,该如何选择一个合适的split属性?(ii) 在选定split的属性后,带有缺失值的训练样本没有这个test的任何输出结果。为了继续生长树,必须将样本分类下去。因此第二个问题是:在将数据集划分成子数据集的时候该如何处理这种样本?(iii) 最后,当树被用来做新样本的分类时,某个test的属性值正是该样本所缺失的,那该如何沿树向下处理呢?可以看到前两个问题发生在学习/生成树的阶段,而第三个问题发生在对新样本分类的阶段。可以预想到,每个问题都有几个可能的方法。在[28]中,Quinlan提出以上三个问题的多个选择,通过不同的组合可以得到处理缺失属性值的一个整体方案。Quinlan在[28]中提出了一个编程框架来设计一个处理缺失值的组合策略。
对于第一个问题,我们可以:(I) 忽视那些训练数据中没有该属性值的样本;(C) 用最常出现的值(对于二值型或者类别型属性)或者已知值的均值(对于数值型属性)来填补;(R) 根据样本中缺失该属性值的数量比例,降低该属性的gain/gain ratio;(S) 用训练数据填充缺失值。这种方式既可以用新的不同的值来填充,也可以根据其他已知属性值来推断的方法[28]。CART中的surrogate split可以视为最后一种思路的方法。
对于第二个将训练数据迭代分类来构建决策树,当某个节点以属性a做split同时有一个或多个样本缺失该属性值时,我们可以:(I) 忽视该样本; (C) 认为该样本的该属性值为该属性最常出现的值; (F) 按照子集中已有的样本比例将包含缺失值的样本分配到子集中;(A) 分配到所有子集中; (U) 为缺失属性a的样本开辟一个新的分支; (S) 推测最可能的属性a(如前所述,使用[28]中的方法)并据此将其分配到相应的子集中。在[28]中,Quinlan提供了(F)的一个变形方法,样本只被分配到一个子集中,并且也是等比于那个子集中已有样本数量。
最后,当对包含缺失属性a的样本进行分类时,选项如下:(U)如果有一个单独的针对未知a属性值的样本的分支,进入该分支;(C) 按照最常见的值对该样本分类;(S) 按照[28]中使用的方法推测出最可能的a属性值然后做分类;(F) 同时搜索所有的分支,给出不同输出的概率分布作为该样本的分类结果;或者(H)直接结束并分配给最常出现的class标记。
读者或许会觉得一些策略组合更顺理成章,而有些则说不通。对于按比例分配的选项,只要权重和为1,有一种统一形式的计算gain/gain ratio的方法。
1.3.4 产生的规则集合
C4.5的一个显著特征是在生成树上做的规则剪枝。我们可以将决策树理解为一个连续规则的集合模型,每一条规则对应的是树中从根节点到叶节点的一条路径。规则的前半部分是路径上的决策条件,后半部分是叶节点上的预测类别标签。对训练集中的每一个class标记,C4.5首先在(未剪枝)树中提取出规则。然后,对每一个规则,做hill-climbing search来检查这条规则是否可以被移除。因为移除一条规则和敲掉决策树中的节点很类似,所以这里使用了C4.5的pessimistic pruning方法。每一个class都获得了一个简化的规则子集。这里,使用minimum description length(MDL)规则来解析编码规则的cost并对潜在规则排序。最终的规则数量通常远小于原来的决策树里的叶节点(路径)的数量。同样可以看到,由于所有路径都被考虑移除,甚至接近树顶端的节点也可能被剪掉,所以最终的规则可能是无法解压为一颗完整的树的。C4.5规则集的一个缺陷是已知的,当数据集规模增大时规则集的学习时间将会急剧增长。
———————————————————————————————————————————————————————————————————————————
1.4 代码实现
J.Ross.Quinlan的源码在他的个人主页上可以获得:J.Ross.Quinlan。但是这是有版权的,只能获得作者的license之后用于商业。不过用于个人目的的话是可以使用的,这也帮助C4.5在该领域里成长为一种标准方法。还有很多公共的实现,例如Ronny Kohavi的MLC++ Libary,现在已经是SGI Mineset data mining suite 和 Weka data mining suite( Univ of Waikato, New Zealand,weka)的一部分。Weka中C4.5的Java实现称为J48。商业实现包括Intelligent Systems Research,LLC的ODBCMINE。