机器学习实践之决策树算法学习

蓝色之旅 蓝色之旅     2022-10-06     318

关键词:

关于本文说明,本人原博客地址位于http://blog.csdn.net/qq_37608890,本文来自笔者于2017年12月06日 18:06:30所撰写内容(http://blog.csdn.net/qq_37608890/article/details/78731169)。

 

  本文根据最近学习机器学习书籍 网络文章的情况,特将一些学习思路做了归纳整理,详情如下.如有不当之处,请各位大拿多多指点,在此谢过.

一、决策树(decision tree)概述

1、决策树概念

       决策树(decision tree)是一个树结构(可以是二叉树或非二叉树)。其每个非叶节点表示一个特征属性上的测试,每个分支代表这个特征属性在某个值域上的输出,而每个叶节点存放一个类别。使用决策树进行决策的过程就是从根节点开始,测试待分类项中相应的特征属性,并按照其值选择输出分支,直到到达叶子节点,将叶子节点存放的类别作为决策结果。

2 工作原理

      在构造决策树时,需要解决的第一个问题就是,当前数据集上哪个特征在划分数据分类时起到来决定性的作用。为了找到决定性的特征,我们需要对每个特征都要进行评估.完成测试后,原始数据就被划分为几个数据子集.这些数据子集会分布在第一个决策点的所有分支上.若某一分支下的数据属于同一类型,则当前无需阅读的垃圾邮件已经被正确地划分数据分类,没必要再对数据集进行分类.否则,则需要重复划分数据子集的过程.这里划分子集的算法和划分原始数据集的方法相同,直至所有具有相同类型的数据都进入一个数据子集内.构造决策树伪代码函数createBranch()如下:

 

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

        一旦我们构造了一个决策树模型,以它为基础来进行分类将是非常容易的。具体做法是,从根节点开始,对实例的某一特征进行测试,根据测试结构将实例分配到其子节点(也就是选择适当的分支);沿着该分支可能达到叶子节点或者到达另一个内部节点时,那么就使用新的测试条件递归执行下去,直到抵达一个叶子节点。当到达叶子节点时,我们便得到了最终的分类结果。下面介绍一个小例子。

    通俗来说,决策树分类的思想类似于找对象。现想象一个女孩的母亲要给这个女孩介绍男朋友,于是有了下面的对话:

女儿:多大年纪了?
母亲:26。
女儿:长的帅不帅?
母亲:挺帅的。
女儿:收入高不?
母亲:不算很高,中等情况。
女儿:是公务员不?
母亲:是,在税务局上班呢。
女儿:那好,我去见见。


      这个女孩的决策过程就是典型的分类树决策。相当于通过年龄、长相、收入和是否公务员对将男人分为两个类别:见和不见。假设这个女孩对男人的要求是:30岁以下、长相中等以上并且是高收入者或中等以上收入的公务员,那么这个可以用下图表示女孩的决策逻辑:

 

技术分享图片

        上图完整表达了这个女孩决定是否见一个约会对象的策略,其中绿色节点表示判断条件,橙色节点表示决策结果,箭头表示在一个判断条件在不同情况下的决策路径,图中红色箭头表示了上面例子中女孩的决策过程。
这幅图基本可以算是一颗决策树,说它“基本可以算”是因为图中的判定条件没有量化,如收入高中低等等,还不能算是严格意义上的决策树,如果将所有条件量化,则就变成真正的决策树了。

3、决策树的相关特性

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

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

  •    使用数据类型: 数值型和标称型。

4、 一般流程

    (1) 收集数据: 可以使用任何方法.

    (2) 准备数据: 构造算法只适用于标称型数据,因此数值型数据必须离散化.

    (3) 分析数据: 可以使用任何方法,构造树完成之后,应该检查图形是否符合预期.

    (4) 训练算法: 构造树的数据结构.

    (5) 测试算法: 使用经验树计算错误率.

    (6) 使用算法: 此步骤可以适用于任何监督学习算法,而使用决策树可以更好地理解数据的内在含义.

 

二 决策树场景

       假设,现在有一个叫做 "十五个问题" 的游戏,游戏的规则很简单:参与游戏的一方在脑海中想某个事物,其他参与者向他提问,只允许提 15个问题,问题的答案也只能用对或错回答。问问题的人通过推断分解,逐步缩小待猜测事物的范围,最后得到游戏的答案。决策树的工作原理与15个问题类似,用户输入一系列数据后给出游戏答案。

      下图给出了一个假想的邮件分类系统,它首先检测发送邮件域名.如果地址为myEmployer.com,则将其放在"无聊时需要阅读的邮件"中。否则,则需要检查邮件内容中是否包含单词 曲棍球 ,若包含则将邮件归入"需要及时处理的朋友邮件",否则则归类到"无需阅读的垃圾邮件"。

 

    技术分享图片

 

   决策树一个很重要的任务就是为了理解数据中所蕴含的知识信息(这与K-近邻算法无法给出数据的内在含义有着显著不同),因此决策树可以使用不熟悉的数据集合,并从中提取出一系列规则,这些机器根据数据集创建规则的过程,就是机器学习的过程。

三 决策树项目案例一  对海洋生物进行鱼和非鱼判断

1 项目情况

      下表中的数据包含5个海洋生物,特征: 不浮出水面是否可以生存和是否有脚蹼.现将动物划分为两类: 鱼和非鱼.如果想依据给出的特征选出一个来划分数据,就涉及到要将划分数据的依据进行量化后才可以判断出来.

   技术分享图片 

  我们先构造进行数据输入的createDataSet()函数和计算给定数据集的香农熵函数calcShannonEnt()

   

    def createDataSet():  
        dataSet = [[1,1,‘yes‘],  
                  [1,1,‘yes‘],  
                  [1,0,‘no‘],  
                  [0,1,‘no‘],  
                  [0,1,‘no‘]]  
        labels=[‘no surfacing‘,‘flippers‘]  
        # change to discrete values  
        return dataSet,labels  
    #信息增益  
    #计算给定数据的香农熵  
      
    def calcShannonEnt(dataSet): #the the number of unique elements and their occurance  
        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.00000  
        for key in labelCounts:  
            prob = float(labelCounts[key]) /numEntries  
            shannonEnt -= prob * log(prob,2)   #log base 2  
              
        return shannonEnt  

 

 执行

    myDat,labels=createDataSet()  
    myDat  

 得到 

[[1, 1, ‘yes‘], [1, 1, ‘yes‘], [1, 0, ‘no‘], [0, 1, ‘no‘], [0, 1, ‘no‘]]

 执行

calcShannonEnt(myDat)  

得到

0.9709505944546686

熵越高,则混合的数据越多,我们可用在数据集中添加更多的分类,观察熵是如何变化的.

按照给定特征划分数据集,将指定特征的特征值等于 value 的行剩下列作为子数据集。

 

    def splitDataSet(dataSet, index, value):  
        """splitDataSet(通过遍历dataSet数据集,求出index对应的colnum列的值为value的行) 
            就是依据index列进行分类,如果index列的数据等于 value的时候,就要将 index 划分到我们创建的新的数据集中 
        Args: 
            dataSet 数据集                 待划分的数据集 
            index 表示每一行的index列        划分数据集的特征 
            value 表示index列对应的value值   需要返回的特征的值。 
        Returns: 
            index列为value的数据集【该数据集需要排除index列】 
        """  
        retDataSet = []  
        for featVec in dataSet:   
            # index列为value的数据集【该数据集需要排除index列】  
            # 判断index列的值是否为value  
            if featVec[index] == value:  
                # chop out index used for splitting  
                # [:index]表示前index行,即若 index 为2,就是取 featVec 的前 index 行  
                reducedFeatVec = featVec[:index]  
                ‘‘‘‘‘ 
                请百度查询一下: extend和append的区别 
                list.append(object) 向列表中添加一个对象object 
                list.extend(sequence) 把一个序列seq的内容添加到列表中 
                1、使用append的时候,是将new_media看作一个对象,整体打包添加到music_media对象中。 
                2、使用extend的时候,是将new_media看作一个序列,将这个序列和music_media序列合并,并放在其后面。 
                result = [] 
                result.extend([1,2,3]) 
                print result 
                result.append([4,5,6]) 
                print result 
                result.extend([7,8,9]) 
                print result 
                结果: 
                [1, 2, 3] 
                [1, 2, 3, [4, 5, 6]] 
                [1, 2, 3, [4, 5, 6], 7, 8, 9] 
                ‘‘‘  
                reducedFeatVec.extend(featVec[index+1:])  
                # [index+1:]表示从跳过 index 的 index+1行,取接下来的数据  
                # 收集结果值 index列为value的行【该行需要排除index列】  
                retDataSet.append(reducedFeatVec)  
        return retDataSet  

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

 

    def chooseBestFeatureToSplit(dataSet):  
        """chooseBestFeatureToSplit(选择最好的特征) 
     
        Args: 
            dataSet 数据集 
        Returns: 
            bestFeature 最优的特征列 
        """  
        # 求第一行有多少列的 Feature, 最后一列是label列嘛  
        numFeatures = len(dataSet[0]) - 1  
        # 数据集的原始信息熵  
        baseEntropy = calcShannonEnt(dataSet)  
        # 最优的信息增益值, 和最优的Featurn编号  
        bestInfoGain, bestFeature = 0.0, -1  
        # iterate over all the features  
        for i in range(numFeatures):  
            # create a list of all the examples of this feature  
            # 获取对应的feature下的所有数据  
            featList = [example[i] for example in dataSet]  
            # get a set of unique values  
            # 获取剔重后的集合,使用set对list数据进行去重  
            uniqueVals = set(featList)  
            # 创建一个临时的信息熵  
            newEntropy = 0.0  
            # 遍历某一列的value集合,计算该列的信息熵   
            # 遍历当前特征中的所有唯一属性值,对每个唯一属性值划分一次数据集,计算数据集的新熵值,并对所有唯一特征值得到的熵求和。  
            for value in uniqueVals:  
                subDataSet = splitDataSet(dataSet, i, value)  
                # 计算概率  
                prob = len(subDataSet)/float(len(dataSet))  
                # 计算信息熵  
                newEntropy += prob * calcShannonEnt(subDataSet)  
            # gain[信息增益]: 划分数据集前后的信息变化, 获取信息熵最大的值  
            # 信息增益是熵的减少或者是数据无序度的减少。最后,比较所有特征中的信息增益,返回最好特征划分的索引值。  
            infoGain = baseEntropy - newEntropy  
            print ‘infoGain=‘, infoGain, ‘bestFeature=‘, i, baseEntropy, newEntropy  
            if (infoGain > bestInfoGain):  
                bestInfoGain = infoGain  
                bestFeature = i  
        return bestFeature  

 

训练算法:构造树的数据结构

  创建树的函数

    def createTree(dataSet, labels):  
        classList = [example[-1] for example in dataSet]  
        # 如果数据集的最后一列的第一个值出现的次数=整个集合的数量,也就说只有一个类别,就只直接返回结果就行  
        # 第一个停止条件:所有的类标签完全相同,则直接返回该类标签。  
        # count() 函数是统计括号中的值在list中出现的次数  
        if classList.count(classList[0]) == len(classList):  
            return classList[0]  
        # 如果数据集只有1列,那么最初出现label次数最多的一类,作为结果  
        # 第二个停止条件:使用完了所有特征,仍然不能将数据集划分成仅包含唯一类别的分组。  
        if len(dataSet[0]) == 1:  
            return majorityCnt(classList)  
      
        # 选择最优的列,得到最优列对应的label含义  
        bestFeat = chooseBestFeatureToSplit(dataSet)  
        # 获取label的名称  
        bestFeatLabel = labels[bestFeat]  
        # 初始化myTree  
        myTree = {bestFeatLabel: {}}  
        # 注:labels列表是可变对象,在PYTHON函数中作为参数时传址引用,能够被全局修改  
        # 所以这行代码导致函数外的同名变量被删除了元素,造成例句无法执行,提示‘no surfacing‘ is not in list  
        del(labels[bestFeat])  
        # 取出最优列,然后它的branch做分类  
        featValues = [example[bestFeat] for example in dataSet]  
        uniqueVals = set(featValues)  
        for value in uniqueVals:  
            # 求出剩余的标签label  
            subLabels = labels[:]  
            # 遍历当前选择特征包含的所有属性值,在每个数据集划分上递归调用函数createTree()  
            myTree[bestFeatLabel][value] = createTree(splitDataSet(dataSet, bestFeat, value), subLabels)  
            # print ‘myTree‘, value, myTree  
        return myTree  

   测试算法:使用决策树执行分类

 

    def classify(inputTree, featLabels, testVec):  
        """classify(给输入的节点,进行分类) 
     
        Args: 
            inputTree  决策树模型 
            featLabels Feature标签对应的名称 
            testVec    测试输入的数据 
        Returns: 
            classLabel 分类的结果值,需要映射label才能知道名称 
        """  
        # 获取tree的根节点对于的key值  
        firstStr = inputTree.keys()[0]  
        # 通过key得到根节点对应的value  
        secondDict = inputTree[firstStr]  
        # 判断根节点名称获取根节点在label中的先后顺序,这样就知道输入的testVec怎么开始对照树来做分类  
        featIndex = featLabels.index(firstStr)  
        # 测试数据,找到根节点对应的label位置,也就知道从输入的数据的第几位来开始分类  
        key = testVec[featIndex]  
        valueOfFeat = secondDict[key]  
        print ‘+++‘, firstStr, ‘xxx‘, secondDict, ‘---‘, key, ‘>>>‘, valueOfFeat  
        # 判断分枝是否结束: 判断valueOfFeat是否是dict类型  
        if isinstance(valueOfFeat, dict):  
            classLabel = classify(valueOfFeat, featLabels, testVec)  
        else:  
            classLabel = valueOfFeat  
        return classLabel  

 

 

三  项目案例2: 使用决策树预测隐形眼镜类型

项目概述

隐形眼镜类型包括硬材质、软材质以及不适合佩戴隐形眼镜。我们需要使用决策树预测患者需要佩戴的隐形眼镜类型。
开发流程

(1)收集数据: 提供的文本文件。
(2)解析数据: 解析 tab 键分隔的数据行
(3)分析数据: 快速检查数据,确保正确地解析数据内容,使用 createPlot() 函数绘制最终的树形图。
(4)训练算法: 使用 createTree() 函数。
(5)测试算法: 编写测试函数验证决策树可以正确分类给定的数据实例。
(6)使用算法: 存储树的数据结构,以便下次使用时无需重新构造树。

收集数据:提供的文本文件

文本文件数据格式如下:

  

young   myope   no  reduced no lenses  
pre myope   no  reduced no lenses  
presbyopic  myope   no  reduced no lenses 

 

  解析数据:解析 tab 键分隔的数据行

    lecses = [inst.strip().split(‘	‘) for inst in fr.readlines()]  
    lensesLabels = [‘age‘, ‘prescript‘, ‘astigmatic‘, ‘tearRate‘]  

 

分析数据:快速检查数据,确保正确地解析数据内容,使用 createPlot() 函数绘制最终的树形图。

treePlotter.createPlot(lensesTree)  

 
训练算法:使用 createTree() 函数

 

    >>> lensesTree = trees.createTree(lenses, lensesLabels)  
    >>> lensesTree  

 

 
得到

 

    {‘tearRate‘: {‘reduced‘: ‘no lenses‘, ‘normal‘: {‘astigmatic‘:{‘yes‘:  
    {‘prescript‘:{‘hyper‘:{‘age‘:{‘pre‘:‘no lenses‘, ‘presbyopic‘:  
    ‘no lenses‘, ‘young‘:‘hard‘}}, ‘myope‘:‘hard‘}}, ‘no‘:{‘age‘:{‘pre‘:  
    ‘soft‘, ‘presbyopic‘:{‘prescript‘: {‘hyper‘:‘soft‘, ‘myope‘:  
    ‘no lenses‘}}, ‘young‘:‘soft‘}}}}}  

 

 

五 小结

其实决策树跟带终止块的流程图类似,所以这里的终止块就是分类结果.当我们进行数据处理时,首先要对集合中数据的不一致性进行测量评估,也就是计算香农熵,下一步才可以寻找最有方案划分数据,最终实现所有具有相同类型的数据都划分到同一个数据子集里面.在构建数据树时,我们一般采用递归方把数据集转化为决策树.多数情况下,我们不构造新的数据结构,而是采用Python语言内嵌的数据结构字典存储树节点信息.每一步选择信息增益最大的特征作为决策块,最终来完成决策树的生成.


Matplotlib的注解功能,可以让将存储的树结构转化为容易理解的图形.隐形眼镜的例子说明决策树可能会产生过多的数据集划分,结果导致过度匹配数据集的问题.当然可以通过裁剪决策树,合并相邻的不能产生信息增益的叶节点,来解决这个问题(过度匹配).


关于决策树的构造算法,这里本文只是用了ID3算法,当然还有C4.5和CART算法.对于决策树的完整工作过程而言,包括三部分:


1 特征选择;


2 生成决策树;


3 剪枝部分


而除去ID3算法,其他两个算法都有剪枝部分过程.所以这也迎合来隐形眼镜过拟合的问题.

  关于决策树部分,笔者先整理到这里,后续有机会会针对C4.5和CART算法做些归纳整理.有不足之处,请各位同仁多多指导.



















































机器学习算法实践:决策树(decisiontree)(转载)

  前言     最近打算系统学习下机器学习的基础算法,避免眼高手低,决定把常用的机器学习基础算法都实现一遍以便加深印象。本文为这系列博客的第一篇,关于决策树(DecisionTree)的算法实现,文中我将对决策树种... 查看详情

常见机器学习算法原理+实践系列4(决策树)

决策树分类决策树算法借助于树的分支结构实现分类,决策树在选择分裂点的时候,总是选择最好的属性作为分类属性,即让每个分支的记录的类别尽可能纯。常用的属性选择方法有信息增益(InformationGain),增益比例(gainratio... 查看详情

机器学习算法之决策树

一.简介  决策树的一个重要任务是理解数据中蕴含的知识信息。    决策树优点:计算复杂度不高,输出结果易于理解,对中间值的缺失不敏感,可以处理不相关特征数据。    缺点:可能产生过... 查看详情

机器学习入门之决策树算法

1、什么是决策树(DecisionTree)       决策树是一个类似于流程图的树结构,其中每一个树节点表示一个属性上的测试,每一个分支代表一个属性的输出,每一个树叶节点代表一个类或者类的分布,树的... 查看详情

ml之监督学习算法之分类算法一————决策树算法

...用不熟悉的数据集合,并从中提取出一系列规则,在这些机器根据数据创建规则时,就是机器学习的过程。二、决策树的构造  决策树:    优点:计算复杂度不高,输出结果易于理解,对中间值的缺失不敏感,可以处理... 查看详情

机器学习实战之第三章决策树(decisiontree)

第3章决策树<scripttype="text/javascript"src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=default"></script>决策树概述决策树(DecisionTree)算法主要用来处理分类问题,是最经常使用的数据挖掘算法之一。决策树场景一个叫做"二十... 查看详情

sparkmllib分类算法之决策树学习

...种决策分支画成图形很像一棵树的枝干,故称决策树。在机器学习中,决策树是一个预测模型,他代表的是对象属性与对象值之间的一种映射关系。 查看详情

开始学习机器学习时你必须要了解的模型有哪些?机器学习系列之决策树进阶篇(代码片段)

前言在上一篇文章中我们已经详细介绍了决策树模型,并且提到了ID3算法及其局限性,那么在本篇文章中,我们将会介绍基于ID3算法进行改良的C4.5算法以及决策树拟合度的优化问题。目录前言1C4.5算法1.1修改局部最优... 查看详情

361机器学习常见算法

K-近邻算法(KNearestNeighbors)参考:机器学习实战教程(一):K-近邻算法(史诗级干货长文)决策树算法(DecisionTree)参考:机器学习实战教程(二):决策树基础篇之让我们从相亲说起参考:机器学习实战教程(三):决策树... 查看详情

机器学习中的算法:决策树模型组合之gbdt(gradientboostdecisiontree)

【转载自:http://www.cnblogs.com/LeftNotEasy/archive/2011/03/07/random-forest-and-gbdt.html】 前言   决策树这种算法有着很多良好的特性,比如说训练时间复杂度较低,预测的过程比较快速,模型容易展示(容易将得到的决策树做... 查看详情

机器学习中的算法——决策树模型组合之随机森林与gbdt

前言:决策树这种算法有着很多良好的特性,比如说训练时间复杂度较低,预测的过程比较快速,模型容易展示(容易将得到的决策树做成图片展示出来)等。但是同时,单决策树又有一些不好的地方,比如说容易over-fitting,虽... 查看详情

机器学习决策树理论第二卷

决策树内容来至于《统计学习与方法》李航,《机器学习》周志华,以及《机器学习实战》PeterHarringTon,相互学习,不足之处请大家多多指教!本卷的大纲为1CART算法1.1CART回归树1.2CART分类树2CART剪枝3总结1CART算法CART分类与回归树(classi... 查看详情

郑捷《机器学习算法原理与编程实践》学习笔记(第三章决策树的发展)_scikit-learn与回归树

  (上接第三章)   3.4Scikit-Learn与回归树  3.4.1回归算法原理  在预测中,CART使用最小剩余方差(squaredResidualsMinimization)来判断回归时的最优划分,这个准则期望划分之后的子树与样本点的误差方差最小。这样决策... 查看详情

机器学习中的算法-决策树模型组合之随机森林与gbdt

版权声明:   本文由LeftNotEasy发布于http://leftnoteasy.cnblogs.com,本文可以被全部的转载或者部分使用,但请注明出处,如果有问题,请联系[email protected]。也可以加我的微博: @leftnoteasy 前言:   决策... 查看详情

机器学习中的算法-决策树模型组合之随机森林与gbdt

版权声明:   本文由LeftNotEasy发布于http://leftnoteasy.cnblogs.com,本文可以被全部的转载或者部分使用,但请注明出处,如果有问题,请联系[email protected] 前言:   决策树这种算法有着很多良好的特性,... 查看详情

决策树算法之鸢尾花特征分类可视化详解机器学习(代码片段)

...分类决策树算法可视化效果图如下:决策树是一种常用的机器学习方法,它可以帮助我们解决分类和回归问题。该模型具有高度的可解释性。该模型符合人类的思维方式,是一种经典的树形结构。熵:香农用“下降”一词来表示... 查看详情

机器学习笔记之三cart分类与回归树

本文结构:CART算法有两步回归树的生成分类树的生成剪枝CART-ClassificationandRegressionTrees分类与回归树,是二叉树,可以用于分类,也可以用于回归问题,最先由Breiman等提出。分类树的输出是样本的类别,回归树的输出是一个实... 查看详情

机器学习笔记之四adaboost算法

本文结构:什么是集成学习?为什么集成的效果就会好于单个学习器?如何生成个体学习器?什么是Boosting?Adaboost算法?什么是集成学习集成学习就是将多个弱的学习器结合起来组成一个强的学习器。这就涉及到,先产生一组&lsq... 查看详情