(学习笔记)机器学习:决策树

决策树

简介:决策树的原理与游戏 ‘20个问题’ 类似,用户输入一系列数据,然后给出结论。

下面给出5数据,后面程序测试数据以此为例

以 ‘能否不浮出水面生存’ 和 ‘是否有脚蹼’ 两个特性判断 该生物是否是鱼


------No surfacing?--------Flippers?-----------Fish?--------

  1. ----Yes -----------------Yes --------------Yes ---------
  2. ----Yes -----------------Yes --------------Yes --------
  3. ----Yes -----------------No ---------------No --------
  4. ----No ------------------Yes --------------No --------
  5. ----No ------------------No ---------------No ----------

下图为流程图形式的决策树

在这里插入图片描述

决策树的特性

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

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

适用数据类型:数值型,标称型。

一些补充概念

  1. 信息增益:在划分数据集之前之后,信息发生的变化。

  2. 信息增益的用处:知道如何计算信息增益,就可以计算每个特征值划分数据集获得的信息增益,从而知道获得最高信息增益的特征。

  3. 熵(香农熵):定义为信息的期望值。

#熵的公式

        H(X)=−∑p(xi)log(p(xi))    (i=1,2,…,n)

其中X 表示的是随机变量,随机变量的取值为(x1,x2,…,xn) ,p({x_i}) 表示事件xi发生的概率,且有∑p(xi)=1 。信息熵的单位为bit。

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) #log base 2
    return shannonEnt

可以创建函数,自输入数据测试一下上面的代码

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

划分数据集

通过度量划分数据集的熵,可以判断当前是否正确的划分了数据集

#按照给定特征划分数据集
#三个参数分别代表:‘带划分的数据集’,‘划分数据集的特征’,‘需要返回的特征的值’
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 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 

-#代码中两个if语句是递归的两个停止条件,分别为 ‘所有标签完全相同’ 和 ‘遍历完所有特征后仍然不能将数据集划分为仅包含唯一类别的分组’

#由于第二个退出递归条件无法简单的返回唯一的类标签,使用majorityCnt函数返回出现次数最多的类别

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]

《Machine Learning in Action》 - Peter Harrington

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值