zoukankan      html  css  js  c++  java
  • 机器学习笔记(二)之决策树

    机器学习之决策树

    基本概念

    决策树算法是机器学习中一个非常经典的算法,既能够解决分类问题,也能够解决回归问题。
    一般的,一颗决策树包含一个根节点、若干个内部结点和若干个叶子节点;叶子结点对应于决策结果,其他的结点则对应一个属性测试,每个结点包含的样本集合根据属性测试的结果被划分到子节点中。根节点包含样本全集,从根结点到每一个叶子节点表示的是一个判定结果。决策树学习的目的是为了产生一颗泛化能力强的得决策树。

    决策树案例

    这里写图片描述
    图1

    图 1 是一棵结构简单的决策树,用于预测贷款用户是否具有偿还贷款的能力。贷款用户主要具备三个属性:是否拥有房产,是否结婚,平均月收入。每一个内部节点都表示一个属性条件判断,叶子节点表示贷款用户是否具有偿还能力。例如:用户甲没有房产,没有结婚,月收入 5K。通过决策树的根节点判断,用户甲符合右边分支 (拥有房产为“否”);再判断是否结婚,用户甲符合左边分支 (是否结婚为否);然后判断月收入是否大于 4k,用户甲符合左边分支 (月收入大于 4K),该用户落在“可以偿还”的叶子节点上。所以预测用户甲具备偿还贷款能力。

    基本算法流程

    这里写图片描述
    一般流程
    1. 收集数据:可以使用任何方法。
    2. 准备数据:树构造算法只适用于标称型数据,因此数据类型鼻血离散化。
    3. 分许数据:可以使用任何方法,属构造完成之后,我们应该检查图形是否符合预期
    4. 训练数据:构造输的数据结构。
    5. 测试数据:利用经验树计算错误率。
    6. 使用算法:此步骤适用于任何监督学习算法,而使用决策树能够更好的理解数据的内在含义。

    决策树的优点与缺点

    优点:计算复杂度不高,输出结果易于理解,对于中间值缺失不敏感
    缺点:可能产生过度匹配的问题
    适用数据类型:数值型和标称型
    

    注:
    标称型数据:标称型目标变量的结果只在有限目标集中取值,如真与假(标称型目标变量主要用于分类)

    划分选择

    决策树学习的关键在于如何选择最优的划分属性。一般而言,我们希望决策树的分支包含的样本尽可能的属于同一类别。即结点的纯度越来越高

    信息增益

    信息熵是度量样本集合的纯度的一种最常用的指标。熵指的是不确定性的度量而不是确定性的度量。

    信息熵的计算公式

    假定当前样本集合D中第K类样本所占的比率为pk,则D的信息熵定义为
    这里写图片描述
    info(D)的值越小,数据的纯度越高。

    信息增益熵计算

    假定离散属性a有V个可能的取值(a1,a2,a3…av),若使用a对样本D进行划分,则会产生V个分支。其中第v个分支包含了样本D中所有在a属性取值为av的所有样本,记为Dv。根据上面的公式可以计算出Dv的信息熵,给分支结点赋予权值|Dv/D|,所以可以得出样本数越多的分支结点影响越大。因此用a属性对于数据集D进行划分的信息增益为
    这里写图片描述
    信息增益越大,则意味着使用属性a提升的纯度越大。

    下面是用代码实现一个简单的决策树思路

    计算数据集的香农熵

    def calcShannonEnt(dataSet):#计算香农熵
    numEntris = len(dataSet)#求出数据集的长度
    labelCounts = {}# dict变量,保存键值对
    for featVec in dataSet:
        #print(featVec)
        currentLabel = featVec[-1]#表示读取featVec最后一项
        if currentLabel not in labelCounts.keys():#判断currentlabel是否在labelCount的键里面
            labelCounts[currentLabel] = 0#如果不在,统计为0
        labelCounts[currentLabel]+=1#在的情况下就+1
    shannoEnt=0.0
    for key in labelCounts:
        prob = float(labelCounts[key])/numEntris#prob表示该公式出现的概率
        shannoEnt -= prob*log(prob,2)#对应上面的求熵公式
    return shannoEnt
    

    划分数据集

    def splitDataSet(dataSet,axis,value):#
        reDataSet = []
        for featVec in dataSet:
            if featVec[axis] == value:#如果第axia个元素等于value,则将value剔除重新组成数据集
                reduceFeatVec = featVec[:axis]#将featVec从0开始取出axis个值,取括号
                reduceFeatVec.extend(featVec[axis+1:])#从axis+1开始,一直取到最后一个值
                reDataSet.append(reduceFeatVec)#append和extend的区别
        return reDataSet
    

    输入的三个参数分别是:带划分的数据集,划分数据集的特征,需要返回的特征值。
    找到在特征项的值等于value的几项数据,然后将其加入到reDataSet,相当于在原始数据项上面删除了特征项,然后将其他特征值保存到新的数据集reDataSet中
    需要注意一下append和extend的用法
    这里写图片描述

    选择最好的数据集划分方式

    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]#将每一个数据集的第i位取出来
        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 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(1),reverse=True)
        print(sortedClassCount)
    return sortedClassCount[0][0]
    

    然后是利用递归创建决策树

    def createTree(dataSet,labels):
    label_copy=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 = label_copy[bestFeat]
    myTree = {bestFeatLabel: {}}
    del (label_copy[bestFeat])#删除掉出现次数最多的类别的标签
    featValues = [example[bestFeat] for example in dataSet]
    uniqueVals = set(featValues)
    for value in uniqueVals:
        subLabels = label_copy[:]#获取其他的标签,继续进行分类,进行深拷贝
        myTree[bestFeatLabel][value] = createTree(splitDataSet(dataSet, bestFeat, value), subLabels)
    return myTree
    

    利用决策树预测隐形眼镜类型
    提供一个lenses.txt文件,将里面数据图取出来,然后对应生成决策树
    这里写图片描述

    下图是利用递归生成的决策树效果图
    这里写图片描述
    源代码

  • 相关阅读:
    monitor system
    monitor disk
    manage account
    windows
    backup daily
    shell 脚本编程概述
    OGNL表达式
    Struts2各个功能详解(2)-输入校验和拦截器
    struts2各个功能详解(1)----参数自动封装和类型自动转换
    Struts2源码解析2
  • 原文地址:https://www.cnblogs.com/gaot/p/7709690.html
Copyright © 2011-2022 走看看