机器学些技法(9)--Decision Tree

国庆过完,继续干活~

下面总结了几个ensemble的模型的本质,顺便调出决策树的概念:

在不同的情形下,用不同的g的一种方式。

蓝色的部分是leaf,也就是base hypothesis。

内部决策的过程叫做node。通常是很简单的决定。

或者:

递回的概念,一棵树可以用其他的几棵树来代表。

决策树的优缺点:

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

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

伪代码:

检测数据集中的每一个子项书否属于同一分类:
    if so return 类标签;
    else
        寻找划分数据集的最好特征
        划分数据集
        创建分支节点
            for 每个划分的子集
            调用函数并增加返回结果到分支节点中
        return 分支节点

决策树演算法的大概思路:

当然还需要考虑递回式的停止条件:

下面重点介绍CART演算法:

每次做判断只做二元的分类;

选择判断的条件是进过划分后的数据更加纯了。(y一或者y很接近)

那么纯度又如何进行计算呢?

把切开两块的综合的纯度进行考量,所谓综合就是进行加权。就是两边的不纯度的加权相加,进行最小化的优化。

下面是决策树停止的条件:

当分无可分的时候,就会被迫停下来,就叫fully grown tree。然而在这个时候,过拟合就不可避免的发生了。

所以我们需要剪枝这个动作来做一些正则化的事情。模型的复杂度的衡量可以用树叶的数量来进行。

剪掉不同的叶子的数量中做一个最好的选择。 

当出现missing value的时候:

要么想办法补齐这个missing的值,要么使用其他的可替代的feature来进行切割。

总结:

代码:

#计算给定数据集的香农熵
from math import log
def calShannonEnt(dataSet):
    numEntries = len(dataSet)
    #为所有可能的分类创建字典
    labelCounts = {}
    for featVec in dataSet:
        #字典的键值是最后一列的数值
        currentLabel = featVec[-1]
        #如果当前键值不存在,则拓展字典,将当前键值加入字典
        if currentLabel not in labelCounts.keys():
            lableCounts[currentLabel] = 0
        #每个键值都记录了当前类别出现的次数
        lableCounts[currentLabel] += 1
    shannonEnt = 0.0
    #最后,使用所有类标签的发生频率计算类别出现的概率,我们将用这个概率计算香农熵
    for key in lableCounts:
        prob = float(lableCounts[key])/numEntries
        shannonEnt -= prob * log(prob,2)
    return shannonEnt
#按照给定特征划分数据集
#使用了三个输入参数:待划分的数据集,划分数据集的特征,需要返回值的特征
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 = calShannonEnt(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 * calShannonEnt(subDataSet)
        infoGain = baseEntropy - newEntropy
        #比较所有特征中的信息增益,返回最好的特征划分的索引值
        if (infoGain > bestInfoGain):
            bestInfoGain = infoGain
            bestFeature = i
    return bestFeature
#创建树的函数代码
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)
    bestFestLabel = labels[bestFeat]
    #开始创建树
    myTree = {bestFestLabel:{}}
    del(labels[bestFeat])
    featValues = [example[bestFest] for eample in dataSet]
    uniqueVals = set(featValues)
    for value in uniqueVals:
        subLabels = labels[:]
        myTree[bestFestLabel][value] = createTree(splitDataSet(dataSet,bestFeat,value),subLabels)
    return myTree
            

 

posted @ 2016-10-08 13:48  cyoutetsu  阅读(263)  评论(0编辑  收藏  举报