决策树02——决策树的构建

《 machine learning in action》之决策树

计算给定数据集的香农熵

创建文件trees.py

# -*- coding=utf-8 -*-
#计算给定数据集的熵
from math import log

def calcShannonEnt(dataSet):
    numEntries = len(dataSet)
    labelCounts = {}  #实例总数
    for featVec in dataSet:
        #为所有可能分类创建字典
        currentLabel = featVec[-1]       #将最后一列,即分类结果存入currentLabel
        if currentLabel not in labelCounts.keys():       #若分类结果已经在labelCounts这个字典中
            labelCounts[currentLabel] = 0              #若当前label不存在,则扩展字典,加入此键值
        labelCounts[currentLabel] += 1                 #字典中的每个键值都记录了当前类别的数量
    #print 'labelCounts,currentLabel:',labelCounts,currentLabel
    #print 'labelCounts.keys()',labelCounts.keys()
    #print 'labelCounts.values()',labelCounts.values()
    shannonEnt = 0.0
    for key in labelCounts:
        prob = float(labelCounts[key])/numEntries
        shannonEnt -= prob*log(prob,2)  #求以2为底的对数,其和即为熵
        #print 'labelCounts[key]',labelCounts[key]
    return shannonEnt

创建或导入dataSet

#鱼类数据集
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

在命令提示符下输入:

In[9]: import trees
In[10]: myDat,labels = trees.createDataSet()
In[11]: myDat
Out[11]: 
[[1, 1, 'yes'], [1, 1, 'yes'], [1, 0, 'no'], [0, 1, 'no'], [0, 1, 'no']]
In[12]: labels
Out[12]: 
['no surfacing', 'flippers']
In[13]: trees.calcShannonEnt(myDat)
#混合的数据越多,熵越高,测试:
In[18]: myDat[0][-1] = 'maybe'
In[19]: myDat
Out[19]: 
[[1, 1, 'maybe'], [1, 1, 'yes'], [1, 0, 'no'], [0, 1, 'no'], [0, 1, 'no']]
In[20]: trees.calcShannonEnt(myDat)
Out[20]: 
1.3709505944546687

划分数据集

取出符合要求某个特征属性值的样本,并将其此特征从数据集中去除。

#按照给定特征划分数据集
def splitDataSet(dataSet,axis,value):  #待划分的数据集,划分数据集的特征(第几列),需要返回的特征的值,(axis-->a,value-->v)
    #为了不修改原始数据集,创建新的list对象
    retDataSet = []
    for featVec in dataSet:
        #将符合特征的数据抽取出来
        if featVec[axis] == value:  #Python中的数据.即featVec中的数据从第0列开始,[0,1,2,3,4,5,……]
            reducedFeatVec = featVec[:axis] #[:axis]表示前axis行,若axis为3,则表示取festVec的前3列,即第[0,1,2]列
            reducedFeatVec.extend(featVec[axis+1:])    #[axis+1:] 表示跳过axis+1列,从下一列数据取到最后一列的数据,即跳过第[3]列,从第[4]列到最后一列
            retDataSet.append(reducedFeatVec)
    return retDataSet

在Python命令行中输入:

In[16]: reload(trees)
Out[16]: 
<module 'trees' from '/home/vickyleexy/PycharmProjects/Classification of contact lenses/trees.py'>
In[17]: myDat,labels = trees.createDataSet()
In[18]: myDat
Out[18]: 
[[1, 1, 'yes'], [1, 1, 'yes'], [1, 0, 'no'], [0, 1, 'no'], [0, 1, 'no']]
In[19]: trees.splitDataSet(myDat,0,1) #抽取出数据集中第0列中数据值为1的样本,并将此列剔除,组成新的样本集
Out[19]: 
[[1, 'yes'], [1, 'yes'], [0, 'no']]
In[20]: trees.splitDataSet(myDat,0,0) #抽取出数据集中第0列中数据值为0的样本,并将此列剔除,组成新的样本集
Out[20]: 
[[1, 'no'], [1, 'no']]
In[21]: trees.splitDataSet(myDat,1,0) #抽取出数据集中第1列中数据值为0的样本,并将此列剔除,组成新的样本集
Out[21]: 
[[1, 'no']]

选取最好的数据集划分方式

即选取取出信息增益最大的特征。信息增益是熵减少或者说信息无序度的减少,信息增益越大,信息无序度减少越大,信息的可确定性越强。

#选择最好的数据集划分数据,即计算每种特征信息熵 Gain(D,a)
def chooseBestFeatureToSplit(dataSet):
    numFeatures = len(dataSet[0]) - 1                     #可选特征的个数
    baseEntropy = calcShannonEnt(dataSet)  # 计算总体信息熵Ent(D)
    bestInfoGain = 0.0;       #初始化最好的信息增益
    bestFeature = -1;        #初始化选取的最好的特征
    #创建唯一的分类标签列表
    for i in range(numFeatures):           #遍历各个特征
        featList = [example[i] for example in dataSet]   #将第i列特征的值选取出来,并存入featList
        uniqueVals = set(featList)         #将featList存为集合的格式,即去除featList中重复的元素,因此uniqueVals中为每个特征的中不同的属性
        newEntropy = 0.0
        #计算每种划分方式的信息熵
        for value in uniqueVals:        #遍历每个特征中的各个属性
            subDataSet = splitDataSet(dataSet,i,value)       #选取符合条件的特征,并将此特征从样本中去除,以便进行下面的进一步计算
            prob = len(subDataSet)/float(len(dataSet))       #符合此特征中此属性的个数占总体样本的比例,即|D^v|/|D|
            newEntropy += prob * calcShannonEnt(subDataSet)  #计算各个特征中每个属性的加权信息熵的和
        infoGain = baseEntropy - newEntropy               #计算信息增益,即Gain(D,a)
        #计算最好额信息增益
        if (infoGain > bestInfoGain):
            bestInfoGain = infoGain
            bestFeature = i
    print '最好的特征,最好的信息增益:',bestFeature,bestInfoGain
    return bestFeature

在Python命令行下输入以下代码进行测试:

In[9]: reload(trees)
Out[9]: 
<module 'trees' from '/home/vickyleexy/PycharmProjects/Classification of contact lenses/trees.py'>
In[10]: myDat,labels = trees.createDataSet()
In[11]: myDat
Out[11]: 
[[1, 1, 'yes'], [1, 1, 'yes'], [1, 0, 'no'], [0, 1, 'no'], [0, 1, 'no']]
In[12]: trees.chooseBestFeatureToSplit(myDat)
最好的特征,最好的信息增益: 0 , 0.419973094022
Out[12]: 
0

递归构建决策树

递归结束的条件:

  • 程序遍历完所有划分数据集的属性
  • 每个分支下的所有实例都具有相同的分类

若已经处理了所有的属性,但类标签依然不是唯一的,此时采用多数表决的方法决定叶子节点的分类。
在trees.py文件的顶部添加operator库

import operator

统计剩余样本中属于哪一类别最多的数量最多:

def majorityCnt(classList):     #classList类别列表
    classCount = {}             #新建立一个字典
    for vote in classList:       #遍历所有的类别
        #统计各类别剩余样本的数量
        if vote not in classCount.keys():     #如果此类别不在classCount的key中
            classCount[vote] = 0
            classCount[vote] += 1
    sortedClassCount = sorted(classCount.iteritems(),key = operator.itemgetter(1),reverse = True) #将统计好的剩余样本类别和其数量,根据其数量进行从大到小的排序
    return sortedClassCount[0][0]     #取出剩余样本中数量最大的类别名称

创建树的函数代码:

#创建树的函数代码
def createTree(dataSet,labels):
    classList = [example[-1] for example in dataSet]
    #类别完全相同则停止继续划分
    if classList.count(classList[0]) == len(classList):  #若classList中第一个类别的数量等于样本的总数量,即样本类别完全相同
        return classList[0]
    #遍历完所有特征时返回出现次数最多的
    if len(dataSet[0]) == 1:
        return majorityCnt(classList)
    bestFeat = chooseBestFeatureToSplit(dataSet)
    bestFeatLabel = labels[bestFeat]
    myTree = {bestFeatLabel:{}}
    del(labels[bestFeat]) #去掉已经使用的(bestFeat)类标签
    #得到最好的特征这一列,包含其所有属性值的列表
    featValues = [example[bestFeat] for example in dataSet]
    uniqueVals = set(featValues)        #去掉featValues列表中重复的属性
    for value in uniqueVals:             #遍历最好的特征中所有的属性
        subLabels = labels[:]            #复制del(labels[bestFeat])后的结果,并将其存在新列表变量subLabels中
        myTree[bestFeatLabel][value] = createTree(splitDataSet(dataSet,bestFeat,value),subLabels)
    return myTree

命令行中输入:

In[66]: reload(trees)
Out[66]: 
<module 'trees' from '/home/vickyleexy/PycharmProjects/Classification of contact lenses/trees.py'>
In[67]: myDat,labels = trees.createDataSet()
In[68]: myTree = trees.createTree(myDat,labels)
最好的特征,最好的信息增益: 0 , 0.419973094022
最好的特征,最好的信息增益: 0 , 0.918295834054
In[69]: myTree
Out[69]: 
{'no surfacing': {0: 'no', 1: {'flippers': {0: 'no', 1: 'yes'}}}}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值