决策树笔算和python代码实现

来源:互联网 发布:caffe pdf百度云 编辑:程序博客网 时间:2024/04/28 01:46
本次的学习笔记是决策树,顾名思义,它的分类图形特别像一棵树,分类就是从树干开始根据规则进行分类到枝,再从这个枝细分到下一个子枝。。。,举个栗子,根据下面5条数据来划分对美女感觉的好差。那么就得根据她们的两个特征进行判断,那么你可能会得到这么个结论不会打扮的一定感觉不好,会打扮的人中身材好的感觉好,身材不好的感觉差。
那么问题来了,为什么你是先根据“会打扮”这个特征进行先划分的?也许你会说拿“会打扮”先分,直接就可以分出两条数据,而拿“身材好”分,第一次只能划分出一条数据。这里面其实就是潜移默化的应用了信息熵的概念。就是将信息进行量化后进比较,从而根据信息量大的进行划分数据集。





机器学习中的决策树其实就是解决如下几个问题:
1、信息熵怎么计算?
2、优先选哪个特征进行划分,主要根据信息增益来衡量。
3、数据集分到啥时候算完事?

———————————————————————————————————————————————————
笔算过程
1、计算数据集的熵,即训练集T,H(T)= -p× log2p-p× log2p=-(2/5)×log2(2/5) - (3/5)×log2(3/5) ≈ 0.971
2、计算“会打扮”属性的子集的熵:
H(会打扮 = 是)= -p× log2 p-p× log2 p=-(2/3)×log2(2/3) - (1/3)×log2(1/3) ≈ 0.918
H(会打扮 = 否)= -p× log2 p-p× log2 p=-(0/2)×log2(0/2) - (2/2)×log2(2/2) = 0
得到子集的熵的期望值:
H(T, 会打扮)= p(会打扮 = 是) × H(会打扮 = 是)+ (会打扮 = 否) × H(会打扮 = 否)
= (3/5) × 0.918+ (2/5) × 0≈0.551
3、同理计算出H(T, 身材好)= 0.80
4、计算信息增益:
I(T, 会打扮)=H(T) - H(T, 会打扮)= 0.971 - 0.551 ≈ 0.42
I(T, 身材好)=H(T) - H(T, 身材好)= 0.971 - 0.80 ≈ 0.17
因此,“会打扮”这个特征具有更高的信息增益,贡献了最大的信息量。
———————————————————————————————————————————————————

———————————————————————————————————————————————————
python实现过程
那么我们利用python根据上面一步步来:
第一步,老规矩,先引入包,告诉python你要用到哪些工具
from numpy import *
import opertare
from math import log

第二步,告诉程序信息熵怎么计算

def calcShannonEnt(dataSet):
#计算数据集dataSet总数用于计算概率
numEntries = len(dataSet)
#统计每个出现的频率
labelCounts = {}
for fentVec in dataSet:
currentLabel = fentVec[-1]
if currentLabel not in labelCounts.keys():
labelCounts[currentLabel] = 0
labelCounts[currentLabel] += 1
#计算信息熵
shangnonEnt = 0.0
for key in labelCounts:
prob = float(labelCounts[key])/numEntries
shangnonEnt -=prob * log(prob, 2)
return shangnonEnt

第三步,根据特征、标签计算出来的信息熵如何划分数据
#按特征值划分数据集
def splitDataSet(dataSet, axis, value):
#实现把第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.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 * calcShannonEnt(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.items(), key = operator.itemgetter(1), resverse = True)
return sortedClassCount[0][0]

#第六步,把上面的组装起来,创建决策树的函数
def createTree(dataSet, labels):
#将标签列,用列表推导式放到列表中,用来判断是不是可以结束分类
classList = [example[-1] for example in dataSet]
#类别完全相同则停止继续划分,即结论就一种情况了。str.count('a',2,10)统计str列表中‘a'出现的次数。
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 = ['会打扮', '身材好']
myTree = createTree(dataSet, labels)
print(myTree)

#输出结果为:{'会打扮': {'否': '差', '是': {'身材好': {'否': '差', '是': '好'}}}}
这其实就是训练出来的结果,即辨别感觉好差的规则。
———————————————————————————————————————————————————
以上均为本人的学习笔记及心得体会,如有错误望指点,感激涕零哭
原创粉丝点击