机器学习实战---------第三章 决策树

决策树的构造

  • 优点:计算复杂度不高,输出结果易于理解,对中间值的缺失不敏感,可以处理不相关特征数据。
  • 缺点:可能会产生过度匹配问题
  • 适用数据类型:数值型和标称型

原理

在构造决策树时候,我们需要解决的第一个问题是:当前数据集上哪个特征在划分数据时候起决定作用,为了找到决定性的特征,划分出最好的结果,我们必须评估每个特征。
创建分支的伪代码函数createBrance()如下所示:
检测数据集中每个子项是够属于同一分类:
    If so  return 类标签;
    else
    寻找划分数据集的最好特征
    划分数据集
    创建分支节点
        for 每个划分的子集
            调用函数createBrance并增加返回结果到分支节点中
    return 分支节点

决策树的一般流程

  • 收集数据:可以使用任何方法
  • 准备数据:树构造算法只适用于标称型数据,因此数值型数据必须离散化
  • 分析数据:可以使用任何方法,构造树完成之后,我们应该检查图形是否符合与其
  • 训练算法:构造树的数据结构
  • 测试算法:使用经验树计算错误率
  • 使用算法:此步骤可以适用于任何监督学习算法,而使用决策树可以更好地理解数据的内在含义

一般算法采用二分法划分数据,这里我们采用ID3算法,每次划分数据集我们只选取一个特征属性,如果训练集中存在20个特征,第一次我们选择哪个特征作为划分的参考属性呢?
划分数据集的最大原则是:将无序的数据变得更加有序,我们可以使用多重方法划分数据集,这里我们引入信息增益来作为我们划分数据的主要工具。
那么什么是信息增益呢?在划分数据集前后信息发生的变化称为信息增益
如果知道如何计算信息增益,我们就可以计算每个特征值划分数据集获得信息增益,获得信息增益最高的特征就是最好的选择。

在这之前我们需要了解一下,集合信息的度量方式:香农熵或者简称为熵
在明确这个概念之前,我们必须知道信息的定义,如果带分类的事物可能划分在多个分类中,则符号 xi 的信息定义为:

l(xi)=log2p(xi)

其中 p(xi) 是选择该分类的概率
为了计算熵,我们需要计算所有类别所有可能值包含的信息期望值,通过下面的公式可以得到:
H=i=1np(xi)log2p(xi)

下面我们利用Python计算信息熵。

from math import log
def calcShannonEnt(dataSet):
    numEntries=len(dataSet)
    labelCounts={}
    for featVec in dataSet:
        currentLabel=featVec[-1]
        if currentLabel not in labelCounts.keys():
            labelCounts[currentLabel]=0
        labelCounts[currentLabel]+=1
    shannonEnt=0.0
    for key in labelCounts:
        prob=float(labelCounts[key])/numEntries
        shannonEnt-=prob*log(prob,2)
    return shannonEnt

def createDataSet():
    dataSet=[[1,1,'yes'],[1,1,'yes'],[1,0,'no'],[0,1,'no'],[0,1,'maybe']]
    labels=['no surfacing','flippes']
    return dataSet,labels

if __name__=='__main__':
    myDat,labels=createDataSet()
    print calcShannonEnt(myDat)

划分数据集

我们学习了如何度量数据集的无序程序,分类算法除了需要测量信息熵,还需要分划分数据集,度量划分数据集的熵,以便判断当前是否正确地划分数据集。
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

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 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]


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

你可能感兴趣的:(机器学习实战---------第三章 决策树)