4.1 基本流程

决策树(decision)是一类常见的机器学习算法,以二分类任务为例,我们希望从给定训练数据集学得一个模型用以对新示例进行分类,这个把样本分类的任务,可看做对“当前样本属于正类吗”这个问题的“决策”或“判定”过程。顾名思义,决策树是基于树结构进行决策的,这恰是人类在面临决策问腿时一种很自然的处理机制。

python实现决策树分类


from math import log
import operator'''******************************python实现决策树******************************'''
'''加载数据集'''
def loadData():dataSet = [[1, 1, 'yes'],[1, 1, 'yes'],[1, 0, 'no'],[0, 1, 'no'],[0, 1, 'no']]labels = ['no surfacing', 'flippers']return dataSet, labels
'''计算数据集的熵,熵越小,分类效果越好'''
def calShang(data):num=len(data)#特征的字典,键值为字典,值为特征个数classCount={}for feat in data:featVec=feat[-1]#若字典中不存在此键值,则创建if featVec not in classCount.keys():classCount[featVec]=0classCount[featVec]+=1Shang=0.0for key in classCount:prob=classCount[key]/float(num)Shang-=prob*log(prob,2)return Shang
'''分割数据集,根据特征值value分割'''
def splitData(data,axis,value):retData=[]for dataList in data:if dataList[axis]==value:newData=dataList[:axis]newData.extend(dataList[axis+1:])retData.append(newData)return retData
'''根据数据集的熵值大小,寻找最优的数据集划分方式'''
def findOptSplit(data):#特征变量的个数numFeat=len(data[0])-1#先将原始数据集的熵值作为最小的熵值bestShang=calShang(data)for i in range(numFeat):Shang=0.0featList=[feat[i] for feat in data]featSet=set(featList)for value in featSet:splData=splitData(data,i,value)prob=len(splData)/float(len(data))Shang+=prob*calShang(splData)if Shang<bestShang:bestShang=ShangbestFeat=ireturn bestFeat
'''获取出现次数最多的类别名称'''
def majorityCnt(classList):classCount={}for vote in classList:if vote not in classCount.keys():classCount=0classCount[vote]+=1sortedClassCount=sorted(classCount.iteritems(),key=operator.itemgetter(1),reverse=True)return sortedClassCount
'''创建树'''
def createTree(dataSet,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=findOptSplit(dataSet)bestFeatLbel=labels[bestFeat]myTree={bestFeatLbel:{}}#删除当前特征del(labels[bestFeat])featValues=[example[bestFeat] for example in dataSet]uniqueVals=set(featValues)for value in uniqueVals:subLabels=labels[:]myTree[bestFeatLbel][value]=createTree(splitData(dataSet,bestFeat,value),subLabels)return myTree

4.2 划分选择

如何选择最优划分属性,一般而言,随着划分过程不断进行,我们希望决策树的分支节点所办含的样本尽可能属于同一类别,既节点的纯度(purity)越来越高。

这里涉及到信息增益和基尼指数,后面有介绍。
4.3 剪枝处理
就好象算法里的剪枝处理。
4.4 连续与缺失值

4.4.1
连续值处理
到目前为止,我们仅仅讨论了基于离散属性生成决策树,现实任务中常会遇到连续属性,有必要讨论在决策树学习中使用连续属性。
4.4.2
缺失值处理
现实任务中,常会遇到不完整样本,既样本的属性值缺失,例如由于诊测成本,隐私保护等因素,
患者的医疗数据在某些属性上的取值(如HIV测试结果)未知,

4.5 多变量决策树

与传统的单变量决策树不用,在多变量决策树学习过程中,不是为没一个非叶节点找到一个最优有划分属性,
而是试图建立一个合适的线性分类器,
可以对西瓜数据集,3.0阿发进行处理,找到多变量决策树对应的分类边界。

以上4个方面很重要,后续会写详细一点,不在这里介绍了哈。
信息增益
划分数据集的大原则是:将无序数据变得更加有序,但是各种方法都有各自的优缺点,信息论是量化处理信息的分支科学,在划分数据集前后信息发生的变化称为信息增益,获得信息增益最高的特征就是最好的选择,所以必须先学习如何计算信息增益,集合信息的度量方式称为香农熵,或者简称熵。

希望通过所给的训练数据学习一个贷款申请的决策树,用以对未来的贷款申请进行分类,即当新的客户提出贷款申请时,根据申请人的特征利用决策树决定是否批准贷款申请。

特征选择就是决定用哪个特征来划分特征空间。比如,我们通过上述数据表得到两个可能的决策树,分别由两个不同特征的根结点构成

图(a)所示的根结点的特征是年龄,有3个取值,对应于不同的取值有不同的子结点。图(b)所示的根节点的特征是工作,有2个取值,对应于不同的取值有不同的子结点。两个决策树都可以从此延续下去。问题是:究竟选择哪个特征更好些?这就要求确定选择特征的准则。直观上,如果一个特征具有更好的分类能力,或者说,按照这一特征将训练数据集分割成子集,使得各个子集在当前条件下有最好的分类,那么就更应该选择这个特征。信息增益就能够很好地表示这一直观的准则。

什么是信息增益呢?在划分数据集之前之后信息发生的变化成为信息增益,知道如何计算信息增益,我们就可以计算每个特征值划分数据集获得的信息增益,获得信息增益最高的特征就是最好的选择。

熵定义为信息的期望值,如果待分类的事物可能划分在多个类之中,则符号xix_ix
i

的信息定义为:
l(xi)=−log2p(xi)l(x_i)=-log_2 p(x_i)
l(x
i

)=−log
2

p(x
i

)

其中,p(xi)p(x_i)p(x
i

)是选择该分类的概率。

为了计算熵,我们需要计算所有类别所有可能值所包含的信息期望值,通过下式得到:
H=−Σni=1p(xi)log2p(xi)H=-\Sigma_{i=1}^n p(x_i)log_2 p(x_i)
H=−Σ
i=1
n

p(x
i

)log
2

p(x
i

)

其中,nnn为分类数目,熵越大,随机变量的不确定性就越大。

当熵中的概率由数据估计(特别是最大似然估计)得到时,所对应的熵称为经验熵(empirical entropy)。什么叫由数据估计?比如有10个数据,一共有两个类别,A类和B类。其中有7个数据属于A类,则该A类的概率即为十分之七。其中有3个数据属于B类,则该B类的概率即为十分之三。浅显的解释就是,这概率是我们根据数据数出来的。我们定义贷款申请样本数据表中的数据为训练数据集D,则训练数据集D的经验熵为H(D),|D|表示其样本容量,及样本个数。设有K个类Ck,k = 1,2,3,···,K,|Ck|为属于类Ck的样本个数,这经验熵公式可以写为:
H(D)=−Σ∣ck∣∣D∣log2∣ck∣∣D∣H(D)=-\Sigma \frac{|c_k|}{|D|}log_2\frac{|c_k|}{|D|}
H(D)=−Σ
∣D∣
∣c
k



log
2

∣D∣
∣c
k


根据此公式计算经验熵H(D),分析贷款申请样本数据表中的数据。最终分类结果只有两类,即放贷和不放贷。根据表中的数据统计可知,在15个数据中,9个数据的结果为放贷,6个数据的结果为不放贷。所以数据集D的经验熵H(D)为:
H(D)=−915log2915−615log2615=0.971H(D)=-\frac{9}{15} log_2\frac{9}{15}-\frac{6}{15} log_2\frac{6}{15}=0.971
H(D)=−
15
9

log
2

15
9


15
6

log
2

15
6

=0.971

经过计算可知,数据集D的经验熵H(D)的值为0.971。

在理解信息增益之前,要明确——条件熵

信息增益表示得知特征X的信息而使得类Y的信息不确定性减少的程度。

条件熵H(Y∣X)H(Y|X)H(Y∣X)表示在已知随机变量X的条件下随机变量Y的不确定性,随机变量X给定的条件下随机变量Y的条件熵(conditional entropy) H(Y|X),定义X给定条件下Y的条件概率分布的熵对X的数学期望:
H(Y∣X)=∑ni=1piH(Y∣X=xi)H(Y|X)=\sum_{i=1}^n p_iH(Y|X=x_i)
H(Y∣X)=
i=1

n

p
i

H(Y∣X=x
i

)

其中,pi=P(X=xi)p_i=P(X=x_i)p
i

=P(X=x
i

)

当熵和条件熵中的概率由数据估计(特别是极大似然估计)得到时,所对应的分别为经验熵和经验条件熵,此时如果有0概率,令0log0=00log0=00log0=0

信息增益:信息增益是相对于特征而言的。所以,特征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)。决策树学习中的信息增益等价于训练数据集中类与特征的互信息。

信息增益值的大小相对于训练数据集而言的,并没有绝对意义,在分类问题困难时,也就是说在训练数据集经验熵大的时候,信息增益值会偏大,反之信息增益值会偏小,使用信息增益比可以对这个问题进行校正,这是特征选择的另一个标准。

信息增益比:特征AAA对训练数据集D的信息增益比gR(D,A)g_R(D,A)g
R

(D,A)定义为其信息增益g(D,A)g(D,A)g(D,A)与训练数据集DDD的经验熵之比:

gR(D,A)=g(D,A)H(D)g_R(D,A)=\frac{g(D,A)}{H(D)}
g
R

(D,A)=
H(D)
g(D,A)

3.1.2 编写代码计算经验熵

在编写代码之前,我们先对数据集进行属性标注。

年龄:0代表青年,1代表中年,2代表老年;
有工作:0代表否,1代表是;
有自己的房子:0代表否,1代表是;
信贷情况:0代表一般,1代表好,2代表非常好;
类别(是否给贷款):no代表否,yes代表是。
创建数据集,计算经验熵的代码如下:

from math import log"""
函数说明:创建测试数据集
Parameters:无
Returns:dataSet:数据集labels:分类属性
Modify:2018-03-12"""
def creatDataSet():# 数据集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"""
函数说明:计算给定数据集的经验熵(香农熵)
Parameters:dataSet:数据集
Returns:shannonEnt:经验熵
Modify:2018-03-12"""
def calcShannonEnt(dataSet):#返回数据集行数numEntries=len(dataSet)#保存每个标签(label)出现次数的字典labelCounts={}#对每组特征向量进行统计for featVec in dataSet:currentLabel=featVec[-1]                     #提取标签信息if currentLabel not in labelCounts.keys():   #如果标签没有放入统计次数的字典,添加进去labelCounts[currentLabel]=0labelCounts[currentLabel]+=1                 #label计数shannonEnt=0.0                                   #经验熵#计算经验熵for key in labelCounts:prob=float(labelCounts[key])/numEntries      #选择该标签的概率shannonEnt-=prob*log(prob,2)                 #利用公式计算return shannonEnt                                #返回经验熵#main函数
if __name__=='__main__':dataSet,features=creatDataSet()print(dataSet)print(calcShannonEnt(dataSet))

结果:

第0个特征的增益为0.083
第1个特征的增益为0.324
第2个特征的增益为0.420
第3个特征的增益为0.363
第0个特征的增益为0.252
第1个特征的增益为0.918
第2个特征的增益为0.474
{'有自己的房子': {0: {'有工作': {0: 'no', 1: 'yes'}}, 1: 'yes'}}

3.1.4利用代码计算信息增益


from math import log"""
函数说明:创建测试数据集
Parameters:无
Returns:dataSet:数据集labels:分类属性
Modify:2018-03-12"""
def creatDataSet():# 数据集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"""
函数说明:计算给定数据集的经验熵(香农熵)
Parameters:dataSet:数据集
Returns:shannonEnt:经验熵
Modify:2018-03-12"""
def calcShannonEnt(dataSet):#返回数据集行数numEntries=len(dataSet)#保存每个标签(label)出现次数的字典labelCounts={}#对每组特征向量进行统计for featVec in dataSet:currentLabel=featVec[-1]                     #提取标签信息if currentLabel not in labelCounts.keys():   #如果标签没有放入统计次数的字典,添加进去labelCounts[currentLabel]=0labelCounts[currentLabel]+=1                 #label计数shannonEnt=0.0                                   #经验熵#计算经验熵for key in labelCounts:prob=float(labelCounts[key])/numEntries      #选择该标签的概率shannonEnt-=prob*log(prob,2)                 #利用公式计算return shannonEnt                                #返回经验熵"""
函数说明:计算给定数据集的经验熵(香农熵)
Parameters:dataSet:数据集
Returns:shannonEnt:信息增益最大特征的索引值
Modify:2018-03-12"""def chooseBestFeatureToSplit(dataSet):#特征数量numFeatures = len(dataSet[0]) - 1#计数数据集的香农熵baseEntropy = calcShannonEnt(dataSet)#信息增益bestInfoGain = 0.0#最优特征的索引值bestFeature = -1#遍历所有特征for i in range(numFeatures):# 获取dataSet的第i个所有特征featList = [example[i] for example in dataSet]#创建set集合{},元素不可重复uniqueVals = set(featList)#经验条件熵newEntropy = 0.0#计算信息增益for value in uniqueVals:#subDataSet划分后的子集subDataSet = splitDataSet(dataSet, i, value)#计算子集的概率prob = len(subDataSet) / float(len(dataSet))#根据公式计算经验条件熵newEntropy += prob * calcShannonEnt((subDataSet))#信息增益infoGain = baseEntropy - newEntropy#打印每个特征的信息增益print("第%d个特征的增益为%.3f" % (i, infoGain))#计算信息增益if (infoGain > bestInfoGain):#更新信息增益,找到最大的信息增益bestInfoGain = infoGain#记录信息增益最大的特征的索引值bestFeature = i#返回信息增益最大特征的索引值return bestFeature"""
函数说明:按照给定特征划分数据集
Parameters:dataSet:待划分的数据集axis:划分数据集的特征value:需要返回的特征的值
Returns:shannonEnt:经验熵
Modify:2018-03-12"""
def splitDataSet(dataSet,axis,value):retDataSet=[]for featVec in dataSet:if featVec[axis]==value:reducedFeatVec=featVec[:axis]reducedFeatVec.extend(featVec[axis+1:])retDataSet.append(reducedFeatVec)return retDataSet#main函数
if __name__=='__main__':dataSet,features=creatDataSet()# print(dataSet)# print(calcShannonEnt(dataSet))print("最优索引值:"+str(chooseBestFeatureToSplit(dataSet)))

结果:

第0个特征的增益为0.083
第1个特征的增益为0.324
第2个特征的增益为0.420
第3个特征的增益为0.363
最优索引值:2

决策树的生成和修剪
我们已经学习了从数据集构造决策树算法所需要的子功能模块,包括经验熵的计算和最优特征的选择,其工作原理如下:得到原始数据集,然后基于最好的属性值划分数据集,由于特征值可能多于两个,因此可能存在大于两个分支的数据集划分。第一次划分之后,数据集被向下传递到树的分支的下一个结点。在这个结点上,我们可以再次划分数据。因此我们可以采用递归的原则处理数据集。

构建决策树的算法有很多,比如C4.5、ID3和CART,这些算法在运行时并不总是在每次划分数据分组时都会消耗特征。由于特征数目并不是每次划分数据分组时都减少,因此这些算法在实际使用时可能引起一定的问题。目前我们并不需要考虑这个问题,只需要在算法开始运行前计算列的数目,查看算法是否使用了所有属性即可。

决策树生成算法递归地产生决策树,直到不能继续下去未为止。这样产生的树往往对训练数据的分类很准确,但对未知的测试数据的分类却没有那么准确,即出现过拟合现象。过拟合的原因在于学习时过多地考虑如何提高对训练数据的正确分类,从而构建出过于复杂的决策树。解决这个问题的办法是考虑决策树的复杂度,对已生成的决策树进行简化。

3.2.1 决策树的构建

  1. ID3算法
    ID3算法的核心是在决策树各个结点上对应信息增益准则选择特征,递归地构建决策树。

具体方法是:

1)从根结点(root node)开始,对结点计算所有可能的特征的信息增益,选择信息增益最大的特征作为结点的特征。

2)由该特征的不同取值建立子节点,再对子结点递归地调用以上方法,构建决策树;直到所有特征的信息增益均很小或没有特征可以选择为止;

3)最后得到一个决策树。

ID3相当于用极大似然法进行概率模型的选择

机器学习(MACHINE LEARNING) 【周志华版-”西瓜书“-笔记】 DAY4-决策树相关推荐

  1. 机器学习(MACHINE LEARNING) 【周志华版-”西瓜书“-笔记】 DAY11-特征选择和稀疏学习

    特征工程是机器学习中非常重要的一个环节,它的好坏直接影响了机器学习效果的优劣.而特征工程里非常关键的一步就是特征选择. 如果把机器学习比作是一个厨师做菜的过程,那么数据就是原材料(菜),模型可以理解为 ...

  2. 机器学习(MACHINE LEARNING) 【周志华版-”西瓜书“-笔记】 DAY1-绪论

    我太喜欢这本书了 ,因为封面很好看 .PS:划重点是教科书!需要一定基础,京东正版有售~ 1.1 引言 机器学习:例如我们人吃过,看过很多西瓜, 所以基于色泽.根蒂,敲声这几个特征我们就可以做出相当好 ...

  3. 机器学习(MACHINE LEARNING) 【周志华版-”西瓜书“-笔记】 DAY16-强化学习

    文章目录 16.1 任务与奖赏 RL与有监督学习.无监督学习的比较 形象举例 16.2 K-摇臂赌博机 ε-贪心算法 16.3 有模型学习 16.4 免模型学习 16.5 值函数近似 16.6 模仿学 ...

  4. 机器学习(MACHINE LEARNING) 【周志华版-”西瓜书“-笔记】 DAY15-规则学习

    15.1.规则学习 "规则学习" (rule learning)是从训练数据中学习出一组能用于对未见示例进行判别的规则. 形式上一般为: 式子中,右边的部分称为规则体(Body), ...

  5. 机器学习(MACHINE LEARNING) 【周志华版-”西瓜书“-笔记】 DAY13-半监督学习

    13.1 未标记样本 先说两个概念: 1)有标记样本(Labeled) 训练样本集Dl={(x1,y1), (x2,y2),-, (xl,yl)},这l个样本的类别标记已知. 2)未标记样本(unla ...

  6. 机器学习(MACHINE LEARNING) 【周志华版-”西瓜书“-笔记】 DAY10-降维和度量学习

    10.1 k近邻学习 k近邻(k-Nearest Neighbor,简称kNN)学习是一种常用的监督学习方法. 二.近邻分类算法 1.近邻分类算法的概念 在近邻分类算法中,对于预测的数据,将其与训练样 ...

  7. 机器学习(MACHINE LEARNING) 【周志华版-”西瓜书“-笔记】 DAY6-支持向量机

    今日份打卡~ 一定要读到最后啊,越往后越干货.@!@ 6.1 间隔与支持向量机 6.2 对偶问题 SMO Platt的SMO算法是将大优化问题分解为许多小优化问题求解的,并且对它们顺序求解的结果与将它 ...

  8. 机器学习(MACHINE LEARNING) 【周志华版-”西瓜书“-笔记】 DAY3-线性模型

    3.1 基本形式 一般用向量形式写成 本文介绍几种经典的线性模型,看我们先从回归任务开始,然后讨论二分类和多分类任务. 3.2 线性回归 线性回归是一种监督学习下的线性模型,线性回归试图从给定数据集中 ...

  9. 机器学习(MACHINE LEARNING) 【周志华版-”西瓜书“-笔记】 DAY2-模型评估与选择

    2.1经验误差与过拟合 学习器在训练集上的误差称为"训练误差"(training error)或"经验误差". 当学习器把训练样本学得"太好" ...

最新文章

  1. hdu---5455---fang fang
  2. POJ - 2230 Watchcow(欧拉图)
  3. Problem E: 求最大值和最小值
  4. JS定义数组,初始化
  5. ListView 复用学习
  6. 御剑后台扫描工具下载、安装、使用教程
  7. 常用键盘ASCⅡ码,方便查阅
  8. Pytorch:图像风格迁移
  9. apache+php环境配置
  10. 1004 成绩排名 (20 分)
  11. A79T三极管,A79T芯片规格书
  12. 与Ubuntu16.04+pycharm+第三方包决战的点点滴滴
  13. 小程序如何cdn加速服务器,小程序游戏加速方案
  14. 如何使用Redis实现电商系统的库存扣减?
  15. 欧美插画系列-张聪-专题视频课程
  16. uniapp样式穿透
  17. 5G专网是个大西瓜(三):合成之难
  18. java组合_Java组合
  19. 在c语言中while与do-while,c语言中while与do while循环的主要区别是什么
  20. 网易云音乐管理系统c语言,网易云音乐v2.5.3.197601官方版

热门文章

  1. mini-caffe
  2. C# WebRequest 基础连接已关闭 连接意外关闭
  3. 运动检测 背景减除(Background Segment)
  4. 四种常见的激活函数画图及简单改造
  5. C++默认参数注意事项
  6. 青龙面板node-onebot 教程
  7. 11. 系统信息监控
  8. Java中多线程启动,为什么调用的是start方法,而不是run方法?
  9. swagger2中UI界面接口点击无法展开问题解决
  10. LDD3学习之short