决策树(一) ID3

ID3是决策树的一种。

以下的内容出自

1. 机器学习实战 Peter Harrington

2. 统计学习方法  李航

下面首先是一段python代码:

# coding=utf-8 
from math import log
import operator
def clacShannonEnt(dataSet):#计算给定数据集的香农熵
    numEntries=len(dataSet)
    labelCount={}
    for featVec in dataSet:
        currentLabel=featVec[-1]
        if currentLabel not in labelCount.keys():
            labelCount[currentLabel]=0
        labelCount[currentLabel]+=1
    shannonEnt=0.0
    for key in labelCount:
        prob=float(labelCount[key])/numEntries
        shannonEnt-=prob*log(prob,2)
    return shannonEnt
def createDataSet():
    dataSet=[[1,3,'yes'],
             [1,1,'yes'],
             [1,0,'no'],
             [0,1,'no'],
             [0,1,'no']]
    labels=['no surfacing','flippers']
    return dataSet,labels

#分类的类别越多,越无序
#香农熵越小,集合越纯,当集合仅仅只有一种 则H=p(x)logp(x)=1*log1=0
#当x可以取值很多的时候,H越大


#将数据集合中的实例按照给定的特征来划分,每次去掉一个特征
def splitDataSet(dataSet,axis,value):
    retDataSet=[]
    for featVec in dataSet:
        if featVec[axis]==value:
            reducedFeatVec=featVec[:axis]
            reducedFeatVec.extend(featVec[axis+1:])
            retDataSet.append(reducedFeatVec)
    return retDataSet
#找到信息增益最大的feature分裂 Gain(S)=Entroy(S原始)-sum(SV/S*Entroy(SV))
def chooseBestFeatureToSplit(dataSet):
    numFeatures=len(dataSet[0])-1
    baseEntroy=clacShannonEnt(dataSet)#计算原始香农熵
    bestInfoGain=0.0
    bestFeature=-1
    for i in range(numFeatures):
        featList=[example[i] for example in dataSet]#获得第i个feature的所有可能取值
        uniqueVals=set(featList)#unique it
        newEntroy=0.0
        for value in uniqueVals:#for循环计算SV/S*entroy(SV)的sum
            subDataSet=splitDataSet(dataSet,i,value)
            prob=len(subDataSet)/float(len(dataSet))
            newEntroy+=prob*clacShannonEnt(subDataSet)
        infoGain=baseEntroy-newEntroy
        if infoGain>bestInfoGain:
            bestInfoGain=infoGain
            bestFeature=i
    return bestFeature  #返回最佳的分裂feature
#当数据集已经处理了所有的feature,那就只剩下了label,使用多数表决法则来决定该叶子节点的分类类型
def majorityCnt(classList):
    classCount={}
    for vote in classList:
        if vote not in classCount.keys():
            classCount[vote]=0
        classCount[vote]+=1
        sortedClassCount=sorted(classCount.iteritems(),key=operator.itemgetter(1),reverse=True)
    return sortedClassCount[0][0]
#创建ID3 Tree
def createTree(dataSet,labels):
    classList=[example[-1] for example in dataSet]
    if classList.count(classList[0])==len(classList):#若所有的类别都相同,那么直接返回。
       # print classList[0]
        return classList[0]
    if len(dataSet[0])==1:#当消耗掉了所有的feature 则要采用多数表决的方式
        return majorityCnt(classList)
    bestFeat=chooseBestFeatureToSplit(dataSet)#找到dataSet中最好的Split Feature
    bestFeatLabel=labels[bestFeat]
   # print bestFeatLabel
    myTree={bestFeatLabel:{}}
    del(labels[bestFeat])#消耗掉feature
    featValues=[example[bestFeat] for example in dataSet]
    uniqueVals=set(featValues)
    for value in uniqueVals:
        subLable=labels[:]
        myTree[bestFeatLabel][value]=createTree(splitDataSet(dataSet,bestFeat,value),subLable)
    return myTree
        
#执行分类操作 ID3决策树
def classify(inputTree,featLabels,testVec):
    firstStr=inputTree.keys()[0]
    #print firstStr
    secondDict=inputTree[firstStr]
    featIndex=featLabels.index(firstStr)#找到最佳Split Tree对应的Feature Index
    for key in secondDict.keys():
        if testVec[featIndex]==key:
            if type(secondDict[key]).__name__=='dict':
                classLabel=classify(secondDict[key],featLabels,testVec)
            else:
                classLabel=secondDict[key]
    return classLabel
#存储树
def storeTree(inputTree,filename):
    import pickle
    fw=open(filename,'w')
    pickle.dump(inputTree,fw)
    fw.close()
#从硬盘获得树
def grabTree(filename):
    import pickle
    fr=open(filename)
    return pickle.load(fr)

#myDat,myLabel=createDataSet()
#myTree=createTree(myDat,myLabel)
myTree=grabTree("id3.txt")
print myTree
myLabel=['no surfacing','flippers']
print classify(myTree,myLabel,[1,3])
#storeTree(myTree,'id3.txt')

1. 度量数据集合中数据的一致性:香农熵

2. 信息增益

ID3决策树分类器就像带有终止块的流程图,终止块表示分类的结果,而中间的块表示数据集的feature。开始处理数据集的时候,首先需要测量数据集合的不一致性(香农熵可以表示);然后寻找最优的方案来切割数据集(通常使用信息增益最大的概念);直到数据集属于同一类或者是feature已经消耗完毕(每次split都会消耗掉一个feature)ID3算法无法直接处理数值型数据,尽管可以将数值型数据转化为标称型数据,但是如果存在了过多的特征划分,那么会存在overfiting的问题。

ID3算法与KNN相比,ID3给出的数据形式非常容易理解,KNN无法给出数据的内在含义。

1.数学上如何使用信息论划分数据集?当前数据集上哪个特征在划分数据分类时候起到了决定性的作用?

答:1. 信息增益:划分数据集合之前之后信息发生的变化

划分数据集的原则:是的无序的数据变得更加有序。

可以使用信息论中的香农熵来度量数据集合的混乱程度。

香农熵是信息的期望值,信息x的信息量为-log(p(x),2)

所以香农熵为H=sum(p(label=x)log(p(x=label),2))  p(label==x)标签为x的概率。

香农熵表示了一个dataSet的混乱成都,当类别标签越多,也就是所dataSet越杂乱无章,那么H越大。若p(label==x)==1那么这个dataSet是非常纯净的,则H=1*log(1,2)=0

也就是说:H越大,越杂乱;H越小,越纯净。这也是为什么要找信息增益最大的原因。

计算香农熵的伪代码如下:

  Del calcShannonEnt(dataSet):
  numEntries=len(dataSet)
  labelCounts={}
  For featVec in dataSet:
  currentLabel=featVec[-1]
  If currentLabel not in labelCounts.keys():
  labelCounts[currentLabel]=0
  labelCount[currentLabel]+=1
  shannonEnt=0.0
  For key in labelCounts:
  Prob=float(labelCounts[key])/numEntries
  shannonEnt-=Prob*log(Prob,2)
  Return shanonEnt

 使用信息增益来划分数据集:

数据集的无序程序可以使用香农熵来度量。对每个特征都进行一次划分,来找到使用哪个feature会是的信息增益最大。

Gain(s)=Entroy(s原始)-sum((Sv/S)*(Entroy(Sv))

2. 创建ID3决策树的伪代码:

检测数据集中的每个子项是否属于同一个分类or 检测数据集中的feature是否已经被消耗殆尽

If So return 类标签 or 多数表决

Else:

寻找划分数据集最好的特征(指的是采用该特征来划分数据集该数据集合的信息增益最大)

划分数据集

创建分支节点

For 每个划分的子集

调用createTree 并返回到分支节点中

Return 分支节点

ATTENTION

ID3树构造只适用于标称型数据,因此应该将数值型数据离散化。

一些决策树算法使用二分法划分数据,ID3不是这样的。如果依据某个feature划分数据,若该feature可能去4个值,那么该feature下将会有4个分支。每次划分数据集的时候仅仅采用一个feature,也即是信息增益最大的feature



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值