- Python版本: Python3.x
- 运行平台: Windows
- IDE: PyCharm
- 参考资料:《机器学习》(西瓜书)《机器学习实战》(王斌)
- 转载请标明出处:https://blog.csdn.net/tian121381/category_9748511.html
- 资料下载,提取码:9k59
一、前言
上节介绍的k-近邻算法可以很好地完成分类任务,但是它最⼤的缺点就是⽆法给出数据的内在含义,决策树的主要优势就在于数据形式非常容易理解。决策树的⼀个重要任务是为了数据中所蕴含的知识信息,因此决策树可以使⽤不熟悉的数据集合,并从中提取出⼀系列规则,在这些机器根据数据创建规则时,就是机器学习的过程。下面就详细的说一下决策数吧!
二、决策树的理论知识
1 什么叫决策树
决策树(decision tree) 是一类常见的机器学习方法,以二分类任务为例,我们希望从给定训练数据集学得一个模型用以对新示例进行分类,这个把样本分类的任务,可看作对"当前样本属于正类吗?“这个问题的"决策"或"判定"过程.顾名思义,决策树是基于树结构来进行决策的,这恰是人类在面临决策问题时一种很自然的处理机制。例如,我们要对"这是好瓜吗?“这样的问题进行决策时,通常会进行一系列的判断或"子决策"我们先看"它是什么颜色?”,如果是"青绿色”,则我们再看"它的根蒂是什么形态?",如果是"蜷缩",我们再判断"它敲起来是什么声音?",最后我们得出最终决策:这是个好瓜。如下图。
这时你可能会想:为什么一开始要先判断色泽呢?而不是敲声?这就涉及到了下节讲到的决策树的划分选择了。
2 决策树中的划分选择
在构造决策树时,我们需要解决的第⼀个问题就是,当前数据集上哪个特征在划分数据分类时起决定性作⽤(也就是在众多特征中找根节点,它的影响最大,然后再画它的子节点,影响稍微小点的特征,依次往下)。为了找到决定性的特征,划分出最好的结果,我们必须评估每个特征。完成测试之后,原始数据集就被划分为几个数据子集。这些数据⼦集会分布在第一个决策点的所有分支上。一般而言,随着划分过程不断进行,我们希望决策树的分支结点所包含的样本尽可能属于同一类别,即结点的"纯度" (purity)越来越高.
划分数据集的原则是:将无序的数据变得更加有序。我们可以使用多种方法划分数据集,但是每种⽅法都有各⾃的优缺点。在可以评测哪种数据划分⽅式是最好的数据划分之前,我们必须学习如何计算信息增益。
1). 信息增益
信息增益是在划分数据集之前之后信息发⽣的变化,知道如何计算信息增益,我们就可以计算每个特征值划分数据集获得的信息增益,获得信息增益最⾼的特征就是最好的选择(就是我们要的根节点)。
“信息熵” (information entropy)是度量样本集合纯度最常用的一种指标. 假定当前样本集合 D 中第 k 类样本所占的比例为 Pk (k = 1,2,. . . , IyI),则 D 的信息熵定义为
仔细看看这个公式,负号的位置为了好记忆是不是可以换换呀?
换一下位置不就成了概率乘log下概率的倒数了嘛?清爽很多了吧。这是总体样本的信息熵。那么一个属性各自取值的信息熵呢?就以有自己取值的所有样例作为一个集合,通过正反例算信息熵。最后乘各自的概率相加即可。
有了总体样本的信息熵,又求得了各自属性的信息熵,它们的信息增益直接相减即可得到。我们需要判断的是看哪个属性的信息增益大,大的就为决定性的因素。
语言是苍白的,关键时刻还得上例子。
现有如下数据集。
上图知数据集包含 17 个训练样例,用以学习一棵能预测设剖开的是不是好瓜的决策树.显然, IyI = 2(好坏瓜)。在决策树学习开始时,根结点包含 D 中的所有样例,其中好瓜的概率是8/17,坏瓜的是9/17。信息熵通过上述公式得。
之后,我们要计算出当前属性集合{色泽,根蒂,敲声,纹理,脐部,触感} 中每个属性的信息增益。以属性"色泽"为例,它有 3 个可能的取值: {青绿,乌黑,浅白}。
先看取值青绿的集合,设为D1,它占总样本的6/17,其中共有6个样例,分别是编号 {1, 4, 6, 10, 13, 17} ,正例占 p1=3/6, 反例占p2=3/6;它的信息熵求的。
同理,用D2表示乌黑,D3表示浅白,得到它们信息熵为。
通过信息增益公式得。
类似的,我们可计算出其他属性的信息增益:
显然,属性"纹理"的信息增益最大,于是它被选为划分属性.下图给出了基于"纹理"对根结点进行划分的结果,各分支结点所包含的样例子集显示在结点中。
然后,决策树学习算法将对每个分支结点做进一步划分。以图上图中第一 个分支结点( “纹理=清晰” )为例,该结点包含的样例集合 D1 中有编号为 {1, 2, 3, 4, 5, 6, 8, 10, 15} 的 9 个样例,可用属性集合为{色泽,根蒂,敲声,脐部,触感}。基于 D1 计算出各属性的信息增益:
“根蒂”、 “脐部”、 “触感” 3 个属性均取得了最大的信息增益,可任选其中之一作为划分属性。类似的,对每个分支结点进行上述操作,最终得到的决策树如下图所示。
是不是觉得计算好复杂呀,没什么好担心得,一切交给计算机。<( ̄ c ̄)y▂ξ (面包会有的,下面的代码也会有的)
2). 增益率
在上面的介绍中,我们有意忽略了表中的"编号"这一列。若把"编号"也作为一个候选划分属性,则根据信息增益公式可计算出它的信息增益为 0.998, 远大于其他候选划分属性。这很容易理解"编号"将产生 17 个分支,每个分支结点仅包含一个样本,这些分支结点的纯度己达最大.然而,这样的决策树显然不具有泛化能力,无法对新样本进行有效预测。
实际上,信息增益准则对可取值数目较多的属性有所偏好,为减少这种偏好可能带来的不利影响,著名的 C4.5 决策树算法(看不看的吧,知道有这个东西就行啦)不直接使用信息增益,而是使用"增益率" (gain ratio) 来选择最优划分属性。采用信息增益公式相同的符号表示,增益率定义为
其中
IV(α)这个东西不就是信息熵嘛。
需注意的是,增益率准则对可取值数目较少的属性有所偏好,因此,它并不是直接选择增益率最大的候选划分属性,而是使用了一个启发式 先从候选划分属性中找出信息增益高于平均水平的属性,再从中选择增益率最高的。
3 剪枝处理
剪枝(pruning)是决策树学习算法对付"过拟合"的主要手段.在决策树学习中,为了尽可能正确分类训练样本,结点划分过程将不断重复,有时会造成决策树分支过多,这时就可能因训练样本学得"太好"了,以致于把训练集自身的一些特点当作所有数据都具有的一般性质而导致过拟合.因此,可通过主动去掉一些分支来降低过拟合的风险。
决策树剪枝的基本策略有"预剪枝" (prepruning)和"后剪枝"(post" pruning)。预剪枝是指在决策树生成过程中,对每个结点在划分前先进行估计,若当前结点的划分不能带来决策树泛化性能提升,则停止划分并将当前结点标记为叶结点;后剪枝则是先从训练集生成一棵完整的决策树,然后自底向上地对非叶结点进行考察,若将该结点对应的子树替换为叶结点能带来决策树泛化性能提升,则将该子树替换为叶结点。
如何判断决策树泛化性能是否提升呢?这可使用了第一章介绍的性能评估方法。本节假定采用留出法,即预留一部分数据用作"验证集"以进行性能评估.例如西瓜数据集,我们将其随机划分为两部分,下表所示,编号为 {1,2,3,6,7,10,14,15,16,17} 的样例组成训练集,编号为 {4,5, 8,9,11,12,13} 的样例组成验证集。再来看一个实例吧!
1). 预剪枝
我们先讨论预剪枝。基于信息增益准则,我们会选取属性"脐部"来对训练集进行划分,并产生 3 个分支。如下图。然而,是否应该进行这个划分呢?预剪枝要对划分前后的泛化性能进行估计。
让我们来减一下吧!(图来源于致敬大神小姐姐)
此图将各个属性的测试集,训练集样本序号全都标注上了,为了容易描述,我又给各属性加了序号。(注意样本序号,和节点标号呀!!!)
以脐部为例。脐部没有子节点时,它的正确率,就是测试集的正确率呗。3 / 7 = 42.9%(共7个测试集,3个正确的)。有序号为1 2 3的节点之后呢?分析一下,序号1的节点标记是好瓜(标记看训练集,那个标记数量多就是什么标记,如1节点中好瓜标记多,那它的标记就是好瓜),再看测试集,样本4,样本5正确。序号为2的节点,标记为好瓜,样本8正确。序号为3的节点中,标记是坏瓜,样本11,12都正确,这时7个样本对了2+1+2=5个,这时的精度就是5/7=71.4%了。划分后,精度提高了,也就不裁剪掉这些节点。
我现在的精度是71.4%了,也是说我判断是否裁剪掉第二代节点的子节点时,我划分前的精度为71.4%。以色泽为例。他是第二代节点,没有划分前是71.4%的精度。测试集中只有样本13错了。(这里不要用2 / 3 = 67%来求划分前的精度,要用上面求的71.4%)。划分后呢?
节点1.1标记好瓜,样本13错了。节点1.3中,标记是坏瓜,样本5错了。没划分前,错了一个,划分后还多错了一个,那它的精度就是
(5 - 1) / 7 = 57.1%,精度下降了,那就把它删去。如下图。
剩下的都是一样的做法的,可以自己看看。最终结果如下。
注: 精度相同的也裁剪,因为预剪枝的原则是:能减就减。
2). 后剪枝
后剪枝先从训练集生成一棵完整决策树,从后向前开始剪裁,它的原则是:能不减就不减。
还是那张图。
从下往上看(看所有的叶子节点)。以纹理(2.1.2)节点为例。裁剪之前:叶子节点1.1标记好瓜,样本4正确,样本13错误。没有样本的跳过。叶子节点1.3标记坏瓜,样本5错误。依次类推叶子节点2.1.1,2.1.2.1,2.1.2.2,2.1.2.3,2.1.3,2.2,2.3,3。得到共3个正确的,精度为3 / 7 = 42.9%。如果我裁剪掉纹理的子节点呢?(把2.1.2.x的挡着看)看所有叶子节点,1.1,1.2,1.3,2.1.1,2.1.2,2.1.3,2.2,2.3,3。正确的样本有4个,精度为4 / 7 = 57.1%。精度上升了,那么我们就裁掉它吧。值得注意的是别忘了后剪裁的原则,能不减就不减。所以相同精度的我是保留的。最后得如下图所示。
三、构造一个简单的决策树
1). 决策树的⼀般流程
- 收集数据:可以使⽤任何⽅法。
- 准备数据:树构造算法只适⽤于标称型数据,因此数值型数据必须离散化。
- 分析数据:可以使⽤任何⽅法,构造树完成之 后,我们应该检查图形是否符合预期。
- 训练算法:构造树的数据结构。
- 测试算法:使⽤经验树计算错误率。
- 使⽤算法:此步骤可以适⽤于任何监督学习算法,⽽使⽤决策树可以更好地理解数据的内在含义。
我们现有一组数据,里面有一个人的年龄,是否有工作,是否有房子,借贷信誉三个特征,标签是银行是否给他贷款,如图所示。
对数据集进行标注,为下面操作方便。
- 年龄:0代表青年,1代表中年,2代表老年;
- 有工作:0代表否,1代表是;
- 有自己的房子:0代表否,1代表是;
- 信贷情况:0代表一般,1代表好,2代表非常好;
- 类别(是否给贷款):no代表否,yes代表是。
按照上表,咱们来写个简单的数据集吧!
2). 构造决策树
首先,引入相关包
"""
构建一个决策树
@Author:Yuuuuu、Tian
Fri Feb 14 10:40:06 2020
"""
from math import log
import operator
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.font_manager import FontProperties
#创建数据集。
def createDataSet():
dataSet = [[0, 0, 0, 0, 'no'], #数据集
[0, 0, 0, 1, 'no'],
[0, 1, 0, 1, 'yes'],
[0, 1, 1, 0, 'yes'],
[0, 0, 0, 0, 'no'],
[1, 0, 0, 0, 'no'],
[1, 0, 0, 1, 'no'],
[1, 1, 1, 1, 'yes'],
[1, 0, 1, 2, 'yes'],
[1, 0, 1, 2, 'yes'],
[2, 0, 1, 2, 'yes'],
[2, 0, 1, 1, 'yes'],
[2, 1, 0, 1, 'yes'],
[2, 1, 0, 2, 'yes'],
[2, 0, 0