代码及数据:https://github.com/zle1992/MachineLearningInAction

决策树

优点:计算复杂度不高,输出结果易于理解,对中间值的缺失不敏感,可以处理不相关特征数据。
缺点:可能会产生过度匹配问题。
适用数据类型:数值型和标称型。

创建分支的伪代码函数createBranch()如下所示:
检测数据集中的每个子项是否属于同一分类:
if so return 类标签;
Else
  寻找划分数据集的最好特征
  划分数据集
  创建分支节点
    for 每个划分的子集
      调用函数createBranch并增加返回结果到分支节点中
return 分支节点
上面的伪代码createBranch是一个递归函数,在倒数第二行直接调用了它自己。后面我们
寄把上面的伪代码转换为Python代码,这里我们需要进一步了解算法是如何划分数据集的。

1决策树构造

1.1创建数据

 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

1.2信息增益

如果看不明白什么是信息增益(information gain)和墒( entropy ),请不要着急—创门自
诞生的那一天起,就注定会令世人十分费解。
嫡定义为信息的期望值,在明晰这个概念之前,我们必须知道信息的定义。如果待分类的事
务可能划分在多个分类之中,则符号xi,的信息定义为

其中P(xi)是选择该分类的概率。
为了计算嫡,我们需要计算所有类别所有可能值包含的信息期望值,通过下面的公式得到:

其中n是分类的数目。

程序:计算给定数据集的香农熵

 def calcShannonEnt(dataSet):
numEntries = len(dataSet) #Data 的大小N,N行
labelCount = {}#字典存储 不同类别的个数
for featVec in dataSet :
currentLabel = featVec[-1] #每行的最后一个是类别
if currentLabel not in labelCount.keys():
labelCount[currentLabel] = 0
labelCount[currentLabel] += 1 #原书缩进错误!!!
shannonEnt = 0.0
for key in labelCount:
prob = float(labelCount[key])/numEntries
shannonEnt -= prob *math.log(prob,2) #熵最后外面有个求和符号 !!!
return shannonEnt

1.3划分数据集

程序:划分数据集

 def splitDataSet(dataSet,axis,value):
retDataSet = []
for featVec in dataSet:
if featVec[axis] == value:
#去掉axis 这一列
reducedFeatVec = featVec[:axis]
reducedFeatVec.extend(featVec[axis+1: ])
retDataSet.append(reducedFeatVec)
return retDataSet

划分数据集之后,使得划分后的纯度越小。选择信息增益最大的划分。

程序:选择最好的数据集划分方式

 def chooseBestFeatureTopSplit(dataSet):
#列数 = len(dataset[0])
#行数 = len(dataset)
numFeatures = len(dataSet[0]) -1 #最后一列是标签
baseEntropy = calcShannonEnt(dataSet) #所有数据的信息熵
bestInfoGainn = 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:#在第i个属性里,遍历第i个属性所有不同的属性值
subDataSet = splitDataSet(dataSet,i,value) #划分数据
prob = len(subDataSet)/float(len(dataSet)) #len([[]]) 行数
newEntropy += prob *calcShannonEnt(subDataSet)
infoGain = baseEntropy - newEntropy
if(infoGain > bestInfoGainn):
bestInfoGainn = infoGain
bestFeature = i
return bestFeature

1.4递归构建决策树

 def majorityCnt(classList):
classCount ={}
for vote in classList:
if vote not in classCount.keys():
classCount[vote] = 0
classCount[vote] += 1 classCount = sorted(classCount.items(),key=operator.itemgetter(1),reverse=True) #与python2 不同!!!!!!python3 的字典items 就是迭代对象
return classCount[0][0] #返回的是字典第一个元素的key 即 类别标签
def createTree(dataSet,labels):
#mytree 是一个字典,key 是属性值,val 是类别或者是另一个字典,
#如果val 是类标签,则该子节点就是叶子节点
#如果val是另一个数据字典,则该节点是一个判断节点
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 = chooseBestFeatureTopSplit(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

2在Python中使用Matplotlib注解绘制树形图

2.1使用文本注解绘制树节点

 #定义文本框跟箭头格式
decisionNode = dict(boxstyle="sawtooth", fc="0.8")
leafNode = dict(boxstyle="round4", fc="0.8")
arrow_args = dict(arrowstyle="<-")
def plotNode(nodeTxt, centerPt, parentPt, nodeType):
createPlot.ax1.annotate(nodeTxt, xy=parentPt, xycoords='axes fraction',
xytext=centerPt, textcoords='axes fraction',
va="center", ha="center", bbox=nodeType, arrowprops=arrow_args )

2.2构造注解树

程序:获得叶子节点数与深度

 def getNumLeafs(myTree):
numLeafs = 0
firstStr = list(myTree)[0]#找到第一个节点
secondDict = myTree[firstStr] #第二个节点
for key in secondDict.keys(): #第二节点的字典的key
if type(secondDict[key]).__name__=='dict': #判断第二节点是否为字典
numLeafs += getNumLeafs(secondDict[key]) #第二节点是字典 ,递归调用getNum
else :numLeafs += 1 #第二节点不是字典,说明此节点是最后一个节点
return numLeafs def getTreeDepth(myTree):
maxDepth = 0
firstStr = list(myTree)[0]#找到第一个节点
secondDict = myTree[firstStr] #第二个节点
for key in secondDict.keys(): #第二节点的字典的key
if type(secondDict[key]).__name__=='dict': #判断第二节点是否为字典
thisDepth = 1 + getTreeDepth(secondDict[key]) #第二节点是字典 ,递归调用getNum
else :thisDepth = 1 #第二节点不是字典,说明此节点是最后一个节点
if thisDepth > maxDepth: maxDepth =thisDepth
return maxDepth

程序:plotTree

 def plotMidText(cntrPt, parentPt, txtString):#在父子节点间填充文本信息
xMid = (parentPt[0]-cntrPt[0])/2.0 + cntrPt[0]
yMid = (parentPt[1]-cntrPt[1])/2.0 + cntrPt[1]
createPlot.ax1.text(xMid, yMid, txtString, va="center", ha="center", rotation=30) def plotTree(myTree, parentPt, nodeTxt):
numLeafs = getNumLeafs(myTree) #叶子节点个数
depth = getTreeDepth(myTree) #树的高度
firstStr = list(myTree)[0] #!!!!!!!与py2不同
cntrPt = (plotTree.xOff + (1.0 + float(numLeafs))/2.0/plotTree.totalW, plotTree.yOff) #按照叶子结点个数划分x轴
plotMidText(cntrPt,parentPt,nodeTxt)
plotNode(firstStr,cntrPt,parentPt,decisionNode)
secondDict = myTree[firstStr]
plotTree.yOff = plotTree.yOff - 1.0/plotTree.totalD #plotTree.yOff 全局变量
for key in secondDict.keys():
if type(secondDict[key]).__name__ =='dict':
plotTree(secondDict[key],cntrPt,str(key))# 第二节点是字典,递归调用plotTree
else:
plotTree.xOff = plotTree.xOff + 1.0/plotTree.totalW #x方向计算结点坐标
plotNode(secondDict[key], (plotTree.xOff, plotTree.yOff), cntrPt, leafNode)#绘制子节点
plotMidText((plotTree.xOff, plotTree.yOff), cntrPt, str(key))#添加文本信息
plotTree.yOff = plotTree.yOff + 1.0/plotTree.totalD #下次重新调用时恢复y
def createPlot(inTree):
fig = plt.figure(1, facecolor='white')
fig.clf()
axprops = dict(xticks=[], yticks=[])
createPlot.ax1 = plt.subplot(111, frameon=False, **axprops) # no ticks
# createPlot.ax1 = plt.subplot(111, frameon=False) #ticks for demo puropses
plotTree.totalW = float(getNumLeafs(inTree))
plotTree.totalD = float(getTreeDepth(inTree))
plotTree.xOff = -0.5 / plotTree.totalW
plotTree.yOff = 1.0
plotTree(inTree, (0.5, 1.0), '')
plt.show()

程序:测试

 def retrieveTree(i):
listOfTrees =[{'no surfacing': {0: 'no', 1: {'flippers': {0: 'no', 1: 'yes'}}}},
{'no surfacing': {0: 'no', 1: {'flippers': {0: {'head': {0: 'no', 1: 'yes'}}, 1: 'no'}}}}
]
return listOfTrees[i]
if __name__ == '__main__':
tree = retrieveTree(0)
createPlot(tree)

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':
classLabel = classify(secondDict[key],featLabels,testVec)
else : classLabel = secondDict[key]#到达叶子节点,返回标签
return classLabel

程序:使用pickle保存模型

 def storeTree(inputTree,filename):

     with open(filename,'wb') as f:
pickle.dump(inputTree,f) def grabTree(filename):
with open(filename,'rb') as f:
t = pickle.load(f)
return t

程序:主程序

 if __name__ == '__main__':
#
dataSet,labels = createDataSet()
tree = createTree(dataSet,labels)
storeTree(tree,"tree.model")
tree = grabTree("tree.model")
treePlotter.createPlot(tree) #读取txt文件,预测隐形眼镜的类型
with open('lenses.txt') as f:
lenses = [inst.strip().split('\t') for inst in f.readlines()]
lensesLabels = ['age','prescript','astigmastic','tearRate']
lensesTree = createTree(lenses,lensesLabels)
treePlotter.createPlot(lensesTree)

机器学习实战python3 决策树ID3的更多相关文章

  1. 【Python机器学习实战】决策树和集成学习(一)

    摘要:本部分对决策树几种算法的原理及算法过程进行简要介绍,然后编写程序实现决策树算法,再根据Python自带机器学习包实现决策树算法,最后从决策树引申至集成学习相关内容. 1.决策树 决策树作为一种常 ...

  2. 机器学习实战python3 K近邻(KNN)算法实现

    台大机器技法跟基石都看完了,但是没有编程一直,现在打算结合周志华的<机器学习>,撸一遍机器学习实战, 原书是python2 的,但是本人感觉python3更好用一些,所以打算用python ...

  3. 机器学习实战:决策树的存储读写文件报错(Python3)

    错误原因:pickle模块存储的是二进制字节码,需要以二进制的方式进行读写 1. 报错一:TypeError: write() argument must be str, not bytes 将决策树 ...

  4. 【Python机器学习实战】决策树和集成学习(二)——决策树的实现

    摘要:上一节对决策树的基本原理进行了梳理,本节主要根据其原理做一个逻辑的实现,然后调用sklearn的包实现决策树分类. 这里主要是对分类树的决策进行实现,算法采用ID3,即以信息增益作为划分标准进行 ...

  5. 【Python机器学习实战】决策树与集成学习(七)——集成学习(5)XGBoost实例及调参

    上一节对XGBoost算法的原理和过程进行了描述,XGBoost在算法优化方面主要在原损失函数中加入了正则项,同时将损失函数的二阶泰勒展开近似展开代替残差(事实上在GBDT中叶子结点的最优值求解也是使 ...

  6. 03机器学习实战之决策树CART算法

    CART生成 CART假设决策树是二叉树,内部结点特征的取值为“是”和“否”,左分支是取值为“是”的分支,右分支是取值为“否”的分支.这样的决策树等价于递归地二分每个特征,将输入空间即特征空间划分为有 ...

  7. 【Python机器学习实战】决策树与集成学习(四)——集成学习(2)GBDT

    本打算将GBDT和XGBoost放在一起,但由于涉及内容较多,且两个都是比较重要的算法,这里主要先看GBDT算法,XGBoost是GBDT算法的优化和变种,等熟悉GBDT后再去理解XGBoost就会容 ...

  8. 【Python机器学习实战】决策树与集成学习(六)——集成学习(4)XGBoost原理篇

    XGBoost是陈天奇等人开发的一个开源项目,前文提到XGBoost是GBDT的一种提升和变异形式,其本质上还是一个GBDT,但力争将GBDT的性能发挥到极致,因此这里的X指代的"Extre ...

  9. 机器学习实战 - python3 学习笔记(一) - k近邻算法

    一. 使用k近邻算法改进约会网站的配对效果 k-近邻算法的一般流程: 收集数据:可以使用爬虫进行数据的收集,也可以使用第三方提供的免费或收费的数据.一般来讲,数据放在txt文本文件中,按照一定的格式进 ...

随机推荐

  1. Java千百问_05面向对象(011)_引用传递和值传递有什么差别

    点击进入_很多其它_Java千百问 1.什么是值传递 值传递,是将内存空间中某个存储单元中存放的值,传送给还有一个存储单元.(java中的存储单元并不是物理内存的地址,但具有相关性) 比如: //定义 ...

  2. 《SQL Server 2000设计与T-SQL编程》

    <SQL Server 2000设计与T-SQL编程> <SQL Server 2000设计与T-SQL编程>笔记1 http://dukedingding.blog.sohu ...

  3. laravel 配置修改及读取

    1)laravel 的所以配置文件都在根目录下的 config 目录里,直接看一个配置文件的名字就知道是做什么的了,这里不说了 2)读取配置的方法 $value = config('app.timez ...

  4. IOS7开发~新UI学起(二)

    本文转载至 http://blog.csdn.net/lizhongfu2013/article/details/9133281 1.UINavigationBar: NSDictionary* at ...

  5. phpcms v9表单实现问答咨询功能

    本文转自别人 phpcms v9的留言板插件可以安装留言板,做问答咨询,那样的话有很多东西需要修改,也有人发现phpcms v9有个表单向导功能,只能留言,不能回复,今天仿站网:新源网络工作室告诉大家 ...

  6. 如何把IOS应用,发给别人测试?

    ios应用,除了用XCODE连接真实设备调试以外,也可以制作ipa安包,发给别人测试.下面是具体步骤: 1. 把要测试的设备标识添加到你苹果开发账号的调试设备里.(可以用xcode或者itools查看 ...

  7. 【BZOJ1441】Min 拓展裴蜀定理

    [BZOJ1441]Min Description 给出n个数(A1...An)现求一组整数序列(X1...Xn)使得S=A1*X1+...An*Xn>0,且S的值最小 Input 第一行给出数 ...

  8. 160615、Spring3 MVC 拦截器拦截不到的问题

    昨天项目组有个成员使用拦截器的时候发现不起作用,后来发现了原因,在这里跟大家分享一下(主要是冲突了).分享的是一位网友写的文章,他总结的很好. com.zk.interceptors.MyInterc ...

  9. Centos7.0配置MySQL主从服务器

    主服务器:192.168.186.131 从服务器:192.168.186.133 主从服务器mysql版本尽量保持一致,安装步骤请阅mysql安装步骤 一.修改主服务器配置文件 #   vi /et ...

  10. php 乘除法原理

    w $wdays = ceil(($wmaxutime-$wminutime)/(24*3600)); $wdays = ceil(($wmaxutime-$wminutime)/243600); 二 ...