决策树及代码实现

“信息熵”(information entropy)是度量样本集合纯度的一种常用指标。商越小代表纯度越高。商越大越混乱。
熵的计算公式在这里插入图片描述
其中在这里插入图片描述为集合中第K类属性所占样本的比例。Ent(D)的值越小,则D的纯度越高

信息增益
在这里插入图片描述
开始的ID3算法就是根据信息增益来进行分类的。
通过不断得到信息增益最大的特征作为分类的依据,不断划分。缺点是倾向于可取数目多的属性有所偏好;

C4.5算法使用增益率来选择最优的划分属性,但是对可取数目较少的属性有所偏好:
在这里插入图片描述
在这里插入图片描述

代码的实现与公式一致,不断拿信息增益最大的特征进行分类,直到分类结束–特征使用完毕。

看到有个例子使用了信息熵和条件熵,这里用来方便理解。

信息熵是代表随机变量的复杂度(不确定度),条件熵代表在某一个条件下,随机变量的复杂度(不确定度)
而我们的信息增益恰好是:信息熵-条件熵。
换句话说,信息增益代表了在一个条件下,信息复杂度(不确定性)减少的程度。

如果选择一个特征后,信息增益最大(信息不确定性减少的程度最大),那么我们就选取这个特征。
在这里插入图片描述
求得随机变量X(嫁与不嫁)的信息熵为:嫁的个数为6个,占1/2,那么信息熵为-1/2log1/2-1/2log1/2 = -log1/2=0.301

现在假如我知道了一个男生的身高信息。

身高有三个可能的取值{矮,中,高} 矮包括{1,2,3,5,6,11,12},嫁的个数为1个,不嫁的个数为6个中包括{8,9} ,嫁的个数为2个,不嫁的个数为0个高包括{4,7,10},嫁的个数为3个,不嫁的个数为0个。

我们先求出公式对应的:
H(Y|X = 矮) = -1/7log1/7-6/7log6/7=0.178

H(Y|X=中) = -1log1-0 = 0

H(Y|X=高) = -1log1-0=0

p(X = 矮) = 7/12,p(X =中) = 2/12,p(X=高) = 3/12

则可以得出条件熵为:

7/120.178+2/120+3/12*0 = 0.103

那么我们知道信息熵与条件熵相减就是我们的信息增益,为

0.301-0.103=0.198

所以我们可以得出我们在知道了身高这个信息之后,信息增益是0.198

代码实现:

# -*- coding: utf-8 -*-
"""
Created on Thu Dec 20 00:17:49 2018
@author: keqkeq
"""
 
from math import log
import operator
 
def calcShannonEnt(dataSet):  # 计算数据的熵(entropy)
    numEntries=len(dataSet)  # 数据条数
    labelCounts={}
    for featVec in dataSet:
        currentLabel=featVec[-1] # 每行数据的最后一个是类别
        if currentLabel not in labelCounts.keys():
            labelCounts[currentLabel]=0
        labelCounts[currentLabel]+=1  # 统计有多少个类以及每个类的数量
    shannonEnt=0
    for key in labelCounts:
        prob=float(labelCounts[key])/numEntries # 计算单个类的熵值
        shannonEnt-=prob*log(prob,2) # 累加每个类的熵值
    return shannonEnt
 
def createDataSet1():    # 创造示例数据
    dataSet = [['0_5K', 'Bad','Low', 'Reject'],
               ['0_5K', 'Good', 'Low','Approve'],
               ['0_5K', 'Unknown', 'High','Reject'],
               ['0_5K', 'Unknown', 'Low','Approve'],
               ['0_5K', 'Unknown', 'Low','Approve'],
               ['0_5K', 'Unknown', 'Low','Reject'],
               ['5_10K', 'Bad', 'High','Reject'],
               ['5_10K', 'Good', 'High','Approve'],
               ['5_10K', 'Unknown', 'High','Approve'],
               ['5_10K', 'Unknown', 'Low','Approve'],
               ['Over_10K', 'Bad', 'Low','Reject'],
               ['Over_10K', 'Good', 'Low','Approve']]
    labels = ['Income','Credit_History','Debt']  #三个特征
    return dataSet,labels
 
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
 
def chooseBestFeatureToSplit(dataSet):  # 选择最优的分类特征
    numFeatures = len(dataSet[0])-1
    baseEntropy = calcShannonEnt(dataSet)  # 原始的熵
    bestInfoGain = 0
    bestFeature = -1
    for i in range(numFeatures):
        featList = [example[i] for example in dataSet]
        uniqueVals = set(featList)
        newEntropy = 0
        for value in uniqueVals:
            subDataSet = splitDataSet(dataSet,i,value)
            prob =len(subDataSet)/float(len(dataSet))
            newEntropy +=prob*calcShannonEnt(subDataSet)  # 按特征分类后的熵
        infoGain = baseEntropy - newEntropy  # 原始熵与按特征分类后的熵的差值
        if (infoGain>bestInfoGain):   # 若按某特征划分后,熵值减少的最大,则次特征为最优分类特征
            bestInfoGain=infoGain
            bestFeature = i
    return bestFeature
 
def majorityCnt(classList):    #按分类后类别数量排序,消除噪音,比如:最后分类为2R1A,则判定为R;
    classCount={}
    for vote in classList:
        if vote not in classCount.keys():
            classCount[vote]=0
        classCount[vote]+=1
    sortedClassCount = sorted(classCount.items(),key=operator.itemgetter(1),reverse=True)
    return sortedClassCount[0][0]
 
def createTree(dataSet,labels):
    classList=[example[-1] for example in dataSet]  # 类别:Reject or Approve
    if classList.count(classList[0])==len(classList):
        return classList[0]
    if len(dataSet[0])==1:
        return majorityCnt(classList)
    bestFeat=chooseBestFeatureToSplit(dataSet) #选择最优特征
    bestFeatLabel=labels[bestFeat]
    myTree={bestFeatLabel:{}} #分类结果以字典形式保存
    del(labels[bestFeat])
    featValues=[example[bestFeat] for example in dataSet]
    uniqueVals=set(featValues)
    for value in uniqueVals:
        subLabels=labels[:]
        myTree[bestFeatLabel][value]=createTree(splitDataSet\
                            (dataSet,bestFeat,value),subLabels)
    return myTree
 
 
if __name__=='__main__':
    dataSet, labels=createDataSet1()  # 创造示列数据
    print(createTree(dataSet, labels))  # 输出决策树模型结果

GIni计算实例

在这里插入图片描述
其中是否逾期为我们的目标变量,这是一个二分类的问题,上面公式中的n = 2,那么要对每个字段的每一种切割方法计算Gini不纯度:在这里插入图片描述
在这个节点如果按照性别分割Gini不纯度为0.4283。

教育程度:
第一种分割方法:把高中及以下和本科/大专分到一组,硕士及以上单独一组。
在这里插入图片描述
第二种分割方法:把高中及以下和硕士及以上分到一组,本科/大专单独一组
在这里插入图片描述
第三种分割方法:把本科/大专和硕士及以上分到一组,高中及以下单独一组在这里插入图片描述
可以看到在教育程度的三种切割方法中,第二种(把高中及以下和硕士及以上分到一组,本科/大专单独一组)有最小的Gini不纯度0.3667。

年龄:年龄为连续型变量,一共有14个不同的取值,每两个相邻值之间都可以是一个切割点,一共有13种不同的切割方法,切割点往往选择为两个相邻值的均值。在这里插入图片描述
在这13种切割方法中最小的Gini不纯度为0.4105。再对比根据性别、教育程度和年龄切割的三个Gini不纯度可以得出,在这个节点应该根据教育程度进行切割,且将高中及以下和硕士及以上分到一组,本科/大专单独一组。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值