决策树
ID3,C4.5,CART,决策树的生成,剪枝。
一、概述
决策树(decision tree)是一种基本的分类与回归方法(这里是分类的决策树)。决策树模型呈树形结构,在分类问题中,表示基于特征对实例进行分类的过程。它可以认为是if-then规则的集合,也可以认为是定义在特征空间与类空间上的条件概率分布。其主要优点是模型具有可读性,分类速度快。学习时,利用训练数据,根据损失函数最小化的原则建立决策树模型。预测时,对新的数据利用决策树模型进行分类。决策树学习通常包括三个步骤:特征选择、决策树的生成和决策树的修剪。
用决策树分类,从根结点开始,对实例的某一特征进行测试,根据测试结果,将实例分配到其子结点;这时,每一个子结点对应着该特征的一个取值。如此递归地对实例进行测试并分配,直至达到叶结点。最后将实例分到叶结点的类中。
二、决策树学习
假设给定训练数据集:
D = { ( x1,y1 ),( x2,y2 ),......,( xN,yN ) }
其中,xi = (xi1,xi2,xi3,......,xin)T 为输入实例(特征向量),N为实例个数(样本容量),n为特征个数,yi为类标记。
学习的目标是根据给定的训练数据集构建一个决策树模型,使它能够对实例进行正确的分类。
决策树学习的算法通常是一个递归地选择最优特征,并根据该特征队训练数据进行分割,使得对各个子集有一个最好的分类的过程。这一过程对应着特征空间的划分和决策树的构建。
生成的决策树可能对训练数据有很好的分类能力,但对未知的测试数据却未必有很好的分类能力,即可能发生过拟合现象。我们需要对已生成的树自上而下进行剪枝,将树变得更简单,从而使它具有更好的泛化能力。具体地,就是去掉过于细分的叶结点,使其回退到父结点,甚至更高的结点,然后将父结点或更高的结点改为新的叶结点。
可以看出,决策树学习算法包含特征选择、决策树的生成与决策树的剪枝过程。常用的算法有ID3、C4.5与CART。
三、特征选择
特征选择在于选取对训练数据具有分类能力的最优特征。通常特征选择的准则是信息增益或信息增益比(信息增益率)。
1、熵(也称香农熵)和条件熵
香农熵这个名字来源于信息论之父克劳德?香农。熵定义为信息的期望值,表示随机变量不确定性的度量。
设X是一个取有有限个值的离散随机变量,其概率分布为:
P ( X = xi ) = pi, i = 1,2,3,…,n,
则随机变量X的熵定义为:
H(X) = -∑ pi * log pi
上试若取 log2 ,这时熵的单位为比特(bit) ;若取 ln ,这时熵的单位为纳特(nat),一般取 log2。
由定义知,熵只依赖于X的分布,而与X的取值无关,所以也可以将X的熵记作:
H ( p ) = -∑ pi * log pi
熵越大,随机变量的不确定性就越大。
条件熵 H(Y|X)表示一直随机变量X的条件下随机变量Y的不确定性。
H ( Y | X ) = -∑ pi * H ( Y | X = xi ) 这里 pi = P( X = xi ) ,i = 1,2,...,n
当熵和条件熵中的概率由数据估计(特别是极大似然估计)得到是,所对应的熵与条件熵分别称为经验熵和经验条件熵。
2、信息增益(information gain)
信息增益,表示由于特征A而使得数据集的分类的不确定性减少的程度。不同的特征往往有不同的信息增益,信息增益大的特征具有更强的分类能力。
定义:特征A对训练数据集D的信息增益 Gain(D,A),定义为集合D的经验熵H(D)与特征A给定条件下的经验熵H(D|A)之差,即:
Gain(D,A) = H ( D ) - H ( D | A )
根据信息增益准则的特征选择方法是:对训练数据集(或子集)D,计算其每个特征的信息增益,并比较他们的大小,选择信息增益最大的特征。
设训练数据集为D,|D|表示其样本容量(样本总数)。设有K个类Ck,k = 1,2,...,K,|Ck|为属于类Ck的样本个数,∑|Ck| = |D|。设特征A有n个不同的取值 { a1,a2,...,an},根据特征A的取值将D划分为n个子集 D1,D2,...,Dn ,|Di|为Di的样本个数,∑|Dk| = |D|。记子集Di中属于类Ck的样本的几何为Dik,即 Dik = Di ∩ Ck,|Dik|为Dik的样本个数。于是有:
信息增益的算法:
输入:训练数据集D和特征A;
输出:特征A对训练数据集D的信心增益 Gain(D,A).
(1)计算数据集D的经验熵H(D)
H(D) = -∑1k (|Ck| / |D|) * log2 (|Ck| / |D|)
(2)计算特征A对数据集D的经验条件熵 H(D | A)
H ( D | A ) = ∑1n (|Di| / |D|) * H(Di) = -∑1n (|Di| / |D|) * ∑1k (|Dik| / |Di|) * log2 (|Dik| / |Di|)
(3)计算信息增益
Gain(D,A) = H ( D ) - H ( D | A )
3、信息增益比(增益率)
以信息增益作为划分训练数据集的特征,存在偏向于选择取值较多的特征的问题。使用信息增益比可以对这一问题进行校正。
定义:特征A对训练数据集D的信息增益比 Gain_ratio(D,A) 定义为其信息增益Gain(D,A)与训练数据集D关于特征A的值熵 HA(D) 之比,即:
Gain_ratio(D,A) = Gain(D,A) / HA(D)
其中,HA(D) = -∑1n (|Di| / |D|) * log2 (|Di| / |D|),n是特征A取值的个数。
四、决策树的生成
决策树生成算法:
输入:训练数据集D,特征集A,阈值ε(预剪枝用,后剪枝不需要此项);
输出:决策树T。
(1)若D中所有样本属于同一类Ck,则T为但结点树,并将Ck作为该结点的类标记,返回T;
(2)若A = ?,则T为单结点树,并将D中样本数最多的类Ck作为该结点的类标记,返回T;
(3)否则,计算A中各个特征对D的信息增益或者信息增益比,选择信息增益或信息增益比最大的特征 Ag;
(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 。
ID3算法
在决策树生成过程中,以信息增益为特征选择的准则。
c4.5算法
在决策树生成过程中,以信息增益比为特征选择的准则。
五、决策树的剪枝
剪枝是决策树学习算法对付“过拟合”的主要手段。在决策树学习中,为了尽可能正确分类训练样本,结点划分过程将不断重复,有时会造成决策树分支过多。因此,可通过主动去掉一些分支来降低过拟合的风险。
决策树剪枝的基本策略有“预剪枝”和“后剪枝”。
预剪枝是指在决策树生成过程中,对每个结点在划分前先进行估计,若当前结点的划分不能带来决策树泛化性能提升,则停止划分并将当前结点标记为叶结点;
后剪枝则是先从训练集生成一棵完整的决策树,然后自底向上地对非叶结点进行考察,若将该结点对应的子树替换为叶结点能带来决策树泛化性能提升,则该子树替换为叶结点。
如何判断决策树泛化性能是否提升呢?可以选择一种性能评估方法(留出法、交叉验证法、自助法等)。性能评估方法参看其他笔记。
六、CART算法(分类与回归树clssification and regression tree)
CART同样由特征选择、树的生成及剪枝组成,既可以用于分类也可以用于回归。
CART假设决策树是二叉树,内部结点特征的取值为“是”和“否”,左分支是取值“是”的分支,右分支是取值为“否”的分支。这样的决策树等价于递归地二分每个特征。
CART算法由以下两步组成:
(1)决策树生成:基于训练数据集生成决策树,生成的决策树要尽量大;
(2)决策树剪枝:用验证数据集对已生成的树进行剪枝并选择最优子树,这时用损失函数最小作为剪枝的标准。
1、CART生成决策树
决策树的生成就是递归地构建二叉树的过程。对回归树用平方误差最小化准则,对分类树用基尼指数(Gini index)最小化准则,进行特征选择,生成二叉树。
(1)回归树的生成
假设X与Y分别为输入和输出变量,并且Y是连续变量,给定训练数据集
D = { ( x1,y1 ),( x2,y2 ),......,( xN,yN ) }
考虑如何生成回归树。
一个回归树对应着输入空间(即特征空间)的一个划分以及在划分的单元的输出值。假设已将输入空间划分为M个单元R1,R2,...,RM,
并且在每个单元Rm上有一个固定的输出值cm,于是回归树模型可表示为:
? ( x ) = ∑ cm I ( x ∈ Rm)
当输入空间的划分确定时,可以用平方差 ∑( yi - ? ( xi ))2 来表示回归树对于训练数据的预测误差,用平方差最小的准则求解每个单元上的最优输出值。
假如使用特征 j 的取值 s 来将输入空间划分为两个区域,分别为:
我们需要最小化损失函数,即:
其中c1,c2分别为R1,R2区间内的输出平均值。(此处与统计学习方法上的公式有所不同,在课本中里面的c1,c2都需要取最小值,但是,在确定的区间中,当c1,c2取区间输出值的平均值时其平方会达到最小,为简单起见,故而在此直接使用区间的输出均值。)
为了使平方误差最小,我们需要依次对每个特征的每个取值进行遍历,计算出当前每一个可能的切分点的误差,最后选择切分误差最小的点将输入空间切分为两个部分,然后递归上述步骤,直到切分结束。此方法切分的树称为最小二乘回归树。
最小二乘回归树生成算法:
输入:训练数据集 D;
输出:回归树 ? ( x ).
在训练数据集所在的输入空间中,递归地将每个区域划分为两个子区域并决定每个区域上的输出值,构建二叉决策树:
(1) 选择最优切分变量 j 与切分点 s,求解
遍历变量 j, 对固定的切分变量 j 扫描切分点 s,选择使上式达到最小值的对(j,s)。
(2)用选定的对(j,s)划分区域并决定相应 的输出值:
(3)继续对两个子区域调用步骤(1)、(2),直到满足停止条件。
(4)将输入空间划分为M个区域 R1,R2,...,RM,生成决策树:
其中Cm是Rm上所有输入实例 xi 对应的输出 yi 的均值。
(2)分类树的生成
分类树的生成用基尼指数选择最优特征,同时决定改特征的最优二值切分点。
基尼指数:
分类问题中,假设有K个类,样本点属于第K类的概率为pk ,则概率分布基尼指数为:
对于给定的样本集合D,其基尼指数为:
这里,ck 是 D 中属于第 k类的样本子集,K是类的个数。
如果样本集合根据特征A是否取某一可能值a,被分割成 D1和D2两部分,即:
则在特征A的条件下,集合D的基尼指数定义为:
基尼指数 Gini(D)表示集合D的不确定性,基尼指数Gini(D,A)表示经 A = a 分割后集合D 的不确定性。基尼指数值越大,样本集合的不确定性也就越大,这一点与熵相似。
CART生成算法:
输入:训练数据集D,停止计算的条件;
输出:CART决策树。
根据训练数据集,从根结点开始,递归地对每个结点进行以下操作,构建二插决策树:
(1)设节点的训练数据集为D,计算现有特征对该数据集的基尼指数。此时,对每一个特征A,对其可能取的每个值a,根据样本点对A=a的测试为“是”或“否”将D分割成 D1和D2两部分,计算 Gini(D,A)(见上面公式)。
(2)在所有可能的特征A以及它们所有可能的值(切分点)a中,选择基尼指数最小的特征及其对应的切分点作为最优特征与最优切分点。依最优特征与最优切分点,从现有结点生成两个子结点,将训练数据集依特征分配到两个子结点中去。
(3)对两个子结点递归地调用(1)、(2),直到满足停止条件。
(4)生成CART决策树。
算法停止条件,是结点中的样本个数小于预定阈值,或样本集的基尼指数小于预定阈值(样本基本属于同一类),或者没有更多特征。
2、CART剪枝
决策树常用的剪枝有事前剪枝(预剪枝)和事后剪枝(后剪枝),CART算法采用后剪枝,具体方法为代价复杂性剪枝法。可参考如下链接(累,有时间再补上自己的)
剪枝参考:http://www.cnblogs.com/zhangchaoyang/articles/2709922.html
七、算法的代码实现:
代码是照着《机器学习实战》这本书敲的,只是实现了ID3树的生成,很简单。希望后面自己能实现其他的算法。
1 # -*- coding: utf-8 -*- 2 from math import log 3 import operator 4 5 ‘‘‘计算给定数据集的熵‘‘‘ 6 def calcShannonEnt(dataSet): 7 numEntries = len(dataSet) #样本总数 8 labelCounts = {} #创建一个字典,存放分类信息,各类含样本数 9 for featVec in dataSet: 10 currentLabel = featVec[-1] # 11 if currentLabel not in labelCounts.keys(): #dic.keys() 返回字典所有的键 12 labelCounts[currentLabel] = 0 13 labelCounts[currentLabel] += 1 14 shannonEnt = 0.0 15 for key in labelCounts: 16 prob = float(labelCounts[key])/numEntries 17 shannonEnt -= prob * log(prob,2) 18 return shannonEnt 19 20 ‘‘‘创建数据集‘‘‘ 21 def createDataSet(): 22 dataSet = [ 23 [1,1,‘yes‘], 24 [1,1,‘yes‘], 25 [1,0,‘no‘], 26 [0,1,‘no‘], 27 [0,1,‘no‘] 28 ] 29 labels = [‘without water‘,‘flippers‘] 30 return dataSet,labels 31 32 ‘‘‘划分数据集‘‘‘ 33 def splitDataSet(dataSet,axis,value):#axis-划分数据集的特征,value-需要返回的特征的值 34 retDataSet = [] 35 for featVec in dataSet: 36 if featVec[axis] == value: 37 reducedFeatVec = featVec[:axis] 38 reducedFeatVec.extend(featVec[axis + 1:]) #extend() 用于在列表末尾一次性追加另一个序列(用新列表扩展原来的列表) 39 retDataSet.append(reducedFeatVec) 40 return retDataSet 41 42 ‘‘‘选择出信息增益大的特征‘‘‘ 43 def chooseBestFeatureToSplit(dataSet): 44 numFeatures = len(dataSet[0]) - 1 45 baseEntropy = calcShannonEnt(dataSet) #熵 46 bestInfoGain = 0.0 47 bestFeature = -1 48 for i in range(numFeatures): 49 featList = [example[i] for example in dataSet] 50 uniqueVals = set(featList) 51 newEntropy = 0.0 52 for value in uniqueVals: 53 subDataSet = splitDataSet(dataSet,i,value) 54 prob = len(subDataSet) / float(len(dataSet)) 55 newEntropy += prob * calcShannonEnt(subDataSet) 56 infoGain = baseEntropy - newEntropy 57 if(infoGain > bestInfoGain): 58 bestInfoGain = infoGain 59 bestFeature = i 60 return bestFeature 61 62 ‘‘‘返回次数出现最多的分类名称‘‘‘ 63 def majorityCnt(classList): 64 classCount = {} 65 for vote in classList: 66 if vote not in classCount.keys(): 67 classCount[vote] = 0 68 classCount[vote] += 1 69 sortedClassCout = sorted(classCount.iteritems(),key=operator.itemgetter(1),reverse=True) 70 return sortedClassCout[0][0] 71 72 ‘‘‘生成决策树‘‘‘ 73 def createTree(dataSet,labels): 74 classList = [example[-1] for example in dataSet] 75 if classList.count(classList[0]) == len(classList):#类别完全相同则停止划分 76 return classList[0] 77 if len(dataSet[0]) == 1: #遍历完所有特征时,返回出现次数最多的类别 78 return majorityCnt(classList) 79 bestFeat = chooseBestFeatureToSplit(dataSet) #得到的是下标 80 bestFeatLabel = labels[bestFeat] #取值:no water 或者 flippers 81 82 myTree = {bestFeatLabel:{}} 83 del(labels[bestFeat]) 84 featValues = [example[bestFeat] for example in dataSet] 85 uniqueVals = set(featValues) 86 for value in uniqueVals: 87 subLables = labels[:] 88 myTree[bestFeatLabel][value] = createTree(splitDataSet(dataSet,bestFeat,value),subLables) 89 return myTree
参考文献:《统计学习方法》-- 李航、《机器学习》(西瓜书)-- 周志华、《机器学习实战》-- 李锐
这是我的第一篇博客,希望自己在学习过程中能坚持多记笔记多总结。