机器学习实战第三章——决策树,读书笔记

         决策树是一种常见的机器学习方法,也称作“判定树”。决策树是根据树结构来进行决策的,决策过程中提出的每一个判定都是对某个属性的“测试”,每个测试的结果或是导出最终结论,或者导出进一步的判定问题,在测评那种数据划分方式是做好的数据划分的时候,有多种测量方法,其中有一种计算信息增益的方法,叫作香农熵。“信息熵”是用来度量两种概率分布的差异,假设当前样本的集合D中第k类样本所占的比例为pk(k=1,2,...,|y|),则D的信息熵为:

    下面是计算给定数据集的香农熵:

from math import log

def calcShannonEnt(dataSet):
	numEntries=len(dataSet)                                             #numEntries得到的是数据集的大小,保存实例总数
	labelCounts={}                                                     
	for featVec in dataSet:                                             #为了所有数据创建一个字典,方便后面的求每种类的概率                     
		currentLabel=featVec[-1]                                    #创建一个数据字典,健值是最后一列的值,取该数据的特征标签
		if currentLabel not in labelCounts.keys():                  #如果该特征标签不存在
			labelCounts[currentLabels]=0                        #则扩展字典并将当前标签加入字典
		labelCounts[currentLabels]+=1                               #记录每个类别出现的次数
	shannonEnt=0.0
	for key in labelCounts:                                             
		prob=float(labelCounts[key])/numEntries                     #每个类别除以总数,是该类别的概率,也就是上面式子中的pk
		shannonEnt-=prob*log(prob,2)                                *这一行就是上述pk乘以以2为底的对数
	return shannonEnt                                          

测试上面的代码的结果为:

机器学习实战第三章——决策树,读书笔记_第1张图片

下面开始划分数据集:

这个函数的作用是将第axis列中等于value的数据集划分出来

def splitDataSet(dataSet,axis,value):                                #可以看到这个函数有三个输入参数:待划分的数据集,划分数据集的特征以及需要返回的特征的值
	retDataSet=[]                                                #因为该函数在同一个数据集上调用了很多次,所以定义一个新的列表对象
	for featVec in dataSet:                                      #遍历数据集中的每个元素的特征
		if featVec[axis]==value:                             #如果该数据的这个特征的值符合要求
			reducedFeatVec=featVec[:axis]                #axis前几行
			reducedFeatVec.extend(featVec[axis+1:])      #跳过axis,添加之后的之后的
			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)                             #这里的set是一个无序不重复的集合
		newEntropy=0.0
		for value in uniqueVals:
			subDataSet=splitDataSet(dataSet,i,value)     #用这个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.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




下面是一个使用文本注解绘制树节点:

import matplotlib.pyplot as plt 

decisionNode=dict(boxstyle="sawtooth",fc="0.8")
leafNode=dict(boxstyle="round4",fc="0.8")
arrow_args=dict(arrowstyle="<-")

def plotNode(nodeTxt,conterPt,parentPt,nodeType):
	createPlot.ax1.annotate(nodeTxt,xy=parentPt,\
		xycoords='axes fraction',\
		xytext=conterPt,textcoords='axes fraction',\
		va="center",ha="center",bbox=nodeType,arrowprops=arrow_args)

def createPlot():
	fig=plt.figure(1,facecolor='white')
	fig.clf()
	createPlot.ax1=plt.subplot(111,frameon=False)
	plotNode(U'a',(0.5,0.1),(0.1,0.5),decisionNode)
	plotNode(U'a',(0.8,0.1),(0.3,0.8),leafNode)
	plt.show()
产生的效果如下;
机器学习实战第三章——决策树,读书笔记_第2张图片



你可能感兴趣的:(Python)