机器学习实战第3章-决策树(decision tree)

一、概念
决策树:

每个决策或事件(即自然状态)都可能引出两个或多个事件,导致不同的结果,把这种决策分支画成图形很像一棵树的枝干,故称决策树。

目标:

最快的速度到达叶子节点,划分的节点尽量属于同一类
什么时候停止生长:1.到叶子2.拥有相似的属性值3.早期的终止方法!(剪枝)

算法划分属性方法基本思想
ID3信息增益(Info Gain)算法的基本思想是,以信息熵为度量用于决策树节点的属性选择,每次优先取信息量最多亦即能使熵值变为最小的属性,以构造一颗下降最快的决策树,到叶子节点处的熵值为0。此时,每个叶子节点对应的实例集中属于同一个类。
CARTGini指数CART假设决策树是二叉树,内部结点特征的取值为“是”和“否”,左分支是取值为“是”的分支,右分支是取值为“否”的分支。这样的决策树等价于递归地二分每个特征,将输入空间即特征空间划分为有限个单元,并在这些单元上确定预测的概率分布,也就是在输入给定的条件下输出的条件概率分布。
C4.5信息增益率(Info Gain Ratio)C4.5 克服了ID3在应用中的不足,主要体现在: 用信息增益比例/信息增益率来选择属性,克服了用信息增益率来选择属性时偏向于取值多的不足;能够完成对连续属性的离散化处理; 可以处理具有缺少属性值的训练样本; 在数构造过程中或者完成之后,进行剪枝以避免过度拟合;C4.5采用的知识表示形式为决策树,并最终可以形成产生式规则。
二:优缺点
ID3算法:

优点:
1.算法的理论清晰,方法简单,学习能力较强。
缺点:
1.只对比较小的数据集有效,且对噪声比较敏感,当训练数据集加大时,决策树可能会随之改变。
2.只能处理离散数据。

cart算法:

优点:
1.可以生成可以理解的规则。
2.计算量相对来说不是很大。
3.可以处理连续和种类字段。可以回归可以分类。
4.决策树可以清晰的显示哪些字段比较重要
缺点:
1. 对连续性的字段比较难预测。
2.对有时间顺序的数据,需要很多预处理的工作。
3.当类别太多时,错误可能就会增加的比较快。
4.一般的算法分类的时候,只是根据一个字段来分类。

C4.5算法:

优点:产生的分类规则易于理解,准确率较高。
缺点是:在构造树的过程中,需要对数据集进行多次的顺序扫描和排序,因而导致算法的低效。此外,C4.5只适合于能够驻留于内存的数据集,当训练集大得无法在内存容纳时程序无法运行。

三、信息熵、信息增益、Gini指数、信息增益率概念
熵:

是接收的每条消息中包含的信息的平均量,又被称为信息熵、信源熵、平均自信息量。
假如有变量X,其可能的取值有n种,每一种取到的概率为Pi,那么X的熵就定义为这里写图片描述
也就是说X可能的变化越多,X所携带的信息量越大,熵也就越大。对于文本分类或聚类而言,就是说文档属于哪个类别的变化越多,类别的信息量就越大。

信息增益:

特征T给聚类C或分类C带来的信息增益为IG(T)=H(C)-H(C|T)。
H(C|T)包含两种情况:一种是特征T出现,标记为t,一种是特征T不出现,标记为t’。所以H(C|T)=P(t)H(C|t)+P(t’)H(C|t‘),再由熵的计算公式便可推得特征与类别的信息增益公式。
信息增益最大的问题在于它只能考察特征对整个系统的贡献,而不能具体到某个类别上,这就使得它只适合用来做所谓“全局”的特征选择(指所有的类都使用相同的特征集合),而无法做“本地”的特征选择(每个类别有自己的特征集合,因为有的词,对这个类别很有区分度,对另一个类别则无足轻重)。

Gini指数:

是一种不等性度量、通常用来度量收入不平衡,可以用来度量任何不均匀分布、是介于0~1之间的数,0-完全相等,1-完全不相等、总体内包含的类别越杂乱,GINI指数就越大(跟熵的概念很相似,越大越不好,越混乱)
计算公式:
这里写图片描述

这里写图片描述

信息增益率:

信息增益更适合用于大量数值的属性,即倾向于可以取到的数值越多的某个属性。比如用这个属性T直接把训练集的20个数据划分成20类,然后算出IG(T)为0,但是不能这么划分。
计算公式:Gr=[H(C)-H(C|T)]/H(C)

机器学习实战里主要代码加了注释:
from math import log
import numpy as np
import operator
#计算给定数据的香农熵
def calcShannonEnt(dataSet):
    #数据总数
    numEntries=len(dataSet)
    labelCounts={}
    for featVec in dataSet:
        #找出每个数据的标签
        currentLabel=featVec[-1]
        #当前类标签有数目+1;无就设置为0
        if currentLabel not in labelCounts.keys():
            labelCounts[currentLabel]=0
        labelCounts[currentLabel]+=1
    shannonEnt=0.0
    #计算信息熵
    for key in labelCounts:
        prob=float(labelCounts[key])/numEntries
        shannonEnt-=prob*log(prob,2)
    return shannonEnt
#创建数据集
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
#按照给定特征划分数据集
#待划分的数据集/划分数据及的特征/需要返回的特征的值
#按照第axis列属性进行划分,划分的值为value,返回划分后的数据值
#append和extend区别
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
#选择最好的数据集划分方式
def chooseBestFeattureToSplit(dataSet):
    #计算特征数,总列数-1
    numFeatures=len(dataSet[0])-1
    #计算原始香农熵
    baseEntropy=calcShannonEnt(dataSet)
    bestInfoGain=0.0;
    bestFeature=-1
    #第一个for遍历所有特征
    for i in range(numFeatures):
        #计算每类特征有几种不同数值,创建唯一的分类标签列表
        #把某特征的所有数值放进特征列表
        featList=[example[i]for example in dataSet]
        #看看该特征有几种数值
        uniqueVals=set(featList)
        newEntropy=0.0
        #第二个for遍历每个特征里的每种值,计算香农熵
        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 majoriyCnt(classList):
    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]
    #如果某元素(某特征全是一样的)在列表中出现次数等于列表长,返回该特征
    if classList.count(classList[0])==len(classList):
        return classList[0]
    #如果只有一列说明没特征了,投票表决,返回该类别
    if len(classList)==1:
        return  majoriyCnt(classList)
    #找信息熵最小的特征
    bestFeat=chooseBestFeattureToSplit(dataSet)
    bestFeatLabel=labels[bestFeat]
    #按照最好的特征值划分
    myTree={bestFeatLabel:{}}
    #加入树里,然后删除该特征
    del(labels[bestFeat])
    featValues=[example[bestFeat]for example in dataSet]
    uniqueVals=set(featValues)
    for value in uniqueVals:
        #把剩下的所有类别(标签)放进subLabels
        subLabels=labels[:]
        #构造树的下一层,使用处理过的新的数据集和新的标签
        myTree[bestFeatLabel][value]=createTree(splitDataSet(dataSet,bestFeat,value),subLabels)
    return myTree
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值