机器学习实战之决策树

1 算法概述
1.1 结构分析
决策树是一种依托决策而建立起来的树,其中,每一个内部节点表示一个属性上的测试,每一个分支代表一个测试的结果输出,每一个叶子代表一种类别。
这里写图片描述
如上图所示就是一个决策树,首先分析所给数据集是否为同一类别,如果是,那就不用划分了,如果不是,就寻找划分数据集最好的特征进行划分(也就是影响数据集划分因素最明显的特征划分,这个后面会专门介绍最大信息增益法划分,知道怎么用就中),比如上图一开始就是选择的是:发送邮件域名地址为某某莫,每个内部节点(数据子集)代表一个二分类问题,每个叶子节点是分类的结果,遇到内部节点就一直划分,直到划分的数据子集都属于同一类型的数据时,就停止划分,此时,也就意味着你的决策树已经建好。
1.2 算法思想
这是一种寻找数据集内部之间规律的算法,以信息熵为度量,构造一颗熵值下降最快的数,到叶子节点处的熵值为零。此时,每一个叶子代表一个类别。
在决策树的每一个非叶子结点划分之前,先计算每一个属性所带来的信息增益,选择最大信息增益的属性来划分,因为信息增益越大,区分样本的能力就越强,越具有代表性,很显然这是一种自顶向下的贪心策略。以上就是ID3算法的核心思想
1.3 算法实现步骤
①计算每种特征划分方式的信息熵,选取信息熵最大的一种划分方式
②递归的构建决策树
2 实现
(1)创造数据集
(2)计算数据集信息熵

def calcShannonEnt(dataSet):
    numEntries = len(dataSet) #len()是计算变量长度的函数 ,numEntries=5
    labelCounts = {}   #为所有可能分类创造字典
    #遍历每条数据集样本,如果字典里没有数据集中的类别,将此类别存入字典中,如果有,将此类别数目加1
    #以下for循环里计算结果为labelCounts=['yes':2,'no':3]
    #其实,以下for循环可以用一句话概括:
    #labelCounts[currentLabel]=labelCounts.get(currentLabel,0)+1
    for featVec in dataSet: #the the number of unique elements and their occurance
        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 #numEntries=5
        shannonEnt -= prob * log(prob,2) #log base 2
    return shannonEnt

(3)根据上面计算的信息熵,划分数据集
(4)选择最好的划分结果

def chooseBestFeatureToSplit(dataSet):
    numFeatures = len(dataSet[0]) - 1      #特征数,-1是因为dataSet最后一列是标签类别
    baseEntropy = calcShannonEnt(dataSet)   #计算总数据集的信息熵
    bestInfoGain = 0.0; bestFeature = -1
    for i in range(numFeatures):        #遍历每一个特征
        featList = [example[i] for example in dataSet]#遍历每个特征的数据集
        uniqueVals = set(featList)    #第i个特征取值集合,如果i=1,则uniqueVals=[1,1,1,0,0]
        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     #calculate the info gain; ie reduction in entropy
        if (infoGain > bestInfoGain):       #选择最大信息熵的划分结果
            bestInfoGain = infoGain         #if better than current best, set to best
            bestFeature = i
    return bestFeature                      #returns an integer

(5)递归构造决策树
多数表决的方法决定叶子节点的分类 –该叶子属于哪一类的样本最多,我们就说该叶子属于哪类

def createTree(dataSet,labels):
    classList = [example[-1] for example in dataSet] #数据集所有标签列表
    #终止条件1;类别完全相同,表示就只有一个类别,则停止继续划分  返回标签-叶子节点
    if classList.count(classList[0]) == len(classList):
        return classList[0]#stop splitting when all of the classes are equal
    #终止条件2:无法将数据集划分成唯一类别时,采用多数表决法决定叶子的分类
    if len(dataSet[0]) == 1: #stop splitting when there are no more features in dataSet
        return majorityCnt(classList)  #遍历完所有的特征时返回出现次数最多的
    #开始创建树
    bestFeat = chooseBestFeatureToSplit(dataSet) #选择最好的方式进行划分数据集,得到最好划分数据集特征
    bestFeatLabel = labels[bestFeat]
    myTree = {bestFeatLabel:{}}  #用上面得到的最好划分数据集特征建立一个空树(空字典)
    del(labels[bestFeat])  #删除labels[bestFeat]
    featValues = [example[bestFeat] for example in dataSet]
    uniqueVals = set(featValues)
    for value in uniqueVals:  #遍历当前选择的特征包含的所有属性
        subLabels = labels[:]       #copy all of labels, so trees don't mess up existing labels
        #递归调用构建树的过程,直到遍历完所有划分数据集属性,所有相同类别的数据均被分到同一个数据子集中
        myTree[bestFeatLabel][value] = createTree(splitDataSet(dataSet, bestFeat, value),subLabels)
    return myTree

(6)用决策树进行预测标签

def classify(inputTree,featLabels,testVec):
    firstStr = inputTree.keys()[0] #第一个特征属性:firstStr='no surfacing'
    #除去第一个特征属性的字典:secondDict={0: 'no', 1: {'flippers': {0: 'no', 1: 'yes'}}}
    secondDict = inputTree[firstStr]
    featIndex = featLabels.index(firstStr) #寻找第一个特征属性在特征属性列表中的位置:featIndex=0
    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
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值