决策树
1、决策树的概念
决策树是什么?
决策树(decision tree)是一种基本的分类与回归方法,通俗的讲也就是一颗用于决策的树。
决策树长什么样呢?
举个通俗易懂的例子,如下图所示的流程图就是一个决策树。
这个决策树中,长方形
代表判断模块
(decision block),也就是用于条件判断的模块。
椭圆形
代表终止模块
(terminating block),表示已经得出结论,可以终止运行。
从判断模块引出的左右箭头称作为分支
(branch),它可以达到另一个判断模块或者终止模块。
回到这个流程图,这就是一个假想的相亲对象分类系统
。这个系统首先检测相亲对方是否有房
。如果有房
,则对于这个相亲对象可以考虑进一步接触
。如果没有房
,则观察相亲对象是否有上进心
,如果没有
,直接Say Goodbye
,此时可以说:"你人很好,但是我们不合适。"如果有
,则可以把这个相亲对象列入候选名单
,好听点叫候选名单,有点瑕疵地讲,那就是备胎
。
举个例子
如果有一个男人(没房,没有上进心)
,输入这个相亲系统,就会得到Say Goodbye
;男人(有房,有上进心)
,输入这个相亲系统,就会得到值的认真考虑
;男人(没房,有上进心)
,输入这个相亲系统,就会得到备胎
;
换一种说法
可以这样理解,分类决策树模型是一种描述对实例进行分类的树形结构。决策树由结点(node)
和有向边(directed edge)
组成。结点
有两种类型:内部结点(internal node)
和叶结点(leaf node)
。内部结点
表示一个特征或属性
,叶结点
表示一个类
。
像上面例子中,内部结点也就是特征或属性
为:相亲对象有房子
,有上进心
;叶结点
也就是类
为:Say Goodbye
、值的认真考虑
、备胎
;有向边
类似if-then规则
,满足条件往右走,不满足往左边走。
决策树就是一颗在内部结点
加上判断条件,在叶结点
加上结论即类
的树。
2、决策树开发流程
使用决策树做预测需要以下过程:
收集数据:可以使用任何方法。
准备数据:收集完的数据,我们要进行整理,将这些所有收集的信息按照一定规则整理出来,并排版,方便我们进行后续处理。
分析数据:可以使用任何方法,决策树构造完成之后,我们可以检查决策树图形是否符合预期。
训练算法:这个过程也就是构造决策树,同样也可以说是决策树学习,就是构造一个决策树的数据结构。
测试算法:使用经验树计算错误率。当错误率达到了可接收范围,这个决策树就可以投放使用了。
使用算法:此步骤可以使用适用于任何监督学习算法,而使用决策树可以更好地理解数据的内在含义。
3、决策树的构建的准备工作
接下来说一下,如何构建决策树?
通常,这一过程可以概括为3个步骤:特征选择
、决策树的生成
和决策树的修剪
。
1、特征选择
为什么进行特征选择?
现实中有分类能力的特征往往在数据样本中占少数,不是所有的特征都可以用来进行分类或者回归。而特征选择在于选取对训练数据具有分类能力的特征。这样可以提高决策树学习的效率,如果利用一个特征进行分类的结果与随机分类的结果没有很大差别,则称这个特征是没有分类能力的。
特征选择就是决定用哪个特征来划分特征空间
。
那么如何进行特征选择呢?
这就要求确定选择特征的准则。直观上,如果一个特征具有更好的分类能力,或者说,按照这一特征将训练数据集分割成子集,使得各个子集在当前条件下有最好的分类,那么就更应该选择这个特征。信息增益就能够很好地表示这一直观的准则。
经验上扔掉对决策树学习的精度影响不大的特征。通常特征选择的标准是信息增益(information gain)或信息增益比,为了简单,本文使用信息增益作为选择特征的标准。
什么是信息增益?
在划分数据集之后信息发生的变化称为信息增益
,知道如何计算信息增益,我们就可以计算每个特征值划分数据集获得的信息增益,获得信息增益最高的特征就是最好的选择。
(1)香农熵
在可以评测哪个数据划分方式是最好的数据划分之前,我们必须学习如何计算信息增益
。集合信息的度量方式称为香农熵或者简称为熵(entropy)
,这个名字来源于信息论之父克劳德·香农。
如果看不明白什么是信息增益和熵,请不要着急,因为他们自诞生的那一天起,就注定会令世人十分费解。克劳德·香农写完信息论之后,约翰·冯·诺依曼建议使用"熵"这个术语,因为大家都不知道它是什么意思。
熵定义为信息的期望值
。在信息论与概率统计中,熵是表示随机变量不确定性的度量
。如果待分类的事物可能划分在多个分类之中,则符号xi的信息定义为 :
I ( x i ) = − log 2 p ( x i ) I(x_{i}) = -\log_{2}p(x_{i}) I(xi)=−log2p(xi)
其中 p ( x i ) p(x_{i}) p(xi)是选择该分类的概率。有人可能会问,信息为啥这样定义啊?答曰:前辈得出的结论。这就跟1+1等于2一样,记住并且会用即可。上述式中的对数以2为底,也可以e为底(自然对数)。
通过上式,我们可以得到所有类别的信息。为了计算熵,我们需要计算所有类别所有可能值包含的信息期望值(数学期望),通过下面的公式得到:
H = − ∑ k = 1 n p ( x i ) log 2 p ( x i ) H = -\sum_{k=1}^np(x_{i})\log_{2}p(x_{i}) H=−k=1∑np(xi)log2p(xi)
期中n是分类的数目。熵越大,随机变量的不确定性就越大。
当熵中的概率由数据估计(特别是最大似然估计)得到时,所对应的熵称为经验熵(empirical entropy)
。
什么叫由数据估计?
比如有10个数据,一共有两个类别,A类和B类。其中有7个数据属于A类,则该A类的概率即为十分之七。其中有3个数据属于B类,则该B类的概率即为十分之三。浅显的解释就是,这概率是我们根据数据数出来的
。
在编写代码之前,我们先对数据集进行属性标注。
年龄:0代表青年,1代表中年,2代表老年;
有工作:0代表否,1代表是;
有自己的房子:0代表否,1代表是;
信贷情况:0代表一般,1代表好,2代表非常好;
类别(是否给贷款):no代表否,yes代表是。
确定这些之后,我们就可以创建数据集,代码编写如下:
from math import log
"""
函数说明:创建测试数据集
Parameters:
无
Returns:
dataSet - 数据集
labels - 分类属性
"""
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, 0, 'no']]
labels = ['不放贷', '放贷'] #分类属性
return dataSet, labels #返回数据集和分类属性
我们定义贷款申请样本数据表中的数据为训练数据集D,则训练数据集D的经验熵为H(D),|D|表示其样本容量
,及样本个数
。设有K个类Ck, = 1,2,3,…,K,|Ck|为属于类Ck的样本个数,因此经验熵公式就可以写为 :
H ( D ) = − ∑ k = 1 K ∣ C k ∣ ∣ D ∣ log 2 ∣ C k ∣ ∣ D ∣ H(D) = -\sum_{k=1}^K\frac{|C_{k}|}{|D|}\log_{2}\frac{|C_{k}|}{|D|} H(D)=−k=1∑K∣D∣∣Ck∣log2∣D∣∣Ck∣
根据此公式计算经验熵H(D),分析贷款申请样本数据表中的数据。最终分类结果只有两类,即放贷和不放贷。根据表中的数据统计可知,在15个数据中,9个数据的结果为放贷,6个数据的结果为不放贷。所以数据集D的经验熵H(D)为:
H ( D ) = − 9 15 log 2 9 15 − 6 15 log 2 6 15 H(D) = -\frac{9}{15}\log_{2}\frac{9}{15}-\frac{6}{15}\log_{2}\frac{6}{15} H(D)=−159log2159−156log2156
经过计算可知,数据集D的经验熵H(D)的值为0.971。
(2)编写代码计算经验熵
"""
函数说明:计算给定数据集的经验熵(香农熵)
Parameters:
dataSet - 数据集
Returns:
shannonEnt - 经验熵(香农熵)
Author:
Jack Cui
Modify:
2017-03-29
"""
def calcShannonEnt(dataSet):
numEntires = len(dataSet) #返回数据集的行数
labelCounts = {
} #保存每个标签(Label)出现次数的字典
for featVec in dataSet: #对每组特征向量进行统计
currentLabel = featVec[-1] #提取标签(Label)信息
if currentLabel not in labelCounts.keys(): #如果标签(Label)没有放入统计次数的字典,添加进去
labelCounts[currentLabel] = 0
labelCounts[currentLabel] += 1 #Label计数
shannonEnt = 0.0 #经验熵(香农熵)
for key in labelCounts: #计算香农熵
prob = float(labelCounts[key]) / numEntires #选择该标签(Label)的概率
shannonEnt -= prob * log(prob, 2) #利用公式计算
return shannonEnt #返回经验熵(香农熵)
if __name__ == '__main__':
dataSet, features = createDataSet()
print(calcShannonEnt(dataSet))
#output
0.9709505944546686
(3) 信息增益
在上面,我们已经说过,如何选择特征
,需要看信息增益
。也就是说,信息增益是相对于特征而言的,信息增益越大,特征对最终的分类结果影响也就越大,我们就应该选择对最终分类结果影响最大的那个特征作为我们的分类特征
。
在讲解信息增益定义之前,我们还需要明确一个概念,条件熵(conditional entropy)
。
熵
我们知道是什么,条件熵
又是个什么鬼?
条件熵
: H ( Y ∣ X ) H(Y|X) H(Y∣X)表示在已知随机变量X的条件下随机变量Y的不确定性。
随机变量X给定的条件下随机变量Y的条件熵,定义为X给定条件下Y的条件概率分布的熵
对X的数学期望:
H ( Y ∣ X ) = − ∑ k = 1 K P ( X = x i ) log 2 H ( Y ∣ X = x i ) , i = 1 , 2 , . . . , n H(Y|X) = -\sum_{k=1}^KP(X=x_{i})\log_{2}H(Y|X=x_{i}),i=1,2,...,n H(Y∣X)=−k=1∑KP(X=xi)log2H(Y∣X=xi),i=1,2,...,n
当条件熵
中的概率由数据估计(特别是极大似然估计)得到时,所对应的条件熵称为条件经验熵(empirical conditional entropy)
。
明确了条件熵
和经验条件熵
的概念。接下来,让我们说说信息增益
。前面也提到了,信息增益是相对于特征而言的。所以,特征A
对训练数据集D
的信息增益g(D,A)
,定义为集合D的经验熵H(D)
与特征A给定条件下D的经验条件熵H(D|A)
之差,即:
g ( D , A ) = H ( D ) − H ( D ∣ A ) g(D,A)=H(D)-H(D|A) g(D,A)=H(D)−H(D∣A)
一般地,熵H(D)
与条件熵H(D|A)
之差称为互信息(mutual information)
。决策树学习中的信息增益等价于训练数据集中类与特征的互信息。
设特征A
有n个不同的取值{a1,a2,···,an}
,根据特征A的取值
将D划分为n个子集{D1,D2,···,Dn}
,|Di|为Di的样本个数
。记子集Di中属于Ck的样本的集合为Dik
,即Dik = Di ∩ Ck,|Dik|为Dik的样本个数,|Ck|为属于类Ck的样本个数。于是经验条件熵的公式可以些为:
H ( D ∣ A ) = − ∑ i = 1 n ∣ D i ∣ ∣ D ∣ H ( D i ) = − ∑ i = 1 n ∣ D i ∣ ∣ D ∣ ∑ k = 1 K ∣ C i k ∣ ∣ D i ∣ log 2 ∣ C i k ∣ ∣ D i ∣ H(D|A)= -\sum_{i=1}^n\frac{|D_{i}|}{|D|}H(D_{i})= -\sum_{i=1}^n\frac{|D_{i}|}{|D|}\sum_{k=1}^K\frac{|C_{ik}|}{|D_{i}|}\log_{2}\frac{|C_{ik}|}{|D_{i}|} H(D∣A)=−i=1∑n