第三章 3.1创建决策树

参考数据:

创建决策树的代码实现:

from math import log
import operator
'''
(1)函数说明:创建测试数据集
     返回值:dataSet:数据集
             labels:分类属性
'''
def createDataSet():
    # 数据集.
    '''
    1列:年龄:0代表青年,1代表中年,2代表老年;
    2列:有工作:0代表否,1代表是;
    3列:有自己的房子:0代表否,1代表是;
    4列:信贷情况:0代表一般,1代表好,2代表非常好;
    5列:类别(是否给贷款):no代表否,yes代表是。(结果)
    '''
    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']]
    #分类的属性(4个特征)
    labels = ['年龄','有工作','有自己的房子','信贷情况']
    return dataSet,labels  #返回数据集、分类属性

'''
(2)函数说明:计算数据集dataSet的熵
其公式为:H(D)= -p(x1)log2p(x1)-p(x2)log2p(x2)-....
返回值:该数据集dataSet的熵
'''
def calcShannonEnt(dataSet):
    #获取数据集的行数
    numEntries = len(dataSet)
    #创建字典。键:分类的结果  值:每个结果出现的次数
    labelCounts = {}
    #遍历数据集,统计每个结果出现的次数
    for featVec in dataSet:
        #最后一列元素存储的是分类结果
        currentLabel = featVec[-1]
        #如果当前分类的结果不在labelCounts中,则在labelCounts中加入该键
        if currentLabel not in labelCounts.keys():
            labelCounts[currentLabel] = 0
        #将当前分类的值+1
        labelCounts[currentLabel]+=1
    #用来存储熵的结果
    shannonEnt = 0
    #开始计算熵.遍历字典labelCounts
    for key in labelCounts:
        #计算该结果出现的频率
        prob = float(labelCounts[key])/numEntries
        #计算熵
        shannonEnt -=prob*log(prob,2)
    #返回熵
    return shannonEnt
'''
(3)函数说明:按照给定的特征划分数据集
             抽取数据集dataSet中 axis列中 值为value的部分数据集
                     特    征,结果
    例如: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']]
          axis = 0   
          value = 0
          找第0列,值为0的行(即前5行),并除去该列(即第一列)。将结果(前5行后4列)存放在retDataSet中
          retDataSet =  [[0,0,0,'no'],
                         [0,0,1,'no'],
                         [1,0,1,'yes'],
                         [1,1,0,'yes'],
                         [0,0,0,'no']]
    
   参数:dataSet:数据集
         axis:表示列下标
         value:表axis列(特征)的取值
   该函数的目的;帮助计算Di的样本个数(行数)|Di|—> 计算|Di|/|D|、H(Di)—> 计算H(D|A)
                根据特征A(axis列的列名)的取值,将D划分为n个子集D1,D2,....,Dn
                
'''
def splitDataSet(dataSet,axis,value):
    # 用来存储符合条件的数据集
    retDataSet = []
    #遍历数据集dataSet(一次取一行)
    for featVec in dataSet:
        #如果axis列的值为value,将取出的这行数据(不包含axis列)存放在retDataSet中
        if featVec[axis] == value: #不去除axis列也可以
            #取该行下标0~axis的元素(不包含axis)
            reduceFeatVec = featVec[:axis]
            #接着取下标axis+1往后的所有元素(不包含axis)
            reduceFeatVec.extend(featVec[axis+1:])
            #将去除axis列的该行元素存放在retDataSet中
            retDataSet.append(reduceFeatVec)
    return  retDataSet

'''
(4)函数说明:选择最好的数据集划分方式。
            (即选择对结果影响最大的特征。特征A的信息增益越大,影响越大)
              分别计算所有特征下D的信息增益g(D,A)=H(D)-H(D|A),取最大的信息增益所对应的特征(H(D)表示数据集D的熵)
    参数dataSet:数据集
    返回值bestFeature:最大的信息增益对应的特征下标
'''
def chooseBestFeatureToSplit(dataSet):
    #获取特征总数.dataSet[0]表示总列数
    numFeatures = len(dataSet[0])-1
    #计算数据集D的熵
    baseEntropy = calcShannonEnt(dataSet)
    #存最大的信息增益
    bestInfoGain = 0.0
    #存最大信息增益对应的特征
    bestFeature = -1
    #遍历所有的特征,获取最大的信息增益及其对应的特征
    for i in range(numFeatures):
        #获取数据集中第i列的所有取值
        featList = [example[i] for example in dataSet]
        #去掉featList中重复的取值。set集合元素不可重复
        uniquevals = set(featList)
        #newEntropy存放特征i下的熵
        newEntropy = 0.0
        #遍历特征i下的各种取值,计算特征i下的熵(需要计算出|Di|/|D|,即单独计算出特征i下各种取值的熵)
        for value in uniquevals:
            #subDataSet:特征i取值为value时的部分数据集
            subDataSet = splitDataSet(dataSet,i,value)
            #计算部分数据集所占的概率
            prob = len(subDataSet)/float(len(dataSet))
            #计算熵
            newEntropy += prob*calcShannonEnt(subDataSet)
        #计算特征i的信息增益
        infoGain = baseEntropy-newEntropy
        print("第%d特征的信息增益为:%.3f"%(i,infoGain))
        #寻找最大的信息增益
        if(infoGain>bestInfoGain):
            #最大的信息增益
            bestInfoGain = infoGain
            #最大信息增益对应的特征下标
            bestFeature = i
    return bestFeature
# if __name__ == '__main__':
#     dataSet,labels = createDataSet()
#     print("最大信息增益值:"+str(chooseBestFeatureToSplit(dataSet)))
'''
(5)函数说明;统计结果列表classList中出现次数最多的结果
   参数说明:classList 结果列表
   返回值:出现次数最多的结果
'''
def majorityCnt(classList):
    #创建字典(键:结果、值:该结果出现的次数),用来计每个结果出现的次数。
    classCount = {}
    #遍历结果集classList
    for key in classList:
        #如果该结果不在字典中,就将其添加到字典中
        if key not in classCount.keys():
            classCount[key]  = 0
        #将该结果的次数加1
        classCount[key]+=1
    #对classCount字典按值降序排列
    sortedClassCount = sorted(classCount.items(),key=operator.itemgetter(1),reverse=True)
    #返回出现次数最多的结果
    return sortedClassCount[0][0]
'''
(6)函数说明:创建树
   参数: dataSet:数据集
          labels:特征集
   返回值:创建的树
'''
def createTree(dataSet,labels):
    #获取最后一列的元素(所有的结果)
    classList = [example[-1] for example in dataSet]
    #当划分结果完全一样时,停止划分,跳出循环
    if classList.count(classList[0]) == len(classList):
        #返回划分的结果
        return classList[0]
    #如果所有的特征遍历完时(因为是递归,每次都会把参数数据集dataSet划分,划分到最后,只剩下最后一列)
    if len(dataSet[0]) == 1:
        #返回出现次数最多的结果
        return majorityCnt(classList)
    #获取信息增益最大的特征下标(即影响最大的特征下标)
    bestFeat = chooseBestFeatureToSplit(dataSet)
    #获取信息增益最大的特征
    bestFeatLabel = labels[bestFeat]
    #创建根节点为bestFeatLabel的树(字典)
    myTree = {bestFeatLabel:{}}
    #在labels特征集中删除该特征
    del(labels[bestFeat])
    #得到下标为bestFeat列(即信息增益最大的特征)的所有取值
    featValues = [example[bestFeat] for example in dataSet]
    #除去重复值
    uniqueVals = set(featValues)
    #遍历该特征的所有取值,为每个取值创建决策树
    for value in uniqueVals:
        #获取当前所有的特征(不包含已经创建树的特征)
        subLabels = labels[:]
        #splitDataSet(dataSet,bestFeat,value):将当前数据集进行划分(获取下标为bestFeat特征,值为value的子数据集)
        #subLabels:当前所有的特征(不包含已经创建树的特征)
        myTree[bestFeatLabel][value]=createTree(splitDataSet(dataSet,bestFeat,value),subLabels)
    return  myTree

# if __name__ =='__main__':
#     dataSet,labels = createDataSet()
#     myTree = createTree(dataSet,labels)
#     print(myTree)

实现结果:

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值