机器学习实战-决策树实例

决策树

决策树是什么?决策树(decision tree)是一种基本的分类与回归方法。举个通俗易懂的例子,如下图所示的流程图就是一个决策树,长方形代表判断模块(decision block),椭圆形成代表终止模块(terminating block),表示已经得出结论,可以终止运行。从判断模块引出的左右箭头称作为分支(branch),它可以达到另一个判断模块或者终止模块。我们还可以这样理解,分类决策树模型是一种描述对实例进行分类的树形结构。决策树由结点(node)和有向边(directed edge)组成。结点有两种类型:内部结点(internal node)和叶结点(leaf node)。内部结点表示一个特征或属性,叶结点表示一个类。

计算经验熵的代码

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

 - 年龄: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                
#返回数据集和分类属性

"""
函数说明:计算给定数据集的经验熵(香农熵)

Parameters:
    dataSet - 数据集
Returns:
    shannonEnt - 经验熵(香农熵)
"""
def calcShannonEnt(dataSet):
    #返回数据集的行数
    numEntires = len(dataSet)                       
    #保存每个标签(Label)出现次数的字典
    labelCounts = {}                                
    #对每组特征向量进行统计
    for featVec in dataSet:                 
        #提取标签(Label)信息           
        currentLabel = featVec[-1]     
        #如果标签(Label)没有放入统计次数的字典,添加进去               
        if currentLabel not in labelCounts.keys():    
            labelCounts[currentLabel] = 0
        #Label计数
        labelCounts[currentLabel] += 1              
    #经验熵(香农熵)
    shannonEnt = 0.0                                
    #计算香农熵
    for key in labelCounts:                            
        #选择该标签(Label)的概率
        prob = float(labelCounts[key]) / numEntires  
        #利用公式计算
        shannonEnt -= prob * log(prob, 2)     
    #返回经验熵(香农熵)
    return shannonEnt                                

if __name__ == '__main__':
    dataSet, features = createDataSet()
    print(dataSet)
    print(calcShannonEnt(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']]
0.9709505944546686

计算信息增益的代码

from math import log

"""
函数说明:计算给定数据集的经验熵(香农熵)

Parameters:
    dataSet - 数据集
Returns:
    shannonEnt - 经验熵(香农熵)
"""
def calcShannonEnt(dataSet):
    #返回数据集的行数
    numEntires = len(dataSet)                        
    #保存每个标签(Label)出现次数的字典
    labelCounts = {}              
    #对每组特征向量进行统计                  
    for featVec in dataSet:                            
        #提取标签(Label)信息
        currentLabel = featVec[-1]                    
        #如果标签(Label)没有放入统计次数的字典,添加进去
        if currentLabel not in labelCounts.keys():    
            labelCounts[currentLabel] = 0
        #Label计数
        labelCounts[currentLabel] += 1                
    #经验熵(香农熵)
    shannonEnt = 0.0                                
    #计算香农熵
    for key in labelCounts:                            
        #选择该标签(Label)的概率
        prob = float(labelCounts[key]) / numEntires    
        #利用公式计算
        shannonEnt -= prob * log(prob, 2)            
    #返回经验熵(香农熵)
    return shannonEnt                                

"""
函数说明:创建测试数据集

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                             

"""
函数说明:按照给定特征划分数据集

Parameters:
    dataSet - 待划分的数据集
    axis - 划分数据集的特征
    value - 需要返回的特征的值
Returns:
    无
"""
def splitDataSet(dataSet, axis, value):       
    #创建返回的数据集列表
    retDataSet = []
    #遍历数据集
    for featVec in dataSet:                             
        if featVec[axis] == value:
            #去掉axis特征
            reducedFeatVec = featVec[:axis]             
            #将符合条件的添加到返回的数据集
            reducedFeatVec.extend(featVec[axis+1:])     
            retDataSet.append(reducedFeatVec)
    #返回划分后的数据集
    return retDataSet                                      

"""
函数说明:选择最优特征

Parameters:
    dataSet - 数据集
Returns:
    bestFeature - 信息增益最大的(最优)特征的索引值
"""
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                                             

if __name__ == '__main__':
    dataSet, features = createDataSet()
    print("最优特征索引值:" + str(chooseBestFeatureToSplit(dataSet)))

运行结果:

第0个特征的增益为0.083
第1个特征的增益为0.324
第2个特征的增益为0.420
第3个特征的增益为0.363
最优特征索引值:2
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

北顾丶

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值