一、概念
决策树:
每个决策或事件(即自然状态)都可能引出两个或多个事件,导致不同的结果,把这种决策分支画成图形很像一棵树的枝干,故称决策树。
目标:
最快的速度到达叶子节点,划分的节点尽量属于同一类
什么时候停止生长:1.到叶子2.拥有相似的属性值3.早期的终止方法!(剪枝)
算法 | 划分属性方法 | 基本思想 |
---|---|---|
ID3 | 信息增益(Info Gain) | 算法的基本思想是,以信息熵为度量用于决策树节点的属性选择,每次优先取信息量最多亦即能使熵值变为最小的属性,以构造一颗下降最快的决策树,到叶子节点处的熵值为0。此时,每个叶子节点对应的实例集中属于同一个类。 |
CART | Gini指数 | 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