机器学习实战(Machine Learning in Action)学习笔记————03.决策树原理、源码解析及测试

时间:2022-04-22 20:19:38

机器学习实战(Machine Learning in Action)学习笔记————03.决策树原理、源码解析及测试

关键字:决策树、python、源码解析、测试
作者:米仓山下
时间:2018-10-24
机器学习实战(Machine Learning in Action,@author: Peter Harrington)
源码下载地址:https://www.manning.com/books/machine-learning-in-action
git@github.com:pbharrin/machinelearninginaction.git

*************************************************************
一、决策树的原理及源码解析

文件:trees.py,是ID3决策树算法的实现。代码中的主要方法:

createDataSet----创建例子中的数据集5行×3列,即五条数据,前两列为特征,最后一列为是否为鱼类;lable为两个特征的含义'no_surfacing'(不浮出水是否可以生存),'flippers'(是否有脚蹼)

例子:五个海洋生物,两个特征:不浮出水是否可以生存;是否有脚蹼。利用决策树将这些动物分成两类。
数据要求:第一,数据必须是一种列表元素组成的列表,而且所有的列表元素都要具有相同的的数据长度;第二,数据的最后一列或则每个实例的最后一个元素是当前实例的类别标签。

#香农熵的计算
calcShannonEnt----计算给定数据集的香农熵,熵是集合信息的度量方式,公式

#按照信息增益选取最好的特征
chooseBestFeatureToSplit----选择最好的数据集划分方式,返回最好的特征(按照该特征分类的信息增益最大)索引。原理:遍历所有特征,按照当前特征将其划分(splitDataSet)为多个数据集,然后求他们信息熵的和。其中信息增益是熵的减少或则无序减少程度,这里是前原始数据集的信息熵与分类后的信息熵之差。最后选取信息增益最大的特征,返回对应的列索引

#数据集切分
splitDataSet----按照给定特征(axis)的值(value)划分数据集dataset
================================================================
#决策树构建
createTree----决策树构建代码,是一个递归函数

原理:得到原始数据集,然后基于最好的属性值划分数据集,由于特征值可能多于两个,因此可能存在大于两个分支的数据集划分。第一次划分之后,数据将被向下传递到树分支的下一个节点,在这个节点上,再次划分数据。因此我们采用递归的原则处理数据集。递归结束的条件:遍历完所有划分数据集的属性,或则每个分支下的所有实例都具有相同的类(任何到达叶节点的数据必然属于叶节点的分类)。第一种情况,如果遍历完所有的属性,但当前节点类标签不唯一时,通过多数表决的方法(majorityCnt)来确定叶节点的分类。

majorityCnt----多数表决的算法实现返回对应的类别

createTree代码解析:

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:{}} #构建节点(字典,key为最佳的标签)
del(labels[bestFeat]) #删除已采用标签
featValues = [example[bestFeat] for example in dataSet] #获取最佳特征列的值
uniqueVals = set(featValues) #取得其不重复集合
for value in uniqueVals: #遍历
subLabels = labels[:] #copy all of labels, so trees don't mess up existing labels
myTree[bestFeatLabel][value] = createTree(splitDataSet(dataSet, bestFeat, value),subLabels) #在上面节点上增加节点,利用该特征值取值下的数据集,递归
return myTree
>>> import trees
>>> import treePlotter
>>> data,lable=trees.createDataSet()
>>> data
[[, , 'yes'], [, , 'yes'], [, , 'no'], [, , 'no'], [, , 'no']]
>>> lable
['no surfacing', 'flippers']
>>> mytree=trees.createTree(data,lable)
>>> mytree
{'no surfacing': {: 'no', : {'flippers': {: 'no', : 'yes'}}}}

================================================================
#利用构建的树完成测试样本的分类。
#原理:程序比较测试数据与决策树上的数值,递归执行该过程直到进入叶子节点;最后将测试数据定义为叶子节点所属的类型
classify----利用构建的树完成测试样本的分类

def classify(inputTree,featLabels,testVec):
firstStr = inputTree.keys()[0] #获取根节点的key,即采用的第一个特征(只有一个)
secondDict = inputTree[firstStr] #获取根节点的子节点(有多个)
featIndex = featLabels.index(firstStr) #获取获取第一个特征的所在的列索引
key = testVec[featIndex] #取出测试数据对应特征的值
valueOfFeat = secondDict[key] #取出树第二层中key与测试数据相等的节点
if isinstance(valueOfFeat, dict): #判断取出的节点是否是dict对象
classLabel = classify(valueOfFeat, featLabels, testVec) #是,说明还有子节点,继续寻找
else: classLabel = valueOfFeat #否,说明已经到达叶节点,返回其类别
return classLabel

测试:

>>> import trees
>>> import treePlotter
>>> data,lable=trees.createDataSet()
>>> data
[[1, 1, 'yes'], [1, 1, 'yes'], [1, 0, 'no'], [0, 1, 'no'], [0, 1, 'no']]
>>> lable
['no surfacing', 'flippers']
>>> mytree=trees.createTree(data,lable)
>>> mytree
{'no surfacing': {0: 'no', 1: {'flippers': {0: 'no', 1: 'yes'}}}} >>> data,lable=trees.createDataSet()#重置lable
>>> trees.classify(mytree,lable,[0,0])#利用构建的树对测试数据分类
'no'
>>>

#其他方法
storeTree----利用pickle将构建的树对象序列化保存到本地

grabTree----利用pickle加载保存在本地的树文件,构建树

trees.py源码(测试见后文)

'''
Created on Oct 12, 2010
Decision Tree Source Code for Machine Learning in Action Ch. 3
@author: Peter Harrington
'''
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']
#change to discrete values
return dataSet, labels def calcShannonEnt(dataSet):
numEntries = len(dataSet)
labelCounts = {}
for featVec in dataSet: #the the number of unique elements and their occurance
currentLabel = featVec[-1]
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) #log base 2
return shannonEnt def splitDataSet(dataSet, axis, value):
retDataSet = []
for featVec in dataSet:
if featVec[axis] == value:
reducedFeatVec = featVec[:axis] #chop out axis used for splitting
reducedFeatVec.extend(featVec[axis+1:])
retDataSet.append(reducedFeatVec)
return retDataSet def chooseBestFeatureToSplit(dataSet):
numFeatures = len(dataSet[0]) - 1 #the last column is used for the labels
baseEntropy = calcShannonEnt(dataSet)
bestInfoGain = 0.0; bestFeature = -1
for i in range(numFeatures): #iterate over all the features
featList = [example[i] for example in dataSet]#create a list of all the examples of this feature
uniqueVals = set(featList) #get a set of unique values
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 #calculate the info gain; ie reduction in entropy
if (infoGain > bestInfoGain): #compare this to the best gain so far
bestInfoGain = infoGain #if better than current best, set to best
bestFeature = i
return bestFeature #returns an integer 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]#stop splitting when all of the classes are equal
if len(dataSet[0]) == 1: #stop splitting when there are no more features in dataSet
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[:] #copy all of labels, so trees don't mess up existing labels
myTree[bestFeatLabel][value] = createTree(splitDataSet(dataSet, bestFeat, value),subLabels)
return myTree def classify(inputTree,featLabels,testVec):
firstStr = inputTree.keys()[0]
secondDict = inputTree[firstStr]
featIndex = featLabels.index(firstStr)
key = testVec[featIndex]
valueOfFeat = secondDict[key]
if isinstance(valueOfFeat, dict):
classLabel = classify(valueOfFeat, featLabels, testVec)
else: classLabel = valueOfFeat
return classLabel def storeTree(inputTree,filename):
import pickle
fw = open(filename,'w')
pickle.dump(inputTree,fw)
fw.close() def grabTree(filename):
import pickle
fr = open(filename)
return pickle.load(fr)

****************************************************************
二、利用matplotlib实现tree可视化

文件:treePlotter.py,代码中的主要方法:

其中方法createPlot可以将传给它的tree可视化展现出来

plotMidText----连线中间文字
plotTree----构建树
createPlot----主入口,将传给它的tree可视化展现出来

#获取叶节点的数目和树的层数
getNumLeafs----叶节点的数目
getTreeDepth----树的层数

#创建测试数据
retrieveTree----定义了两个树

#使用文本注解绘制树节点
plotNode----使用文本注解绘制树节点

treePlotter.py源码(测试见后文)
*************************************************************
三、测试实现决策树分类

>>> em=trees.calcShannonEnt(test_tree_data[0])#计算测试数据熵
>>> em
0.9709505944546686
>>> >>> import trees
>>> import treePlotter
>>> test_tree_data=trees.createDataSet()#测试数据
>>> test_tree_data
([[1, 1, 'yes'], [1, 1, 'yes'], [1, 0, 'no'], [0, 1, 'no'], [0, 1, 'no']], ['no surfacing', 'flippers'])
>>> mytree=trees.createTree(*test_tree_data)#构建决策树
>>> mytree
{'no surfacing': {0: 'no', 1: {'flippers': {0: 'no', 1: 'yes'}}}}
>>> treePlotter.createPlot(mytree)#可视化树

aaarticlea/png;base64,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+/Xb3/627PXk5ORKPe+uXbvUqFEj1a9fv1LPA8/BEjAAW+jatavq16+vzz//XJZlVdhxLcvS559/rvr166tr164Vdlx4p44dO6pRo0b67LPP5HK5quSc+fn52rhxo1566SX2r0QZH6si/yYEADc2Z84cjRkzRvfdd5+6dOmili1bKiwsTGFhYapfv76qV69+0/eXlJTo1KlTZXsDpqWlKSUlRd9//70++ugjjR49uoq+E3iyefPmafjw4QoNDVWbNm308MMPq379+qpTp45CQ0MVGhqqWrVqlWsT5+LiYuXn5ys/P19nzpxRfn6+nE6nDhw4oEOHDikkJESpqansX4kyFEAAtrJ582YtXbpUa9euVVZW1lV/du+99151X9YvlZaWqqCg4KrXHnjgAfXs2VMvv/yyfve731VaZnifnTt3atWqVUpJSdGePXuuubZ8fHwUEhJyw+vxl4qLi1VYWHjN+xs1aqTOnTurS5cuevnll9kXEFehAAKwrZKSEjmdTuXk5CgnJ0c//PDDDZeHfXx81LBhQ0VERCgiIkKNGze+5cQQuF1FRUU6efLkVV9nzpy5rWXigIAANWjQ4KqvunXr8hg43BQFEAAAwGb4EAgAAIDNUAABAABshgIIAABgMxRAAAAAm6EAAgAA2AwFEAAAwGYogAAAADZDAQQAALAZCiAAAIDNUAABAABshgIIAABgMxRAAAAAm6EAAgAA2AwFEAAAwGYogAAAADZDAQQAALAZCiAAAIDNUAABAABshgIIAABgMxRAAAAAm6EAAgAA2AwFEAAAwGYogAAAADZDAQQAALAZCiAAAIDNUAABAABshgIIAABgMxRAAAAAm6EAAgAA2AwFEAAAwGYogAAAADZDAQQAALAZCiAAAIDNUAABAABshgIIAABgMxRAAAAAm6EAAgAA2AwFEAAAwGYogAAAADZDAQQAALCZ/w9CwPoz0a+hwAAAAABJRU5ErkJggg==" alt="" width="568" height="426" />

(图Figure_1-1.png)

>>> test_tree_data=trees.createDataSet()#注意上面数据已经改变了test_tree_data[1],即lable
>>> trees.classify(mytree,test_tree_data[1],[0,0])
'no'

--------------------------------------------------------------------------
#测试眼镜的例子:特征包括['age','prescript','astigmatic','tearRate'],类别包括['lenses','soft','hard']

>>> import trees
>>> import treePlotter
>>> fr=open('lenses.txt')
>>> lenses=[inst.strip().split('\t') for inst in fr.readlines()]
>>> lenseslable=['age','prescript','astigmatic','tearRate']
>>> lensestree=trees.createTree(lenses,lenseslable)
>>> lensestree
{'tearRate': {'reduced': 'no lenses', 'normal': {'astigmatic': {'yes': {'prescript': {'hyper': {'age': {'pre': 'no lenses', 'presbyopic': 'no lenses', 'young': 'hard'}}, 'myope': 'hard'}}, 'no': {'age': {'pre': 'soft', 'presbyopic': {'prescript': {'hyper': 'soft', 'myope': 'no lenses'}}, 'young': 'soft'}}}}}}
>>> treePlotter.createPlot(lensestree)

机器学习实战(Machine Learning in Action)学习笔记————03.决策树原理、源码解析及测试

(图:测试眼)
存在问题:该树的匹配选项过多,过度匹配

最后提醒,使用这里的方法时,注意前文提到的数据要求