决策树

基本概念和公式

  • 信息
  • 信息熵
    度量样本集合纯度最常用的一种指标:
    在这里插入图片描述
    Ent(D)值越小,则D纯度越高
  • 信息增益
    在这里插入图片描述
    (信息增益标准对可取数目较多的属性有所偏好)
  • 信息增益率
    在这里插入图片描述
    (信息增益率标准对可取数目较少的属性有所偏好)
    (C4.5采取的策略是,先从候选属性中找出信息增益高于平均值的属性,再从中选择增益率最高的)
  • 基尼指数
    基尼值:
    反映从数据集D中随机抽取两个样本,其类别标志不一致的概率
    在这里插入图片描述
    Gini(D)越小,数据集D的纯度越高
    属性a的基尼指数:
    在这里插入图片描述
  • 剪枝处理
    剪枝处理是对付过拟合的一种方法。
    预剪枝:
    在决策树生成过程中,对每个节点在划分前后进行估计,若当前节点划分不能带来决策树泛化性能的提升(即:训练集精度提升),则停止划分当前结点,并将当前节点作为叶子节点。
    后剪枝:
    从训练集中生成一棵完整的决策树,然后对节点(子节点都是叶节点)进行剪枝,若剪枝后决策树的泛化能力比未剪枝前好,则将此节点剪掉,作为叶节点,叶节点的标记为所有包含的样本中个数最多的标记。
    两种剪枝方法的比较:
    后剪枝保留了更多的分支,欠拟合风险小,但训练时间开销更大。
  • 连续值处理
    候选划分点集合:
    T_a={(ai+a(i+1))/2|1≤i≤n-1}
    根据信息增益公式:
    在这里插入图片描述
    计算每个划分集合的点划分出来的信息增益值,然后选择信息增益值最大的点作为最佳划分点。
  • 缺失值的处理
    样本集在属性a上没有缺失的集合记为,权重Wx。
    在这里插入图片描述
    在这里插入图片描述
    若样本在属性a上的值缺失,则同时将样本华人与所有子节点,权值设为R*W

决策树的代码实现

  • 香农公式的代码实现
from math import log


def calcshannonEnt(dataset):
    numData =len(dataset)
    featVect = {}
    calcshannon = 0.0
    for data in dataset:
        label =data[-1]
        if  label not in featVect.keys():
            featVect[label] = 0
        featVect[label] +=1
    for i in featVect.keys():
        sublabels =featVect[i]
        p = float(sublabels)/numData
        calcshannon -= p*log(p, 2)
    return calcshannon


  • 数据集的代码实现
def createDataSet():
    data = [
        [1, 1, 'yes'],
        [1, 1, 'yes'],
        [1, 0, 'no'],
        [0, 1, 'no'],
        [0, 1, 'no']
    ]
    labels = ['no surfacing', 'flippers']
    return data, labels

  • 划分数据集
# coding=utf-8
#划分数据集
def splitDataSet(dataset, axis, value):
    newDataSet = []
    for data in dataset:
        feature = data[axis]
        if feature == value:
            addFeat = data[:axis]
            addFeat.extend(data[axis+1:])
            newDataSet.append(addFeat)
    return newDataSet

  • 找最好的特征对数据集进行划分
# coding=utf-8
#信息增益最大即为最好特征
from calcshannonEnt import *
from splitDataSet import *


def chooseBestFeaturetoSplit(dataset):
    numFeature = len(dataset[0])-1
    baseCalcshannon = calcshannonEnt(dataset)
    bestInfoGain = 0.0
    bestFeature = -1
    for i in range(numFeature):
        numFeatureValue = [example[i] for example in dataset]
        uniqueValue = set(numFeatureValue)
        currentCalcshannon = 0.0
        for value in uniqueValue:
            subData = splitDataSet(dataset, i, value)
            p = float(len(subData))/len(dataset)
            currentCalcshannon += p*calcshannonEnt(subData)
        infoGain = baseCalcshannon - currentCalcshannon
        if infoGain>bestInfoGain:
            bestInfoGain = infoGain
            bestFeature = i
    return bestFeature



  • 构造决策树
# coding=utf-8
"""决策树创建设计递归过程"""
from chooseBestFeaturetoSplit import *
from majority import *


def createTree(dataset,labels):
    #递归出口:样本所有分类标签一致,所有特征值考察完毕
    labelsValue = [example[-1] for example in dataset]
    if labelsValue.count(labelsValue[0]) == len(labelsValue):
        return labelsValue[0]
    if len(dataset
           [0]) == 1:
        return majority(dataset)
    bestFeature = chooseBestFeaturetoSplit(dataset)
    featureLabels = labels[bestFeature]
    myTree = {featureLabels: {}}
    del(labels[bestFeature])
    valueVect = [example[bestFeature] for example in dataset]
    uniqueVect = set(valueVect)
    for value in uniqueVect:
        subLabel = labels[:]
        myTree[featureLabels][value] = createTree(splitDataSet(dataset, bestFeature, value), subLabel)
    return myTree

确定同一类别中叶节点的标签

import  operator


def majority(dataset):
    label = [example[-1] for example in dataset]
    uniqueLabel = set(label)
    labelList = {}
    for data in dataset:
        subLabel =data[-1]
        if subLabel not in labelList:
            labelList[subLabel] = 0
        labelList[subLabel] +=1
    labelCount = sorted(labelList.iteritems(), key=operator.itemgetter(1), reverse=True)
    return labelCount[0][0]
  • 确定测试数据标签
from createTree import *


def classify(myTree,labels,testVect):
    firstStr = myTree.keys()
    secondStr = myTree.keys()[0]
    labelsIndex = labels.index(firstStr)
    for i in secondStr:
        subValue = i.keys()
        if testVect == subValue:
            if subValue.__name__ == 'dict':
                classify(subValue,labels,testVect)
            else:
                return subValue

将决策树程序存储起来

import pickle


def storeTree(tree, filename):
    fw = open(filename, 'w')
    pickle.dump(tree, fw)
    fw.close()


def grapTree(filename):
    fr = open(filename)
    return pickle.load(fr)

决策树优缺点

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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章