1.决策树
1.1决策树原理
决策树模型基于特征对实例进行分类,它是一种树状结构。
决策树每一个叶节点对应着一个分类,非叶节点对应着在某个属性上的划分,根据样本在该属性上的不同取值将其划分成若干个子集。对于非纯的叶节点,多数类的标号给出到达这个节点的样本所属的类。
常用的决策树算法见下表。
决策树算法分类
决策树算法 | 算法描述 |
ID3算法 | 采用信息增益作为特征选择的度量,只适用于离散的描述属性 |
ID4.5算法 | 采用信息增益率作为特征选择的度量,既能处理离散的描述属性,也可以处理连续的属性 |
CART算法 | 当终结点是连续变量时,该树为回归树;当终结点是分类变量时,该树为分类树 |
1.2构建决策树
构建决策树通常包括3个步骤:特征选择,决策树生成和决策树剪枝。
假设给定训练集
,其中
为输入实例, n
为特征个数;
为类标记,i=1,2,...,N ; N 为样本容量。构建决策树的目标是,根据给定的训练数据集学习一个决策树模型。
1.2.1特征选择
特征选择就是选取有较强分类能力的特征,分类能力通过信息增益或者信息增益比(即你所选取的决策树算法)来刻画。
选择特征的标准时找出最优的特征作为判断进行数据切划,划分数据的目的是将无序的数据变得有序,衡量有序的参数有熵、基尼系数和方差,前两个针对分类,后者针对回归。
ID3算法基于信息熵来选择最优特征,它选择当前样本集中具有最大信息增益值的特征作为最优特征。
在划分数据集之前之后信息发生的变化称为信息增益,知道如何计算信息增益,我们就可以计算每个特征值划分数据集获得的信息增益,获得信息增益最高的特征就是最好的选择。
给出熵entropy的定义如下。
设X是一个离散型随机变量,其概率分布为
则随机变量X的熵为
对于数据集S,通过 H(S)来描述数据集的不确定程度,即信息熵。
给定特征A和训练数据集S,定义信息增益为
。
信息增益描述的是由于特征而使得对数据的分类的不确定性减少的程度,构建决策树选择信息增益大的特征来划分数据集。显然H(D/A)越小,Gain(D,A)越大,说明选择特征A对于分类提供的信息越大,选择A之后对分类的不确定程度越小。
1.2.2决策树生成
ID3算法的具体详细实现步骤如下。
(1)对当前样本集合,计算所有特征的信息增益;
(2)选择信息增益最大的特征作为测试特征值,把测试特征取值相同的样本划为同一个子样本集;
(3)若子样本集的类别特征只含有单个特征,则分支为叶子节点,判断其特征值并标上相应的符号,然后返回调用处;否则对子样本集递归调用本算法。
1.2.3决策树剪枝
决策树需要剪枝的原因是:决策树生成算法生成的树对训练数据的预测很准确,但是对于未知的数据分类却很差,容易产生过拟合现象。决策树构建是直到没有特征可选或
者信息增益很小,这会导致模型太复杂。解决过拟合的方法就是控制模型的复杂度,即简化模型,称为剪枝。
剪枝的目标是通过极小化决策树的整体损失函数或代价函数来实现的。
设树T的叶节点个数为 |Tf|,t为树的叶节点,该叶节点有个Nt样本点,其中属于ck类的样本点有 Ntk,k=1,2,...K个。
令H(t)为叶节点上的信息熵,a>=0为参数,则决策树的T损失函数定义为:
剪枝算法实现步骤如下。
(1)对当前决策树,计算每个叶节点的信息熵。
(2)递归地从树的叶节点向上回退:设一组叶节点回退到父节点之前与之后的整棵树分别为Tt与Tt',对应的损失函数值分别为Ca(Tt)与Ca(Tt')。若Ca(Tt)<=Ca(Tt'),则进行剪枝并将父节点变成新的叶节点。
1.3决策树Python实现
#-*-coding:utf-8-*-
from math import log
import operator
#生成数据
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
#计算给定数据的熵
def calcEntropy(dataSet):
numEntries=len(dataSet)
labelCounts={}
for featVec in dataSet:
currentLabel=featVec[-1]
if currentLabel not in labelCounts.keys():
labelCounts[currentLabel]=0
labelCounts[currentLabel]+=1
Entropy=0.0
for key in labelCounts:
prob=float(labelCounts[key])/numEntries
Entropy-=prob*log(prob,2)
return Entropy
#按照给定特征划分数据集
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=calcEntropy(dataSet)
bestInfoGain=0.0
bestFeature=-1
#对所有特征分类进行熵计算
for i in range(numFeatures):
#把该特征的所有取值放在列表里
featList=[example[i] for example in dataSet]
#只保留不重复的特征的值
uniqueVals=set(featList)
newEntropy=0.0
#计算每种划分方式的信息熵
for value in uniqueVals:
subDataSet=splitDataSet(dataSet,i,value)
prob=len(subDataSet)/float(len(dataSet))
newEntropy+=prob*calcEntropy(subDataSet)
infoGain=baseEntropy-newEntropy
if(infoGain>bestInfoGain):
bestInfoGain=infoGain
bestFeature=i
return bestFeature
#采用多数表决的方法决定无法定义的叶子节点的分类
def majorityCnt(classList):
classCount={}
for vote in classList:
if vote not in classCount.keys():
classCount[vote]=0
classCount[vote]+=1
sortedClassCount=sorted(classCount.iteritems(),
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(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__':
myDat,labels=createDataSet()
print createTree(myDat,labels)
代码参考:机器学习实战