第3章 决策树

<script type="text/javascript" src=" http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=default"></script >

决策树 概述

决策树(Decision Tree)算法主要用来处理分类问题,是最经常使用的数据挖掘算法之一。

决策树 场景

一个叫做 "二十个问题" 的游戏,游戏的规则很简单:参与游戏的一方在脑海中想某个事物,其他参与者向他提问,只允许提 20 个问题,问题的答案也只能用对或错回答。问问题的人通过推断分解,逐步缩小待猜测事物的范围,最后得到游戏的答案。

一个邮件分类系统,大致工作流程如下:

首先检测发送邮件域名地址。如果地址为 myEmployer.com, 则将其放在分类 "无聊时需要阅读的邮件"中。
如果邮件不是来自这个域名,则检测邮件内容里是否包含单词 "曲棍球" , 如果包含则将邮件归类到 "需要及时处理的朋友邮件",
如果不包含则将邮件归类到 "无需阅读的垃圾邮件" 。

决策树 原理

决策树 须知概念

信息熵 & 信息增益

熵: 熵(entropy)指的是体系的混乱的程度,在不同的学科中也有引申出的更为具体的定义,是各领域十分重要的参量。

信息熵(香农熵): 是一种信息的度量方式,表示信息的混乱程度,也就是说:信息越有序,信息熵越低。例如:火柴有序放在火柴盒里,熵值很低,相反,熵值很高。

信息增益: 在划分数据集前后信息发生的变化称为信息增益。

决策树 工作原理

如何构造一个决策树?
我们使用 createBranch() 方法,如下所示:

检测数据集中的所有数据的分类标签是否相同:If so return 类标签Else:寻找划分数据集的最好特征(划分之后信息熵最小,也就是信息增益最大的特征)划分数据集创建分支节点for 每个划分的子集调用函数 createBranch (创建分支的函数)并增加返回结果到分支节点中return 分支节点

决策树 开发流程

收集数据:可以使用任何方法。
准备数据:树构造算法只适用于标称型数据,因此数值型数据必须离散化。
分析数据:可以使用任何方法,构造树完成之后,我们应该检查图形是否符合预期。
训练算法:构造树的数据结构。
测试算法:使用经验树计算错误率。(经验树没有搜索到较好的资料,有兴趣的同学可以来补充)
使用算法:此步骤可以适用于任何监督学习算法,而使用决策树可以更好地理解数据的内在含义。

决策树 算法特点

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

决策树 项目案例

项目案例1: 判定鱼类和非鱼类

项目概述

根据以下 2 个特征,将动物分成两类:鱼类和非鱼类。

特征:

  1. 不浮出水面是否可以生存
  2. 是否有脚蹼

开发流程

收集数据:可以使用任何方法
准备数据:树构造算法只适用于标称型数据,因此数值型数据必须离散化
分析数据:可以使用任何方法,构造树完成之后,我们应该检查图形是否符合预期
训练算法:构造树的数据结构
测试算法:使用决策树执行分类
使用算法:此步骤可以适用于任何监督学习算法,而使用决策树可以更好地理解数据的内在含义

收集数据:可以使用任何方法

我们利用 createDataSet() 函数输入数据

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 calcShannonEnt(dataSet):# 求list的长度,表示计算参与训练的数据量numEntries = len(dataSet)# 计算分类标签label出现的次数labelCounts = {}# the the number of unique elements and their occurancefor featVec in dataSet:# 将当前实例的标签存储,即每一行数据的最后一个数据代表的是标签currentLabel = featVec[-1]# 为所有可能的分类创建字典,如果当前的键值不存在,则扩展字典并将当前键值加入字典。每个键值都记录了当前类别出现的次数。if currentLabel not in labelCounts.keys():labelCounts[currentLabel] = 0labelCounts[currentLabel] += 1# 对于 label 标签的占比,求出 label 标签的香农熵shannonEnt = 0.0for key in labelCounts:# 使用所有类标签的发生频率计算类别出现的概率。prob = float(labelCounts[key])/numEntries# 计算香农熵,以 2 为底求对数shannonEnt -= prob * log(prob, 2)return shannonEnt

按照给定特征划分数据集

将指定特征的特征值等于 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列的值是否为valueif 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 featuresfor 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 - newEntropyprint 'infoGain=', infoGain, 'bestFeature=', i, baseEntropy, newEntropyif (infoGain > bestInfoGain):bestInfoGain = infoGainbestFeature = ireturn bestFeature
问:上面的 newEntropy 为什么是根据子集计算的呢?
答:因为我们在根据一个特征计算香农熵的时候,该特征的分类值是相同,这个特征这个分类的香农熵为 0;
这就是为什么计算新的香农熵的时候使用的是子集。

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

创建树的函数代码如下:

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]# 初始化myTreemyTree = {bestFeatLabel: {}}# 注:labels列表是可变对象,在PYTHON函数中作为参数时传址引用,能够被全局修改# 所以这行代码导致函数外的同名变量被删除了元素,造成例句无法执行,提示'no surfacing' is not in listdel(labels[bestFeat])# 取出最优列,然后它的branch做分类featValues = [example[bestFeat] for example in dataSet]uniqueVals = set(featValues)for value in uniqueVals:# 求出剩余的标签labelsubLabels = labels[:]# 遍历当前选择特征包含的所有属性值,在每个数据集划分上递归调用函数createTree()myTree[bestFeatLabel][value] = createTree(splitDataSet(dataSet, bestFeat, value), subLabels)# print 'myTree', value, myTreereturn myTree

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

def classify(inputTree, featLabels, testVec):"""classify(给输入的节点,进行分类)

    Args:
        inputTree  决策树模型
        featLabels Feature标签对应的名称
        testVec    测试输入的数据
    Returns:
        classLabel 分类的结果值,需要映射label才能知道名称
    """# 获取tree的根节点对于的key值firstStr = inputTree.keys()[0]# 通过key得到根节点对应的valuesecondDict = 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 = valueOfFeatreturn classLabel

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

完整代码地址: https://github.com/apachecn/MachineLearning/blob/master/src/python/3.DecisionTree/DecisionTree.py

项目案例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('\t') 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'}}}}}

测试算法: 编写测试函数验证决策树可以正确分类给定的数据实例。

使用算法: 存储树的数据结构,以便下次使用时无需重新构造树。

使用 pickle 模块存储决策树

def storeTree(inputTree, filename):impory picklefw = open(filename, 'w')pickle.dump(inputTree, fw)fw.close()def grabTree(filename):import picklefr = open(filename)return pickle.load(fr)

完整代码地址: https://github.com/apachecn/MachineLearning/blob/master/src/python/3.DecisionTree/DecisionTree.py


  • 作者:片刻 小瑶
  • GitHub地址: https://github.com/apachecn/MachineLearning
  • 版权声明:欢迎转载学习 => 请标注信息来源于 ApacheCN

【机器学习实战】第3章 决策树(DecisionTree)相关推荐

  1. 关于《机器学习实战》中创建决策树的核心代码分析

       关于<机器学习实战>中创建决策树的核心代码分析                 SIAT  nyk          2017年10月21日星期六 一.源码内容 def create ...

  2. 《机器学习实战》第二章学习笔记:K-近邻算法(代码详解)

    <机器学习实战>数据资料以及总代码可以去GitHub中下载: GitHub代码地址:https://github.com/yangshangqi/Machine-Learning-in-A ...

  3. 【机器学习实战】构建/绘制决策树(ID3/C4.5)

    近来想要整理一下机器学习实验的代码,将一些基本算法的过程重新整理实现,并完善注释. 一.构建决策树 1.计算信息熵calculate_entropy(dataset) 2.按某一特征划分数据集spli ...

  4. 机器学习实战第15章pegasos算法原理剖析以及伪代码和算法的对应关系

    Pegasos原文是: http://ttic.uchicago.edu/~nati/Publications/PegasosMPB.pdf 还是挺长的,论文结构是: 第1~6页:主要原理 第7~15 ...

  5. 机器学习实战(二)决策树DT(Decision Tree、ID3算法)

    目录 0. 前言 1. 信息增益(ID3) 2. 决策树(Decision Tree) 3. 实战案例 3.1. 隐形眼镜案例 3.2. 存储决策树 3.3. 决策树画图表示 学习完机器学习实战的决策 ...

  6. 【10月31日】机器学习实战(二)决策树:隐形眼镜数据集

    决策树的优点:计算的复杂度不高,输出的结果易于理解,对中间值的确实不敏感,可以处理不相关的特征数据 决策树的缺点:可能会产生过度匹配的问题. 其本质的思想是通过寻找区分度最好的特征(属性),用于支持分 ...

  7. 机器学习实战:第一章

    根据方教授的建议和要求,在暑假里简单自学<机器学习实战>,记录学习过程和代码. 记 第一章是对机器学习的一些概念介绍,定义了若干专业术语.列举了很多机器学习的各类实例.给出了一个" ...

  8. 机器学习实战(6)——决策树

    目录 1 决策树训练和可视化 2 做出预测 3 估算类别概率 4 CART训练算法 5 正则化超参数 6 回归 7 不稳定性 1 决策树训练和可视化 下面简单看一下例子: 常规模块的导入以及图像可视化 ...

  9. 【机器学习实战】3、决策树

    文章目录 决策树 3.1 决策树的构造 3.1.1 信息增益 3.1.2 编写代码计算经验熵 3.1.4利用代码计算信息增益 3.2 决策树的生成和修剪 3.2.1 决策树的构建 1. ID3算法 2 ...

  10. Python数据分析与机器学习实战<八>决策树、随机森林

    目录 决策树原理概述 树模型 决策树 树的组成 决策树的训练和测试 选择节点(即如何进行特征划分?) 衡量标准---熵 公式: Pi为取到某个类别的概率​ 熵的图像 如何决策一个节点的选择? 决策树构 ...

最新文章

  1. pyqt5实战之幻彩大蛇(贪吃蛇)-1
  2. 重庆计算机二本专业有哪些专业,重庆高考计算机类分数线
  3. 《MS SQL Server 2000管理员手册》系列——8. 管理 Microsoft SQL Server 服务
  4. curl 增加header_libcurl增加HTTP header 和 POST之后获取返回数据
  5. 最in的一期,来自大厂的邀请|C课有道
  6. php ip操作,ip操作 · PHP 个人常用知识总结 · 看云
  7. 欣赏你的孩子(ZT)
  8. proj编译linux,在Ubuntu上安装proj 投影转换程序
  9. c语言浪漫烟花表白,C语言实战之浪漫烟花表白程序.pdf
  10. 小游戏—九宫格(拼图游戏)
  11. 学习笔记——直流电机调速器
  12. 会员260万,续卡率居高不下,山姆有着怎样的魔力?
  13. 计算机重启发出响声怎么办,电脑不断响提示音怎么办
  14. linux硬盘格式化物理卷,创建物理卷报错Can't open /dev/sdb5 exclusively. Mounted filesystem的问题解决过程记录......
  15. 数字信号处理-01- 数字信号处理基础知识
  16. Flutter Convex Bottom 底部导航
  17. 各种手段终于将土豆视频url请求找到了
  18. python设计一个学生类姓名年龄成绩_C# 编写学生类Student,包含学生姓名,成绩,设计一个友员函数sortDegree(),将学生成绩按大到小排序。...
  19. mathmatic engineer
  20. PCB板布线经验~~

热门文章

  1. 无处不数据的时代 三大运营商如何变现大数据价值?
  2. 开发一个基于 Android系统车载智能APP
  3. 使用datadog来监控os和postgresql数据库
  4. 如何使用微信开发者工具调试在微信端访问的网页
  5. k8s集群重新将master节点加入集群
  6. k8s master节点状态为 NotReady问题解决
  7. php sphinx应用场景,Sphinx+Scws 搭建千万级准实时搜索应用场景详解
  8. logTracker错误日志跟踪组件(二)
  9. window下查看TCP端口连接情况:netstat -ano -p tcp|findstr 10001
  10. junit 测试似有方法_JUnit测试私有方法(protected方法类同)