决策树(Decision Tree) | 绘制决策树

2024-02-10 15:08
文章标签 绘制 决策树 tree decision

本文主要是介绍决策树(Decision Tree) | 绘制决策树,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

01 起

在这篇文章中,我们讲解了如何训练决策树,然后我们得到了一个字典嵌套格式的决策树结果,这个结果不太直观,不能一眼看着这颗“树”的形状、分支、属性值等,怎么办呢?

本文就上文得到的决策树,给出决策树绘制函数,让我们对我们训练出的决策树一目了然。

在绘制决策树之后,我们会给出决策树的使用方法:如何利用训练好的决策树,预测训练数据的类别?

提示:不论是绘制还是使用决策树,中心思想都是递归


02 决策树宽度和深度

在绘制决策树之前,我们需要知道利用python绘图的部分知识,比如如何在图中添加注解?

添加注解 annotate()

import matplotlib.pyplot as plt
%matplotlib inline 
%config InlineBackend.figure_format="retina" 
#设置出图显示中文
plt.rcParams['font.sans-serif']=['SimHei']
plt.rcParams['axes.unicode_minus'] = FalsedecisionNode = dict(boxstyle="sawtooth", fc="0.8")
#decisionNode={boxstyle:"sawtooth",fc:"0.8"} #决策节点样式
leafNode=dict(boxstyle="round4",fc="0.8") #叶节点样式#设置标注箭头格式,->表示由注解指向外,<-表示指向注解,<->表示双向箭头
arrow_args=dict(arrowstyle="->") 
#arrow_args=dict(facecolor="blue",shrink=0.05) #另一种设置箭头格式的方式def plotNode(nodeText,centerPt,parentPt,nodeType):# nodeTxt为要显示的文本,centerPt为文本的中心点,parentPt为指向文本的点 createPlot.ax1.annotate(nodeText,xytext=centerPt,textcoords="axes fraction",\xy=parentPt,xycoords="axes fraction",\va="bottom",ha="center",bbox=nodeType,arrowprops=arrow_args)def createPlot():fig=plt.figure(figsize=(6,6),facecolor="white")fig.clf() #清空画布# createPlot.ax1为全局变量,绘制图像的句柄,subplot为定义了一个绘图#111表示figure中的图有1行1列,即1个,最后的1代表第一个图 # frameon表示是否绘制坐标轴矩形 createPlot.ax1=plt.subplot(111,frameon=False)plotNode("决策节点",(0.8,0.4),(1.1,0.8),decisionNode)plotNode("叶节点",(0.5,0.2),(0.2,0.5),leafNode)plt.show()

运行createPlot()之后,得到这张图,注解就添加好了,之后我们会利用这个方法添加决策树的注解:

我们还需要知道如何计算一棵决策树的宽度和深度?

计算决策树宽度和深度
宽度:决策树的叶节点个数
深度:决策树最长分支的节点数

"""
输入:字典嵌套格式的决策树
输出:该决策树的叶节点数,相当于决策树宽度(W)
"""
def countLeaf(desicionTree):cntLeaf=0firstFeatrue=list(desicionTree.keys())[0] #决策树字典的第一个key是第一个最优特征,为什么要提取这个特征呢,因为后面要遍历该特征的属性值从而找个子树subTree=desicionTree[firstFeatrue] #取节点key的value,即子树for key in list(subTree.keys()): #遍历最优特征的各属性值,每个属性对应一个子树,判断子树是否为叶节点if type(subTree[key]).__name__=="dict": #如果当前属性值对应的子树类型为字典,说明这个节点不是叶节点,#那么就递归调用自己,层层下探找到该通路叶节点,然后向上求和得到该通路叶节点数cntLeaf += countLeaf(subTree[key]) #递归else:cntLeaf += 1return cntLeaf"""
输入:字典嵌套格式的决策树
输出:该决策树的深度(D)
"""
def countDepth(desicionTree):maxDepth=0firstFeatrue=list(desicionTree.keys())[0] #当前树的最优特征subTree=desicionTree[firstFeatrue]for key in list(subTree.keys()): #遍历最优特征的各属性值,每个属性对应一个子树,判断子树是否为叶节点if type(subTree[key]).__name__=="dict": thisDepth = 1+countDepth(subTree[key]) #这里值得认真思考过程,作图辅助思考else:thisDepth=1if thisDepth>maxDepth:maxDepth=thisDepth

我们拿上文训练好的决策树来测试一下,决策树长这样:

测试:

我们训练好的决策树宽度为8,深度为4

好了,下面我们可以进入绘制主函数了!


03 绘制决策树

目前我们已经得到了决策树的宽度和深度,还知道了如何在图中添加注解,下面我们开始绘制决策树,中心思想还是递归。

#自定义函数,在父子节点之间添加文本信息,在决策树中,相当于标注父结点特征的属性值
#cntPt是子节点坐标,parentPt是父节点坐标
def plotMidText(cntrPt,parentPt,nodeText):xMid=(parentPt[0]-cntrPt[0])/2+cntrPt[0]yMid=(parentPt[1]-cntrPt[1])/2+cntrPt[1]createPlot.ax1.text(xMid,yMid,nodeText)#自定义函数,是绘制决策树的主力军
def plotTree(decisionTree,parentPt,nodeText):cntLeafs=countLeaf(decisionTree)depth=countDepth(decisionTree)feature=list(decisionTree.keys())[0] #提取当前树的第一个特征subDict=decisionTree[feature] #提取该特征的子集,该子集可能是一个新的字典,那么就继续递归调用子集绘制图,否则该特征对应的子集为叶节点#绘制特征以及该特征属性cntrPt=(plotTree.xOff+(1.0+float(cntLeafs))/2.0/plotTree.totalW,plotTree.yOff) #根据整棵树的宽度深度计算当前子节点的绘制坐标plotMidText(cntrPt,parentPt,nodeText) #绘制属性plotNode(feature,cntrPt,parentPt,decisionNode) #绘制特征#第一个特征绘制好之后,第二个特征的y坐标向下递减(因为自顶向下绘制,yOff初始值为1.0,然后y递减)plotTree.yOff=plotTree.yOff-1.0/plotTree.totalD#遍历当前树的第一个特征的各属性值,判断各属性值对应的子数据集是否为叶节点,是则绘制叶节点,否则递归调用plotTree(),直到找到叶节点for key in subDict.keys(): if type(subDict[key]).__name__=="dict":plotTree(subDict[key],cntrPt,str(key))else:plotTree.xOff=plotTree.xOff+1.0/plotTree.totalW #从左至右绘制,x初始值较小,然后x递增plotNode(subDict[key],(plotTree.xOff,plotTree.yOff),cntrPt,leafNode)plotMidText((plotTree.xOff,plotTree.yOff),cntrPt,str(key))#在上述递归调用plotTree()的过程中,yOff会不断被减小#当我们遍历完该特征的某属性值(即找到该属性分支的叶节点),开始对该特征下一属性值判断时,若无下面语句,则该属性对应的节点会从上一属性最小的yOff开始合理#下面这行代码,作用是:在找到叶节点结束递归时,对yOff加值,保证下一次判断时的y起点与本次初始y一致#若不理解,可以尝试注释掉下面这行语句,看看效果plotTree.yOff=plotTree.yOff+1.0/plotTree.totalD #绘图主函数
def createPlot(decisionTree):fig=plt.figure(figsize=(10,10),facecolor="white")fig.clf() #清空画布axprops=dict(xticks=[],yticks=[]) #设置xy坐标轴的刻度,在[]中填充坐标轴刻度值,[]表示无刻度# createPlot.ax1为全局变量,绘制图像的句柄,subplot为定义了一个绘图#111表示figure中的图有1行1列,即1个,最后的1代表第一个图 # frameon表示是否绘制坐标轴矩形 createPlot.ax1=plt.subplot(111,frameon=False,**axprops)plotTree.totalW=float(countLeaf(decisionTree)) #全局变量,整棵决策树的宽度plotTree.totalD=float(countDepth(decisionTree))#全局变量,整棵决策树的深度plotTree.xOff=-0.5/plotTree.totalWplotTree.yOff=1.0plotTree(decisionTree,(0.5,1.0),'')plt.show()

下面我们用训练好的决策树测试一下绘制函数,激动人心的时刻到了

createPlot(my_tree)

这就是我们训练的决策树,每个节点代表一个特征,节点连接的箭头属性代表该特征的属性值,比如特征(纹理)=属性值(清晰)


04 使用决策树执行分类

目前,我们能够训练决策树,能够绘制决策树了,但是决策树主要的作用还没有发挥出来。

分类决策树,作用在于利用训练好的决策树,对测试集数据进行分类。

下面我们就展示如何利用我们训练好的决策树对测试集进行分类。

中心思想:比较某条测试数据与决策树的数值,递归执行,直到找到某条测试数据的叶节点,然后该测试数据被分类为该叶节点分类

"""
输入:训练好的分类决策树、该决策树的特征列表、某条测试数据各特征属性值(顺序与决策树特征列表一致)
输出:该条测试数据的分类
思路:
比较某条测试数据与决策树的数值,递归执行,
直到找到某条测试数据的叶节点,然后该测试数据被分类为该叶节点分类
"""
def classifyDT(decisionTree,treeFeatures,testVec):firstFeature=list(decisionTree.keys())[0]subDict=decisionTree[firstFeature]#寻找当前树最优特征在特征列表中的位置,便于定位测试数据集对于的特征位置featureIndex=treeFeatures.index(firstFeature) """判断逻辑遍历当前树最优特征各属性值若测试数据对应位置的特征值与key一致,就在这个分支上找下去若此特征属性值对应的分支不是叶节点,就递归调用自己,继续在此分支上下探寻找叶节点若此特征属性值对应的分支是叶节点,就把该测试数据分类到该叶节点类别"""for key in list(subDict.keys()): #遍历当前树最优特征各属性值if testVec[featureIndex]==key: #若测试数据对应位置的特征值与key一致,就在这个分支上找下去if type(subDict[key]).__name__=="dict": #若此特征属性值对应的分支不是叶节点,就递归调用自己,继续在此分支上下探寻找叶节点classLabel=classifyDT(subDict[key],treeFeatures,testVec)else:classLabel=subDict[key] #若此特征属性值对应的分支是叶节点,就把该测试数据分类到该叶节点类别return classLabel

我们来测试一下,classifyDT(),第一个参数代表训练好的决策树,第二个参数代表决策树对应的特征列表,第三个参数就是训练集数据的特征属性了,这些属性要对应第二个参数的特征顺序。

classifyDT(my_tree,\['色泽', '根蒂', '敲声', '纹理', '脐部', '触感'],\['青绿', '蜷缩', '浊响', '清晰', '凹陷', '软粘'])

预测结果:

我们训练的决策树告诉我们,这颗待预测的西瓜,是一颗好瓜!

nice!


05 总结

本文给出了决策树绘制方法和决策树使用方法,中心思想都是递归。

本文训练决策树使用的算法是ID3,信息增益,这种算法只能处理离散型数据,且只能用于分类。如果之后有精力,我们会给出另一种决策树训练算法—CART算法,这种方法可以处理连续型数据,且还可以用于回归。

敬请期待~~


06 参考

  1. 《统计学习方法》 李航 Chapter5
  2. 《机器学习实战》 Peter Harrington Chapter3

这篇关于决策树(Decision Tree) | 绘制决策树的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!


原文地址:
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.chinasem.cn/article/697424

相关文章

使用Python绘制蛇年春节祝福艺术图

《使用Python绘制蛇年春节祝福艺术图》:本文主要介绍如何使用Python的Matplotlib库绘制一幅富有创意的“蛇年有福”艺术图,这幅图结合了数字,蛇形,花朵等装饰,需要的可以参考下... 目录1. 绘图的基本概念2. 准备工作3. 实现代码解析3.1 设置绘图画布3.2 绘制数字“2025”3.3

使用Python绘制可爱的招财猫

《使用Python绘制可爱的招财猫》招财猫,也被称为“幸运猫”,是一种象征财富和好运的吉祥物,经常出现在亚洲文化的商店、餐厅和家庭中,今天,我将带你用Python和matplotlib库从零开始绘制一... 目录1. 为什么选择用 python 绘制?2. 绘图的基本概念3. 实现代码解析3.1 设置绘图画

Python绘制土地利用和土地覆盖类型图示例详解

《Python绘制土地利用和土地覆盖类型图示例详解》本文介绍了如何使用Python绘制土地利用和土地覆盖类型图,并提供了详细的代码示例,通过安装所需的库,准备地理数据,使用geopandas和matp... 目录一、所需库的安装二、数据准备三、绘制土地利用和土地覆盖类型图四、代码解释五、其他可视化形式1.

如何用Python绘制简易动态圣诞树

《如何用Python绘制简易动态圣诞树》这篇文章主要给大家介绍了关于如何用Python绘制简易动态圣诞树,文中讲解了如何通过编写代码来实现特定的效果,包括代码的编写技巧和效果的展示,需要的朋友可以参考... 目录代码:效果:总结 代码:import randomimport timefrom math

【WebGPU Unleashed】1.1 绘制三角形

一部2024新的WebGPU教程,作者Shi Yan。内容很好,翻译过来与大家共享,内容上会有改动,加上自己的理解。更多精彩内容尽在 dt.sim3d.cn ,关注公众号【sky的数孪技术】,技术交流、源码下载请添加微信号:digital_twin123 在 3D 渲染领域,三角形是最基本的绘制元素。在这里,我们将学习如何绘制单个三角形。接下来我们将制作一个简单的着色器来定义三角形内的像素

Flutter 进阶:绘制加载动画

绘制加载动画:由小圆组成的大圆 1. 定义 LoadingScreen 类2. 实现 _LoadingScreenState 类3. 定义 LoadingPainter 类4. 总结 实现加载动画 我们需要定义两个类:LoadingScreen 和 LoadingPainter。LoadingScreen 负责控制动画的状态,而 LoadingPainter 则负责绘制动画。

利用matlab bar函数绘制较为复杂的柱状图,并在图中进行适当标注

示例代码和结果如下:小疑问:如何自动选择合适的坐标位置对柱状图的数值大小进行标注?😂 clear; close all;x = 1:3;aa=[28.6321521955954 26.2453660695847 21.69102348512086.93747104431360 6.25442246899816 3.342835958564245.51365061796319 4.87

树(Tree)——《啊哈!算法》

树 什么是树?树是一种特殊的图,不包含回路的连通无向树。 正因为树有着“不包含回路”这个特点,所以树就被赋予了很多特性。 一棵树中的任意两个结点有且仅有唯一的一条路径连通。一棵树如果有n个结点,那么它一定恰好有n-1条边。在一棵树中加一条边将会构成一个回路。 一棵树有且只有一个根结点。 没有父结点的结点称为根结点(祖先)。没有子结点的结点称为叶结点。如果一个结点既不是根结点也不是叶

YOLOv8/v10+DeepSORT多目标车辆跟踪(车辆检测/跟踪/车辆计数/测速/禁停区域/绘制进出线/绘制禁停区域/车道车辆统计)

01:YOLOv8 + DeepSort 车辆跟踪 该项目利用YOLOv8作为目标检测模型,DeepSort用于多目标跟踪。YOLOv8负责从视频帧中检测出车辆的位置,而DeepSort则负责关联这些检测结果,从而实现车辆的持续跟踪。这种组合使得系统能够在视频流中准确地识别并跟随特定车辆。 02:YOLOv8 + DeepSort 车辆跟踪 + 任意绘制进出线 在此基础上增加了用户

226 Invert Binary Tree

//226 Invert Binary Tree//算法思路:主要使用递归算法public class Solution {public TreeNode invertTree(TreeNode root) {//1 出口 空节点if (root==null)return null;//2 递归 调用自己TreeNode left = root.left;TreeNode right = ro