《机器学习实战》——决策树

来源:互联网 发布:知乎 中国菜 编辑:程序博客网 时间:2024/06/04 17:46

基本原理:每个数据集都有一个或者多个特征作为已知条件,现在根据这些特征分类。K-近邻算法是已知部分分类,通过比较特征距离来将新的数据划分到旧的分类,但是你不知道它是如何划分,也就不知道分类是什么含义。决策树则是将一堆全新的数据,通过一个一个问答的形式,逐步缩小范围,给出最终分类,行成一个树形图。它通过遍历比较信息熵信息增益选出当前最适合分类的特征,从而得出一系列规则。

(参考博客园描述)因此先回忆一下信息论中有关信息量(就是“熵”)的定义。说有这么一个变量X,它可能的取值有n多种,分别是x1,x2,……,xn,每一种取到的概率分别是P1,P2,……,Pn,那么X的熵就定义为:

意思就是一个变量可能的变化越多(反而跟变量具体的取值没有任何关系,只和值的种类多少以及发生概率有关),它携带的信息量就越大。
对分类系统来说,类别C是变量,它可能的取值是C1,C2,……,Cn,而每一个类别出现的概率是P(C1),P(C2),……,P(Cn),因此n就是类别的总数。此时分类系统的熵就可以表示为:

信息增益是针对一个一个的特征而言的,就是看一个特征t,系统有它和没它的时候信息量各是多少。于是有了条件熵:(1)系统不包含特征t;(2)系统虽然包含特征t,但是t已经固定了,不能变化。

特征X被固定为值xi时的条件熵:

特征X被固定时的条件熵:

注意区别。从刚才计算均值的讨论可以看出来,第二个式子与第一个式子的关系就是:

因此固定t时系统的条件熵就有了,为了区别t出现时的符号与特征t本身的符号,我们用T代表特征,而用t代表T出现,那么:

与刚才的式子对照一下,含义很清楚对吧,P(t)就是T出现的概率,就是T不出现的概率。这个式子可以进一步展开,其中的

另一半就可以展开为:

因此特征T给系统带来的信息增益就可以写成系统原本的熵与固定特征T后的条件熵之差:

关键词:信息熵; 条件熵; 信息增益; 树形图

案例:

信息增益Gain(R)表示属性R给分类带来的信息量,我们寻找Gain最大的属性,就能使分类尽可能的纯,即最可能的把不同的类分开。不过我们发现对所以的属性Info(D)都是一样的,所以求最大的Gain可以转化为求最新的InfoR(D)。这里引入Info(D)只是为了说明背后的原理,方便理解,实现时我们不需要计算Info(D)。举一个例子,数据集D如下:

记录ID年龄输入层次学生信用等级是否购买电脑1青少年高否一般否2青少年高否良好否3中年高否一般是4老年中否一般是5老年低是一般是6老年低是良好否7中年低是良好是8青少年中否一般否9青少年低是一般是10老年中是一般是11青少年中是良好是12中年中否良好是13中年高是一般是14老年中否良好否

  这个数据集是根据一个人的年龄、收入、是否学生以及信用等级来确定他是否会购买电脑,即最后一列“是否购买电脑”是类标。现在我们用信息增益选出最最佳的分类属性,计算按年龄分裂后的信息量:

  整个式子由三项累加而成,第一项为青少年,14条记录中有5条为青少年,其中2(占2/5)条购买电脑,3(占3/5)条不购买电脑。第二项为中年,第三项为老年。类似的,有:

  可以得出Info年龄(D)最小,即以年龄分裂后,分得的结果中类标最纯,此时已年龄作为根结点的测试属性,根据青少年、中年、老年分为三个分支:

  注意,年龄这个属性用过后,之后的操作就不需要年龄了,即把年龄从attributeList中删掉。往后就按照同样的方法,构建D1,D2,D3对应的决策子树。ID3算法使用的就是基于信息增益的选择属性方法。


算法实施:

1. 创建数据集,给出特征标签——createDataSet()

2. 计算香农熵——getShannonEnt()

3. 根据特征、特征值抽出符合条件的分类结果——splitDataSet()

4. 选择最佳划分的特征:每个特征按不同的值划分类别,分别计算各个类别香农熵并相加作为该特征划分的香农熵。用初始香农熵减去求出的新熵即为信息增益。信息增益越大,说明熵越小,包含信息种类越少,该特征就越好。遍历所有特征,选出最大的信息增益,选择该增益对应的特征作为返回值.调用2,3.

——chooseBestFeatureToSplit()

5. 选择最后一个特征内部的最大类返回:作为终止条件——majorityCnt()

6. 创建树:两个终止条件——类别完全相同 or 到达最后一个特征。首先选择最佳划分特征,打印出它的label;删除该label,剩余的标签作为新的递归标签组;针对之前选好的特征,遍历其取值划分出一个类别,在此基础上建立子树。递归调用形成整棵决策树。——createTree()

# coding:utf-8from math import logdef getDataSet():dataSet = [[1,1,'yes'],[1,1,'yes'],[1,0,'no'],[0,1,'no'],[0,1,'no']]labels = ['no surfacing', 'flippers']return dataSet, labelsdef getShangnonEnt(dataset):####### 得到信息熵,首先统计实例总数 #######N = len(dataset)labelCounts = {}for item in dataset:nowLabel = item[-1]if nowLabel not in labelCounts.keys():labelCounts[nowLabel] = 0labelCounts[nowLabel] += 1# 开始求熵shannonEnt = 0.0for key in labelCounts:prob = float(labelCounts[key])/NshannonEnt -= prob * log(prob, 2)return shannonEntdef splitDataSet(dataSet, axis, value):####### 根据特征项axis的value值划分类,并返回该分类 #######newData = []for item in dataSet:if item[axis] == value:reducePart = item[:axis]reducePart.extend(item[axis+1:])newData.append(reducePart)return newDatadef getBestFeatureToSplit(dataSet):###### 计算最大的信息增益,选出最佳划分特征。信息增益:基本熵减新熵######numFeature = len(dataSet[0])-1# 特征总数baseEntropy = getShangnonEnt(dataSet)bestInfoGain = 0.0bestFeature = -1# 选择所有特征,逐个计算for i in range(numFeature):myList = [item[i] for item in dataSet]uniqueList = set(myList)newEntropy = 0.0# 计算当前特征的所有可能值的信息熵for value in uniqueList:subDataSet = splitDataSet(dataSet, i, value)prob = len(subDataSet)/float(len(dataSet))newEntropy += prob * getShangnonEnt(subDataSet)infoGain = baseEntropy - newEntropyif (infoGain > bestInfoGain):bestInfoGain = infoGainbestFeature = iprint("bestFeature",bestFeature)return bestFeaturedef majorityCnt(classList):###### 叶子结点定义:多数表决 ######classCount = {}for vote in classList:if vote not in classCount.keys():classCount[vote] = 0classCount[vote] += 1sortedClassCount = sorted(classCount.iteritems(), \key = operator.itemgetter(1), reverse = True)return sortedClassCountdef createTree(dataSet, labels):classList = [item[-1] for item in dataSet]if classList.count(classList[0]) == len(classList):# 类别完全相同则停止划分return classList[0]if len(dataSet[0]) == 1:# 遍历玩所有特征,返回出现次数最多的return majorityCnt(classList)bestFeat = getBestFeatureToSplit(dataSet)bestFeatLabel = labels[bestFeat]myTree = {bestFeatLabel:{}}del(labels[bestFeat])# 得到列表包含的所有属性值featValues = [item[bestFeat] for item in dataSet]uniqueVals = set(featValues)for value in uniqueVals:subLabels = labels[:]myTree[bestFeatLabel][value] = createTree(splitDataSet(dataSet, bestFeat, value), subLabels)return myTreedataSet, labels = getDataSet()print("dataSet:", dataSet, labels)tree = createTree(dataSet, labels)print("myTree:", tree)


0 0
原创粉丝点击