python决策树的应用_【机器学习实战学习笔记(2-2)】决策树python3.6实现及简单应用...

决策树原理及相关概念细节我们知道,决策树的学习算法主要包括3个步骤:特征选择、决策树生成算法、决策树剪枝,我们按照这个思路来一一实现相关功能。

本文的实现目前主要涉及特征选择、ID3及C4.5算法。剪枝及CART算法暂未涉及,后期补上。

1.ID3及C4.5算法基础

前面文章我们提到过,ID3与C4.5的主要区别是特征选择准则的不同:

ID3:信息增益

C4.5:信息增益比

1.1 计算香农熵

不管是这两者的哪一种,都涉及到信息增益的计算,而计算信息增益的基础又是计算香农熵。所以我们先来实现计算香农熵的代码。

from math import log

import operator

# 计算给定数据集的香农熵

def calcShannonEnt(dataSet):

numEntries = len(dataSet)

labelCounts = {}

# 为所有可能分类创建字典

for featVec in dataSet:

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) # 以2为底求对数

return shannonEnt

然后创建书中的数据集,并计算该数据集的香农熵:

# 创建自己的数据集

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

myDat,labels=createDataSet()

myDat # [[1, 1, 'yes'], [1, 1, 'yes'], [1, 0, 'no'], [0, 1, 'no'], [0, 1, 'no']]

calcShannonEnt(myDat) # 0.9709505944546686

1.2 按照给定特征划分数据集

# 按照给定特征划分数据集

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

测试:

splitDataSet(myDat,0,1) # [[1, 'yes'], [1, 'yes'], [0, 'no']]

1.3 选择最优特征

# 选择最好的数据集划分方式

# 选择最好的数据集划分方式

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 # ID3

# infoGain = baseEntropy - newEntropy # C4.5

# 计算最好的信息增益

if (infoGain > bestInfoGain):

bestInfoGain = infoGain

bestFeature = i

return bestFeature

1.4 多数表决实现

在ID3、C4.5算法的停止条件之一是:没有特征可以选择时停止算法,但如果这时该结点类标签依然不是唯一的,此时我们需要决定如何定义该叶子结点。在这种情况下,通常采用多数表决的方法决定该叶子结点的分类。

# 多数表决实现

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),reverse=True)

# Python3中不再支持iteritems(),将iteritems()改成items()

return sortedClassCount[0][0]

对于“多数表决实现”函数的注释:

1.dict.items()

作用:是可以将字典中的所有项,以列表方式返回。因为字典是无序的,所以用items方法返回字典的所有项,也是没有顺序的。

2.operator.itemgetter()

operator模块提供的itemgetter函数用于获取对象的哪些维的数据,参数为一些序号.

3.sorted()函数,排序

list.sort()是对已经存在的列表进行操作,进而可以改变进行操作的列表;

sorted返回的是一个新的list,而不是在原来的基础上进行的操作

2.基于ID3、C4.5生成算法创建决策树

这里主要介绍基于ID3生成算法创建决策树,C4.5只需要在ID3生成决策树代码上将chooseBestFeatureToSplit(dataSet)函数中infoGain = baseEntropy - newEntropy换成infoGain = baseEntropy - newEntropy即可 。

# 创建树的函数代码

def creatTree(dataSet,labels):

classList = [example[-1] for example in dataSet]

labels2 = labels[:]

# 类别完全相同则停止继续划分

if classList.count(classList[0]) == len(classList):

return classList[0]

# 遍历完所有特征时返回出现次数最多的类别

if len(dataSet[0]) == 1:

return majorityCnt(classList)

bestFeat = chooseBestFeatureToSplit(dataSet)

bestFeatLabel = labels2[bestFeat]

myTree = {bestFeatLabel:{}}

del (labels2[bestFeat])

# 得到列表包含的(选定为最佳特征的)所有属性值

featValues = [example[bestFeat] for example in dataSet]

uniqueVals = set(featValues)

for value in uniqueVals:

subLabels = labels2[:] # 复制类标签

# 递归

myTree[bestFeatLabel][value] = creatTree(splitDataSet(dataSet, bestFeat, value),subLabels)

return myTree

对于“creatTree”函数的注释:

1.list.count(obj)

统计某个元素在列表中出现的次数

2.del,list.remove(),list.pop()

del:根据索引位置来删除单个值或指定范围内的值;

list.remove():删除单个元素,删除首个符合条件的元素,按值删除,返回值为空;

list.pop():删除索引位置元素,无参情况下删除最后一个元素,返回删除的元素值;

测试:

myTree = creatTree(myDat, labels)

myTree # {'no surfacing': {0: 'no', 1: {'flippers': {0: 'no', 1: 'yes'}}}}

3.使用决策树进行分类

# 使用决策树的分类函数

def classify(inputTree, featLabels, testVec):

firstStr = list(inputTree.keys())[0]

secondDict = inputTree[firstStr]

featIndex = featLabels.index(firstStr)

for key in secondDict.keys():

if testVec[featIndex] == key:

if type(secondDict[key]).__name__=='dict':

#if isinstance(secondDict[key], dict): 这个也可以

classLabel = classify(secondDict[key],featLabels,testVec)

else:

classLabel = secondDict[key]

return classLabel

对于“classify”的注释:

1.type(a).name == ‘dict’:

可判断a的类型是否类型为dict,list tuple 这些也适用

2.也可以用isinstance(变量名,类型)判断类型:

判断该变量是否是该类型,或者是否是该类和该类的父类类型;

小注:

type(变量名):获取该变量名的类型,结合==判断该变量的类型是否等于目标类型(等号右边value值)

比如:a类继承b类,实例c=a()

isinstance(c,a)和isinstance(c,b)都是True

type(c)的value值是a,a是不等于b的,所以a==b为False即:type(c)==b为False

3.==和is

==:变量名的value值是否相等

is:变量名的id(地址)是否相等(数字类型的value值相等则id相等)

测试:

classify(myTree, labels, [1,0]) # 'no'

classify(myTree, labels, [1,1]) # 'yes'

4.存储决策树

import pickle

# 使用pickle模块存储决策树

def storeTree(inputTree, filename):

with open(filename, 'wb') as f:

pickle.dump(inputTree, f)

# 加载决策树

def grabTree(filename):

with open(filename, 'rb') as f:

return pickle.load(f)

测试:

storeTree(myTree,'classifierStorage.txt')

grabTree('classifierStorage.txt') # {'no surfacing': {0: 'no', 1: {'flippers': {0: 'no', 1: 'yes'}}}}

参考资料:

《机器学习实战》第三章

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值