文章首发于微信公众号:AlgorithmDeveloper,专注机器学习与Python,编程与算法,还有生活。

1.前言

「决策树」| Part2—Python实现之构建决策树中我们已经可以基于给定数据集训练出决策树模型,只不过是以字典方式表示决策树,决策树直观、易于理解的优点完全体现不出来。因此,这篇文章的目的就是将训练出的决策树模型以树状图形表示。

给定数据集:

字典形式决策树模型:

{'人品': {'好': '见 ', '差': {'富有': {'没钱': '不见', '有钱': {'外貌': {'漂亮': '见 ', '丑': '不见'}}}}}}

2.获取决策树的叶节点数及深度

为了使绘制出的决策树图形不因树的节点、深度的增减而变得畸形,因此利用决策树的叶子节点个数以及树的深度将x轴、y轴平均切分,从而使树状图平均分布在画布上。

#获取决策树叶节点个数

def getNumLeafs(tree):

numLeafs = 0

#获取第一个节点的分类特征

firstFeat = list(tree.keys())[0]

#得到firstFeat特征下的决策树(以字典方式表示)

secondDict = tree[firstFeat]

#遍历firstFeat下的每个节点

for key in secondDict.keys():

#如果节点类型为字典,说明该节点下仍然是一棵树,此时递归调用getNumLeafs

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

numLeafs += getNumLeafs(secondDict[key])

#否则该节点为叶节点

else:

numLeafs += 1

return numLeafs

#获取决策树深度

def getTreeDepth(tree):

maxDepth = 0

#获取第一个节点分类特征

firstFeat = list(tree.keys())[0]

#得到firstFeat特征下的决策树(以字典方式表示)

secondDict = tree[firstFeat]

#遍历firstFeat下的每个节点,返回子树中的最大深度

for key in secondDict.keys():

#如果节点类型为字典,说明该节点下仍然是一棵树,此时递归调用getTreeDepth,获取该子树深度

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

thisDepth = 1 + getTreeDepth(secondDict[key])

else:

thisDepth = 1

if thisDepth > maxDepth:

maxDepth = thisDepth

return maxDepth

3.绘制决策树

3.1绘制节点

#绘制决策树

import matplotlib.pyplot as plt

def createPlot(tree):

#定义一块画布,背景为白色

fig = plt.figure(1, facecolor='white')

#清空画布

fig.clf()

#不显示x、y轴刻度

xyticks = dict(xticks=[],yticks=[])

#frameon:是否绘制坐标轴矩形

createPlot.pTree = plt.subplot(111, frameon=False, **xyticks)

#计算决策树叶子节点个数

plotTree.totalW = float(getNumLeafs(tree))

#计算决策树深度

plotTree.totalD = float(getTreeDepth(tree))

#最近绘制的叶子节点的x坐标

plotTree.xOff = -0.5/plotTree.totalW

#当前绘制的深度:y坐标

plotTree.yOff = 1.0

#(0.5,1.0)为根节点坐标

plotTree(tree,(0.5,1.0),'')

plt.show()

#定义决策节点以及叶子节点属性:boxstyle表示文本框类型,sawtooth:锯齿形;fc表示边框线粗细

decisionNode = dict(boxstyle="sawtooth", fc="0.5")

leafNode = dict(boxstyle="round4", fc="0.5")

#定义箭头属性

arrow_args = dict(arrowstyle="

#nodeText:要显示的文本;centerPt:文本中心点,即箭头所在的点;parentPt:指向文本的点;nodeType:节点属性

#ha='center',va='center':水平、垂直方向中心对齐;bbox:方框属性

#arrowprops:箭头属性

#xycoords,textcoords选择坐标系;axes fraction-->0,0是轴域左下角,1,1是右上角

def plotNode(nodeText, centerPt, parentPt, nodeType):

createPlot.pTree.annotate(nodeText, xy=parentPt, xycoords="axes fraction",

xytext=centerPt, textcoords='axes fraction',

va='center',ha='center',bbox=nodeType, arrowprops=arrow_args)

def plotMidText(centerPt,parentPt,midText):

xMid = (parentPt[0] - centerPt[0])/2.0 + centerPt[0]

yMid = (parentPt[1] - centerPt[1])/2.0 + centerPt[1]

createPlot.pTree.text(xMid, yMid, midtext)

plotNode函数一次绘制的是一个箭头与一个节点,plotMidText函数绘制的是直线中点上的文本。

3.2递归绘制决策树

递归绘制决策树的整体思路如下:

(1)绘制当前节点;

(2)如果当前节点的子节点不是叶子节点,则递归;

(3)如果当前节点的子节点是叶子节点,则绘制。

def plotTree(tree, parentPt, nodeTxt):

#计算叶子节点个数

numLeafs = getNumLeafs(tree)

#获取第一个节点特征

firstFeat = list(tree.keys())[0]

#计算当前节点的x坐标

centerPt = (plotTree.xOff + (1.0 + float(numLeafs))/2.0/plotTree.totalW, plotTree.yOff)

#绘制当前节点

plotMidText(centerPt,parentPt,nodeTxt)

plotNode(firstFeat,centerPt,parentPt,decisionNode)

secondDict = tree[firstFeat]

#计算绘制深度

plotTree.yOff -= 1.0/plotTree.totalD

for key in secondDict.keys():

#如果当前节点的子节点不是叶子节点,则递归

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

plotTree(secondDict[key],centerPt,str(key))

#如果当前节点的子节点是叶子节点,则绘制该叶节点

else:

#plotTree.xOff在绘制叶节点坐标的时候才会发生改变

plotTree.xOff += 1.0/plotTree.totalW

plotNode(secondDict[key], (plotTree.xOff,plotTree.yOff),centerPt,leafNode)

plotMidText((plotTree.xOff,plotTree.yOff),centerPt,str(key))

plotTree.yOff += 1.0/plotTree.totalD

根据决策树的叶子节点数和深度来平均切分画布,并且x、y轴的总长度为1,如下图所示:

原谅我的画图水平

3.2.1在createPlot函数中:

plotTree.totalW :表示叶子节点个数,因此上图中每两个叶子节点之间的距离为:1/plotTree.totalW;

plotTree.totalD :表示决策树深度;

plotTree.xOff:表示最近绘制的叶子节点x坐标,在绘制叶节点时其值才会更新;其初始值为图中虚线圆圈位置,这样在以后确定叶子节点位置时可以直接加整数倍的1/plotTree.totalW;

plotTree.yOff = 1.0 :表示当前绘制的深度,其值初始化为根节点y坐标。

3.2.2在plotTree函数中:

#计算当前节点的x坐标

centerPt = (plotTree.xOff + (1.0 + float(numLeafs))/2.0/plotTree.totalW, plotTree.yOff)

在确定当前节点x坐标时,只需确定当前节点下的叶节点个数,其x坐标即为叶节点所占距离的一半:float(numLeafs)/2.0/plotTree.totalW;

由于plotTree.xOff初始值为-0.5/plotTree.totalW,因此当前节点x坐标还需加上0.5/plotTree.totalW。

4.决策树可视化

#决策树节点文本可以以中文显示

import matplotlib as mpl

mpl.rcParams["font.sans-serif"] = ["Microsoft YaHei"]

mpl.rcParams['axes.unicode_minus'] = False

#创建数据集

def createDataSet():

dataSet = [['有钱','好','漂亮','见 '],

['有钱','差','漂亮','见 '],

['有钱','差','丑','不见'],

['没钱','好','丑','见 '],

['没钱','差','漂亮','不见'],

['没钱','好','漂亮','见 ']]

labels = ['富有','人品','外貌']

return dataSet, labels

dataSet, dataLabels = createDataSet()

#创建决策树

myTree = createDecideTree(dataSet,dataLabels)

print(myTree)

#绘制决策树

createPlot(myTree)

字典形式表示决策树:

{'人品': {'好': '见 ', '差': {'富有': {'没钱': '不见', '有钱': {'外貌': {'漂亮': '见 ', '丑': '不见'}}}}}}

树状图形决策树:

5.使用决策树算法

在已知对方有钱,人品差,长得漂亮后,利用前面训练的决策树做出决策,见或不见?!

#使用决策树进行分类

def classify(tree,feat,featValue):

firstFeat = list(tree.keys())[0]

secondDict = tree[firstFeat]

featIndex = feat.index(firstFeat)

for key in secondDict.keys():

if featValue[featIndex] == key:

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

classLabel = classify(secondDict[key],feat,featValue)

else:

classLabel = secondDict[key]

return classLabel

feat = ['富有','人品','外貌']

featValue = ['有钱','差','漂亮']

print(classify(myTree,feat,featValue))

决策结果:

6.存储决策树模型

构建决策树消耗的时间还是很可观的,尤其在数据量大的时候,因此,当训练完决策树模型后有必要将其保存下来,以便后续使用。使用Python模块的pickle序列化对象可以解决这个问题,序列化对象可以在磁盘上保存对象,在需要时将其读取出来。

#保存决策树模型

import pickle

def saveTree(tree, fileName):

fw = open(fileName,'wb')

pickle.dump(tree, fw)

fw.close()

#加载决策树模型

def loadTree(fileName):

fr = open(fileName,'rb')

return pickle.load(fr)

saveTree((myTree),'myTree.txt')

print(loadTree('myTree.txt'))

{'人品': {'差': {'富有': {'有钱': {'外貌': {'丑': '不见', '漂亮': '见 '}}, '没钱': '不见'}}, '好': '见 '}}

Coding Your Ambition!

python决策树可视化_「决策树」| Part3—Python实现之可视化相关推荐

  1. python数学函数_「分享」关于Python整理的常用数学函数整理

    原标题:「分享」关于Python整理的常用数学函数整理 1.函数说明 abs(number)返回数字的绝对值,如abs(-10)返回10 pow(x,y[,z]) 返回x的y次幂(所得结果对z取模), ...

  2. 决策树 结构_「神经网络」能否代替「决策树算法」?

    「神经网络」能否代替「决策树算法」? 这个问题可以从几个维度来分析.但先要说明决策树就是决策树,随机森林和xgboost的性能提升主要是来自于集成学习.所以,我们扩展一下题目把对比延伸到: 单棵决策树 ...

  3. python 文件路径_「按需学Python」 1. Glob库遍历路径/文件

    小前言: 本人Python小白,因为最近想整理下近10几年的老照片,然后就有了写脚本批处理的想法.初始需求其实很简单,就是筛选自己想要的照片到指定文件夹,然后按照exif信息重命名照片为拍摄时间_拍摄 ...

  4. pep8 python 编码规范_「原创」「python自学笔记」python编码规范

    编码规范是学习一个语言前必须要了解的. Python采用PEP8作为编码规范,PEP是Python Enhancement Proposal(Python 增强建议书)的缩写,8代表的是Python代 ...

  5. python 回车字符_「答案」python每日一题20201107

    用python输出 如下9*9 乘法口诀表. #####方法一#####for i in range(1,10): for j in range(1,i+1): print("%2d*%2d ...

  6. 安卓手机python开发环境_「学习」人工智能开发宝典:第四讲 Python开发环境安装(一)...

    上一讲<Python特色>,其中讲到Python.跨平台性: 由于Python开放源码的特性,Python 已被移植到其它诸多平台(意即它们已经过改动以保证其能正常工作).如果你小心地避开 ...

  7. python 开发工具_「干货」推荐一整套 Python 开发工具

    文 | Brendan Maginnis 译 | EarlGrey 在开始一个新的Python项目时,很容易不做规划直接进入编码环节.花费少量时间,用最好的工具设置项目,将节省大量时间并带来更快乐的编 ...

  8. python axes()_「axes」add_axes()——python绘图 - seo实验室

    axes add_axes新增子区域 add_axes为新增子区域,该区域可以座落在figure内任意位置,且该区域可任意设置大小 可以用来做一些子图,图中图 考虑如下代码: import numpy ...

  9. 基于「ClamAv」通过python进行病毒检测(2)-- pyClamd控制clamd详解

    介绍pyClamd模块一般用法和常用方法等. 我们可以使用python来控制clamd,从而操控ClamAv,需要引入第三方模块:pyClamd. 使用pyClamd控制clamd之前,必须先正确安装 ...

最新文章

  1. libusb中的热插拔使用举例
  2. ISME:水库蓝藻水华发生和消退后浮游生物群落的动态变化
  3. matlab 图像显著性检测ft_图像显著性检测总结
  4. JSON In Code
  5. 和AI机器人Alice的一段聊天记录
  6. 过去10年技术人员有哪些状态改变?
  7. 今日英语:out of the box
  8. 解决vue-cli使用组件报错
  9. c#自定义类型的转换方式operator,以及implicit(隐式)和explicit (显示)声明的区别...
  10. guava 集合上 三
  11. MySQL|Aborted connection 日志分析
  12. everything用于移动硬盘资料管理(一):离线搜索
  13. 解决报错 Initialize failed: invalid dom.
  14. 设计一个算法,借助栈实现单链表链接顺序的逆转
  15. item_get - 获得搜好货商品详情
  16. 手机登陆 html,手机登录(登陆)路由器方法
  17. ElasticSearch数据库(ES数据库)简介
  18. c语言less函数,Less 函数
  19. javaWeb开发的放推特项目之推特发布
  20. IPv4和IPv6介绍及区别

热门文章

  1. Android-电话录音服务
  2. 表的插入、更新、删除、合并操作_18_清空表中记录
  3. html5时间画布走动,javascript+HTML5 canvas绘制时钟功能示例
  4. linux推出mysql对话_以及如何配置它以与Linux平台上的MySQL数据库对话
  5. Qt学习笔记之常用控件QTreeWidget
  6. 目标检测之YOLOv2
  7. conda 安装软件
  8. NVIDIA DIGITS 5.1-dev学习笔记之安装过程记录:Windows10 x64位系统 、 MicroSoft Caffe Master、CUDA 8.0 、Python 2.7
  9. labelme的 json格式转化成自己的json格式
  10. php对象序列化总出错false