决策树是基于树的结构来进行决策的,这恰是人类面临问题时一种很自然的处理机制。
例如,我们要对“这是好瓜吗?”这样的问题进行决策,我们会根据瓜的色泽,根蒂,敲声等瓜的属性来进行判断.
决策树的目的是产生一颗具有泛化能力的树,能对未知的实例进行预测。
建立决策树的关键是选择最优的属性进行划分,如上图根节点为什么是“色泽”而不是“根蒂”,我们希望属性划分后的分支节点所包含的样本属于同一类别,即纯度越来越高,因此“色泽”划分后的熵减大于“根蒂”,熵越大,纯度越小。根据选择最优属性的方法不同,分为以下三种算法。
ID3算法是选择信息增益最大的属性进行划分。
ID3算法只有树的生成,所以该算法生成的树容易产生过拟合。
ID3算法对可取值数目较多的属性有所偏好。
信息熵的公式
E n t ( D ) = − ∑ k = 1 ∣ y ∣ p k l o g 2 p k Ent(D)= - \sum_{k=1}^{|y|}p_klog_2p_k Ent(D)=−k=1∑∣y∣pklog2pkpk为样本集D中第k类样本所占的比例
信息增益的公式为
G a i n ( D , a ) = E n t ( D ) − ∑ v = 1 V ∣ D v ∣ ∣ D ∣ E n t ( D v ) Gain(D,a)=Ent(D)-\sum_{v=1}^V\dfrac{|D^v|}{|D|}Ent(D^v) Gain(D,a)=Ent(D)−v=1∑V∣D∣∣Dv∣Ent(Dv)Dv为在属性a上取值为av的样本
举例,我们根据西瓜各属性取值和它所对应的类别(是否为好瓜)建立如下训练集。
先计算信息熵:
集合D中有两个类别,“是”好瓜和“否”好瓜,是好瓜为1-8,占总样本的8/17,即p1=8/17,“否”好瓜为样本9-17,占总样本对的9/17,即p2=9/17,带入信息熵的公式
E n t ( D ) = − ∑ k = 1 ∣ y ∣ p k l o g 2 p k = − ( 8 17 l o g 2 8 17 + 9 17 l o g 2 9 17 ) = 0.998 Ent(D)= - \sum_{k=1}^{|y|}p_klog_2p_k\\ =-(\dfrac8{17}log_2\dfrac8{17}+\dfrac9{17}log_2\dfrac9{17}) =0.998 Ent(D)=−k=1∑∣y∣pklog2pk=−(178log2178+179log2179)=0.998
再计算当前未划分属性集合{色泽,根蒂,敲声,纹理,脐部,触感}的每个属性的信息增益,以“色泽”为例,它有3个可能的取值:{青绿,乌黑,浅白}
青绿包含{1,4,6,10,13,17}6个样本,正例占3/6,反例占3/6,青绿分支的信息熵为
E n t ( D 1 ) = − ( 3 6 l o g 2 3 6 + 3 6 l o g 2 3 6 ) = 1.000 Ent(D^1)=-(\dfrac36log_2\dfrac36+\dfrac36log_2\dfrac36)=1.000 Ent(D1)=−(63log263+63log263)=1.000
乌黑包含{2,3,7,8,9,15}6个样本,正例占4/6,反例占2/6,乌黑分支的信息熵为
E n t ( D 2 ) = − ( 4 6 l o g 2 4 6 + 2 6 l o g 2 2 6 ) = 0.918 Ent(D^2)=-(\dfrac46log_2\dfrac46+\dfrac26log_2\dfrac26)=0.918 Ent(D2)=−(64log264+62log262)=0.918
浅白包含{5,11,12,14,16}5个样本,浅白分支的信息熵为
E n t ( D 3 ) = − ( 1 5 l o g 2 1 5 + 4 5 l o g 2 4 5 ) = 0.722 Ent(D^3)=-(\dfrac15log_2\dfrac15+\dfrac45log_2\dfrac45)=0.722 Ent(D3)=−(51log251+54log254)=0.722
根据信息增益的公式可计算出“色泽”的信息增益为
G a i n ( D , a ) = E n t ( D ) − ∑ v = 1 3 ∣ D v ∣ ∣ D ∣ E n t ( D v ) = 0.998 − ( 6 17 ∗ 1.000 + 6 17 ∗ 0.918 + 5 17 ∗ 0.722 ) = 0.109 Gain(D,a)=Ent(D)-\sum_{v=1}^3\dfrac{|D^v|}{|D|}Ent(D^v) \\ =0.998-(\dfrac6{17}*1.000+\dfrac6{17}*0.918+\dfrac5{17}*0.722)\\ =0.109 Gain(D,a)=Ent(D)−v=1∑3∣D∣∣Dv∣Ent(Dv)=0.998−(176∗1.000+176∗0.918+175∗0.722)=0.109
类似的,我们可以计算出其他属性的信息增益:
Gain(D,根蒂)=0.143; Gain(D,敲声)=0.141;
Gain(D,纹理)=0.381; Gain(D,脐部)=0,289;
Gian(D,触感)=0.006
属性“纹理”的信息增益最大,于是它被选为第一个划分属性,基于“纹理”对根节点进行划分,得到以下结果
再对三个分支所包含的子样本对剩余的属性{色泽,根蒂,敲声,脐部,触感}计算它们的信息增益,选出信息增益最大的属性进行划分,最终得到一颗决策树:
C4.5算法使用增益率来选择最优划分属性。
构造决策树之后进行剪枝操作,解决ID3算法中可能出现的过拟合问题。
克服了ID3算法中倾向于选择拥有多个属性值的属性作为划分属性的不足。
增益率公式
G a i n r a t i o ( D , a ) = G a i n ( D , a ) Λ ( a ) Λ ( a ) = − ∑ v = 1 V ∣ D v ∣ ∣ D ∣ l o g 2 ∣ D v ∣ ∣ D ∣ Gain_ratio(D,a)=\dfrac{Gain(D,a)}{\Lambda(a)}\\ \Lambda(a)=-\sum_{v=1}^V\dfrac{|D^v|}{|D|}log_2\dfrac{|D^v|}{|D|} Gainratio(D,a)=Λ(a)Gain(D,a)Λ(a)=−v=1∑V∣D∣∣Dv∣log2∣D∣∣Dv∣
C4.5算法不是直接选增益率最大的进行划分,而是先从候选划分属性中找出增益高于平均水平的属性,再从中选择增益率最高的。
选择基尼指数最小的属性作为划分属性。
基尼值的公式为
G i n i ( D ) = ∑ k = 1 ∣ y ∣ ∑ k ’ ≠ k p k p k ’ Gini(D)=\sum_{k=1}^{|y|}\sum_{k^’≠k}p_kp_{k’} Gini(D)=k=1∑∣y∣k’=k∑pkpk’
属性a的基尼指数公式为
G a i n i n d e x ( D , a ) = ∑ v = 1 V ∣ D v ∣ ∣ D ∣ G i n i ( D v ) Gain_index(D,a)=\sum_{v=1}^V\dfrac{|D^v|}{|D|}Gini(D^v) Gainindex(D,a)=v=1∑V∣D∣∣Dv∣Gini(Dv)
剪枝是决策树对付“过拟合”的主要手段,有时会因为训练样本学得“太好”了,以致于把训练集自身的一些特点当中所有训练集都具有的一般性质而导致过拟合。剪枝处理能去掉一些分支来降低过拟合的风险。
自上而下的计算,贪心法则,能剪的全减掉,比如,判断脐部该不该划分,把脐部标记为训练样例数最多的类别,假设样例数最多的是好瓜,则把脐部替换成叶子节点好瓜,用测试集计算划分之前的正确率和划分之后的正确率,划分之后的正确率大于分之前的正确率,则该属性应该划分。
后剪枝先从训练集生成一颗完整的决策树,从下往上,能不剪就不剪,剪之后没有变化就不剪,剪之后能提高分类正确率就剪。
例如,判断色泽该不该划分为,划分之后的分类正确率小于划分前的正确率,则不应该划分,即把“色泽”节点替换成“好瓜”叶节点。
选择最好的数据集划分方式
def chooseBestFeatureToSplit(dataSet):
numFeatures=len(dataSet[0])-1
baseEntropy=calcShannonEnt(dataSet)
bestInfoGain=0.0;bestFeature=-1;
for i in range(numFeatures):
featList=[example[i] for example in dataSet] #创建唯一的分类标签列表
uniqueVals=set(featList)
newEntropy=0.0
for value in uniqueVals: #计算每种划分方式的信息熵
subDataSet=splitDataSet(dataSet,i,value)
prob=len(subDataSet)/float(len(dataSet))
newEntropy+=prob*calcShannonEnt(subDataSet)
infoGain=baseEntropy-newEntropy #计算信息增益
if (infoGain>bestInfoGain): #计算最好的信息增益
bestInfoGain=infoGain
bestFeature=i
return bestFeature
创建树的函数代码
def createTree(dataSet,labels):
classList=[example[-1] for example in dataSet]
if classList.count(classList[0])==len(classList): #类别完全相同停止继续划分
return classList[0]
if len(dataSet[0])==1: #遍历完所有特征时返回出现次数最多的
return majorityCnt(classList)
bestFeat=chooseBestFeatureToSplit(dataSet) #选择最优划分属性
bestFeatLabel=labels[bestFeat]
myTree={
bestFeatLabel:{
}}
del(labels{
bestFeat})
featValues=[example[bestFeat] for example in dataSet]
uniqueVals=set(featValues)
for value in uniqueVals:
subLabels=labels[:]
myTree[bestFeatLabel][value]=createTree(splitDataSet\(dataSet,bestFeat,value),subLabels)
return myTree