决策树

决策树定义

  • 概念:决策树可以近似于一个流程图,长方形代表判断模块,椭圆形代表终止模块,表示已经得出结论,可以终止运行。从判断模块引出的左右箭头称作分支,它可以到达另一个判断模块或者终止模块。


    决策树_第1张图片
    决策树
  • 优点:计算复杂度不高,输出结果易于理解,对中间值的缺失不敏感,可以处理不相关特征数据

  • 缺点:可能会产生过度匹配问题

  • 应用难点:很难确定特征

  • 适用数据类型:数值型和标称型

  • 如何创建树的分支?

Function createBranch():
检测数据集中的每个子集是否属于同一分类
    If so return 类标签;
    Else
        寻找划分数据集的最好特征
        划分数据集
        创建分支节点
            for 每个划分的子集
                调用函数createBranch()并增加返回结果到分支节点中
        return 分支节点
  • 信息增益:划分数据之前之后的变化称为信息增益,通过计算每个特征值划分数据集获得的信息增益,获得信息增益最高的特征就是最好的选择。香农提出的了熵用于计算信息增益,信息增益=原来的熵-变化后的熵
  • 信息的定义:l(xi)=-log2p(xi),p(xi)表示选择xi类别的概率
  • 熵:信息的期望值,计算一个样本集合中的数据是纯洁的还是不纯洁的,公式(n是分类的数目):
H=-\sum_{i=1}^{n}p(x_i)log_2p(x_i)

决策树的程序实现

  • 计算给定数据集的香农熵的实现代码:
from math import log
def calcShannonEnt(dataset):
    numEntries = len(dataset)
    labelCounts ={}
    # 求出各个类别的样本总数,用来计算p(xi)
    for featVec in dataset:
        currentLabel = featVec[-1]
        if currentLabel not in labelCounts.keys():
            labelCounts[currentLabel] = 0
        labelCounts[currentLabel] += 1
    shannoEnt = 0.0
    #利用公式计算熵
    for key in labelCounts:
        prob = float(labelCounts[key])/numEntries
        shannoEnt -= prob*log(prob,2)
    return shannoEnt
  • 信息熵、信息增益与信息增益率的区别
  • 划分数据集:对每个特征划分数据集的结果计算一次信息熵,然后判断按照哪个特征划分数据集是最好的划分方式:
#按照给定特征划分数据集
#extend() 函数用于在列表末尾一次性追加另一个序列中的多个值
#输入:待划分的数据集,划分数据集的特征,需要返回的特征的值
#a[i:j]:表示取从第i+1位到第j个元素
def splitDataSet(dataSet,axis,value):
    retDataSet =[]
    for featVec in dataSet:
        if featVec[axis] == value:
            # 从数据元组去掉该特征值
            reduceFeatVec =featVec[:axis]
            reduceFeatVec.extend(featVec[axis+1:])
            retDataSet.append(reduceFeatVec)
    return retDataSet
  • 选择最好的数据集划分方法
#选择最好的数据集划分方式
def chooseBestFeatureToSplit(dataSet):
    #计算列数得到特征数
    numFeatures = len(dataSet) - 1
    baseEntropy = calcShannonEnt(dataSet)
    bestInfoGain = 0.0
    bestFeatures = -1
    for i in range(numFeatures):
        #循环取出dataset的元组,然后取出元组中的第i列的所有取值
        featList = [example[i] for example in dataSet]
        uniqueVals = set(featList)
        #计算每个特征的所有特征值作为划分子节点时的熵
        for values 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
            bestFeatures = i
    return bestFeatures
  • 数据具有多个标签时如何处理?
    • 采用多数表决的方法决定该子节点的分类
#当出现多个类标签结果时,采用投票表决的方法决定最终类标签
def majorityCnt(classList):
    classCount = {}
    for vote in classList:
        if vote not in classCount.keys():
            classCount[vote]=0
        classCount[vote] += 1
        sortedClassCount = sorted(classCount.items(),key=operator.itemgetter(i),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
  • 使用前面构造好的算法得到决策树,对测试数据执行分类:
#使用决策树执行分类
#输入:决策树,特征表,测试数据
def classify(inputTree, feaLabels, testVec):
    #取出第一个键值,即根
    firstStr = inputTree.keys()[0]
    #获得根对应的子节点
    secondDict = inputTree[firstStr]
    #找到第一个键值在实际数据存储中的列位置
    featIndex = feaLabels.index(firstStr)
    for key in secondDict.keys():
        #找到下一步要到达的节点
        if testVec[featIndex]==key:
            if type(secondDict[key])._name_== 'dict':
                classLabel=classify(secondDict[key],feaLabels,testVec)
            else:
                classLabel=secondDict[key]
    return classLabel
  • 如何存储决策树?使用pickle包,pickle提供了一个简单的持久化功能。可以将对象以文件的形式存放在磁盘上。
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)

你可能感兴趣的:(决策树)