决策树算法0基础小白也能懂(附代码)Mephostopheles

决策树(Decisiontree)是基于已知各种情况(特征取值)的基础上,通过构建树型决策结构来进行分析的一种方式,是常用的有监督的分类算法(也就是带有标签的训练数据集训练的,比如后文中使用到的训练集中的好瓜坏瓜就是标签,形容瓜的就是特征)

决策树模型(DecisionTreemodel)模拟人类决策过程。

根节点:决策树的起点,代表数据集的整体。

内部节点:表示对某个特征进行的判断或测试,也可以说是类别二选一。

分支:从一个节点到另一个节点的路径,根据特征的取值进行分割,表示一个测试输出。

叶节点:代表最终的决策或预测结果。

选择特征:决策树通过选取最能分割数据的特征来构建内部节点。通常使用信息增益(InformationGain)或基尼系数(GiniImpurity)等标准来衡量特征的重要性,这些标准后面还会谈到。

分裂:根据选定的特征,将数据集分成若干子集,每个子集对应一个特定的特征取值或范围。

递归分裂:对子集重复上述过程,构建子树,直到满足停止条件(如节点纯度达到阈值、最大深度达到、数据量不足等)。

终止条件:当不能再有效分裂时,节点转化为叶节点,叶节点的输出即为分类标签或回归值。

图里搞的很复杂,重点其实就在递归。

要了解决策树的「最优属性」选择,我们需要先了解一个信息论的概念「信息熵(entropy)」,它是消除不确定性所需信息量的度量,也是未知事件可能含有的信息量。

假设数据集\(D\)中有\(y\)类,其中第\(k\)类样本占比为\(p_k\),则信息熵的计算公式如下:

\(ENT(D)=-\sum_{k=1}^{|y|}p_k\log_2p_k\)

\(p_k\)为1时,信息熵最小为0,很明显为必然事件,\(p_k\)为均匀分布(概率相等)时,信息商取最大值(\(p_k=\frac{1}{y}\))\(\log_2(|y|)\)(概率同等,不确定性最大)

还记得我们之前的决策树家族中的ID3吗?构建时用的就是信息增益信息增益(InformationGain),它衡量的是我们选择某个属性进行划分时信息熵的变化(可以理解为基于这个规则划分,不确定性降低的程度)。典型的决策树算法ID3就是基于信息增益来挑选每一节点分支用于划分的属性(特征)的。

这里面的\(D^v\)可能有点难理解,它是将数据集\(D\)根据属性\(a\)的那些取值划分成了\(v\)个子集\(\{D_1,D_2,...,D_v\}\),那划分后的信息熵又是咋来的,其实是一种条件熵\(H(D|a)\),是数据集\(D\)在基于属性\(a\)进行划分后的不确定性。

下面拿一个西瓜的数据集举个例子,一共17个数据,9个好瓜,8个坏瓜

以色泽属性为条件计算信息熵,一共三类色泽:\(青绿,乌黑,浅白\),看看他们在好坏瓜中的占比进行计算

同样的方法,计算其他属性的信息增益为:

对比不同属性,我们发现「纹理」信息增益最大,它就要作为决策树的根节点,可以看到里面被分为三个属性:\(清晰,模糊,稍糊\),也就是下一层的节点要根据这三个属性来看,计算各属性信息增益

图中只给出了纹理=清晰这一个分支的结果,有三个属性信息增益都一样,那么说明这三个特征都是最能分割数据的特征,均作为决策树的节点。纹理=稍糊以及其他属性的计算过程略去了,最后的结果如下图

大家已经了解了信息增益作为特征选择的方法,但信息增益有一个问题,它偏向取值较多的特征。原因是,当特征的取值较多时,根据此特征划分更容易得到纯度更高的子集,因此划分之后的熵更低,由于划分前的熵是一定的。因此信息增益更大,因此信息增益比较偏向取值较多的特征。

那有没有解决这个小问题的方法呢?有的,这就是我们要提到信息增益率(GainRatio),信息增益率相比信息增益,多了一个衡量本身属性的分散程度的部分作为分母,而著名的决策树算法C4.5就是使用它作为划分属性挑选的原则。

\(Grain\_ratio(D,a)=\frac{Gain(D,a)}{IV(a)}\)\(IV(a)=-\sum_{v=1}^{V}\frac{|D^v|}{|D|}\log_2\frac{|D^v|}{|D|}\)

下面那一块就是熵公式的变式,固有熵通过计算特征自身的“熵”,使得信息增益率能够公平地评价特征的分裂能力,不偏向多值特征。

基尼系数\(Gini(D)=\sum_{k=1}^{|y|}\sum_{k^{'}\not=k}p_kp_{k^{'}}=1-\sum_{k=1}^{|y|}p_k^2\)

为什么它可以作为纯度的量度呢?大家可以想象在一个漆黑的袋里摸球,有不同颜色的球,其中第k类占比记作\(p_k\),那两次摸到的球都是第k类的概率就是\(p_k^2\),那两次摸到的球颜色不一致的概率就是\(1-\sump_k^2\),它的取值越小,两次摸球颜色不一致的概率就越小,纯度就越高。

如果我们让决策树一直生长,最后得到的决策树可能很庞大,而且因为对原始数据学习得过于充分会有过拟合的问题。缓解决策树过拟合可以通过剪枝操作完成。而剪枝方式又可以分为:预剪枝和后剪枝。并使用「留出法」进行评估剪枝前后决策树的优劣。

我们来看一个例子,下面的数据集,为了评价决策树模型的表现,会划分出一部分数据作为验证集

在上述西瓜数据集上生成的一颗完整的决策树,如下图所示。

剪枝基本策略包含「预剪枝」和「后剪枝」两个:

预剪枝(pre-pruning):在决策树生长过程中,对每个结点在划分前进行估计,若当前结点的划分不能带来决策树泛化性能的提升,则停止划分并将当前结点标记为叶结点。

后剪枝(post-pruning):先从训练集生成一颗完整的决策树,然后自底向上地对非叶结点进行考察,若将该结点对应的子树替换为叶结点能带来决策树泛化性能的提升,则将该子树替换为叶结点。

根据我们的验证集,如果只按照好坏瓜来进行分的话验证集精度为3/7x100%=42.9%

但是加入决策树的结点后,验证集精度为5/7x100%=71.4%,比没有划分前大,所以不剪枝,最后分出来如下图

和预剪枝一样是判断精度,只是从下面开始,没剪之前精度42.9,如果把结点⑥的标记为好瓜,精度57.1,可以剪

最终结果为

过/欠拟合风险:预剪枝:过拟合风险降低,欠拟合风险增加。后剪枝:过拟合风险降低,欠拟合风险基本不变。

泛化性能:后剪枝通常优于预剪枝。

我们用于学习的数据包含了连续值特征和离散值特征,之前的例子中使用的都是离散值属性(特征),决策树当然也能处理连续值属性,我们来看看它的处理方式。

对于离散取值的特征,决策树的划分方式是:选取一个最合适的特征属性,然后将集合按照这个特征属性的不同值划分为多个子集合,并且不断的重复这种操作的过程。

对于连续值属性,显然我们不能以这些离散值直接进行分散集合,否则每个连续值将会对应一种分类。那我们如何把连续值属性参与到决策树的建立中呢?

因为连续属性的可取值数目不再有限,因此需要连续属性离散化处理,常用的离散化策略是二分法,这个技术也是C4.5中采用的策略。

原始数据很多时候还会出现缺失值,决策树算法也能有效的处理含有缺失值的数据。缺失值处理的基本思路是:样本赋权,权重划分。

权重划分是指将整体权重分配给不同的部分或类别,确保模型能够有效地学习这些部分。例如,在决策树的构建过程中,使用样本的权重来影响节点的分裂决策。

我们来通过下图这份有缺失值的西瓜数据集,看看具体处理方式。

仅通过无缺失值的样例来判断划分属性的优劣,学习开始时,根结点包含样例集\({D}\)中全部17个样例,权重均为1。

\(\widetilde{D^1},\widetilde{D^2},\widetilde{D^3}\)分别表示在属性「色泽」上取值为「青绿」「乌黑」以及「浅白」的样本子集:

再计算其他属性的增益

因此选择「纹理」作为接下来的划分属性。感觉权重可能就体现在那个\(\widetilde{r_v}\)里,就是排除了缺失值的占比

用的是iris数据集,直接用sklearn库

样本数量:150个。特征数量:4个连续特征。类别数量:3个类别,每个类别包含50个样本。数据平衡:每个类别的样本数量相同,均为50个。

fromsklearn.datasetsimportload_irisfromsklearn.model_selectionimporttrain_test_splitfromsklearn.treeimportDecisionTreeClassifierfromsklearnimportmetricsimportmatplotlib.pyplotaspltfromsklearn.treeimportplot_tree#1.加载数据集iris=load_iris()X=iris.datay=iris.target#2.划分训练集和测试集X_train,X_test,y_train,y_test=train_test_split(X,y,test_size=0.3,random_state=42)#3.训练决策树模型clf=DecisionTreeClassifier()clf.fit(X_train,y_train)#4.进行预测y_pred=clf.predict(X_test)#5.评估模型print("Accuracy:",metrics.accuracy_score(y_test,y_pred))print("ClassificationReport:\n",metrics.classification_report(y_test,y_pred))#6.可视化决策树plt.figure(figsize=(12,8))plot_tree(clf,filled=True,feature_names=iris.feature_names,class_names=iris.target_names)plt.show()

THE END
1.9个常用数据结构与算法的C语言代码实现快速排序是一种常用的排序算法,其基本思想是通过选定一个基准元素,将待排序序列划分为两个子序列,其中一个子序列的所有元素均小于等于基准元素,另一个子序列的所有元素均大于等于基准元素,然后对两个子序列分别进行递归排序,最终将整个序列排序。以下是一个简单的快速排序实现示例代码:#include <stdio.h>void https://baijiahao.baidu.com/s?id=1763048454408546168&wfr=spider&for=pc
2.常用算法代码常用算法代码 这篇文章包含了一系列算法实现,如计算两个数的最大公约数(GCD)和最小公倍数(LCM),筛选法求素数,查找回文数,以及解决字符串子串匹配和连续子数组最大和的问题。还提到了优化输入输出和数据结构在处理大量数据时的重要性。 摘要由CSDN通过智能技术生成https://blog.csdn.net/qq_44380224/article/details/123455379
3.可能是你看过最全的十大排序算法详解(完整版代码)C语言排序算法是程序中常用的算法,下面这篇文章主要给大家介绍了关于十大排序算法的相关资料,文中通过实例代码介绍的非常详细,需要的朋友可以参考下+ 目录 GPT4.0+Midjourney绘画+国内大模型 会员永久免费使用!【 如果你想靠AI翻身,你先需要一个靠谱的工具!】前言https://www.jb51.net/article/251992.htm
4.数据挖掘算法代码数据挖掘算法案例数据挖掘算法代码 数据挖掘算法案例 数据挖掘作为一门新兴的多学科交叉应用技术,正在各行各业的决策支持活动中扮演着越来越重要的角色。数据挖掘概念的定义描述有若干版本,本文采用的是一个普遍接受的定义:数据挖掘,又称为数据库中的知识发现(KDD),它是一个从大量数据中抽取出未知的、有价值的模式或规律等知识的复杂https://blog.51cto.com/u_16213642/7090644
5.ModelArts创建算法ModelArts用户指南训练过程中,自定义算法需要从OBS桶或者数据集中获取数据进行模型训练,训练产生的输出结果也需要存储至OBS桶中。用户的算法代码中需解析输入输出参数实现ModelArts后台与OBS的数据交互,用户可以参考开发自定义脚本完成适配ModelArts训练的代码开发。 创建自定义算法时,用户需要将算法代码中定义的输入输出参数进行配置。 https://ecloud.10086.cn/op-help-center/doc/article/72086
6.腾讯算法岗武功秘籍(上)所以,不要存在侥幸心理,踏踏实实的刷题,复习好常规机器学习算法,尤其是算法的原理和应用场景。 ★ 项目和比赛经历非常的重要,往往面试官都是根据项目里用到的方法拓展提问,对项目的优化和改进也问的比较多。还有就是能内推的一定去找学长学姐或是其它资源去内推。 ★ 面试过程中如果实在写不出来代码的话,就给https://www.flyai.com/article/930
7.算法与数据结构复杂度分析粗略地说,算法的执行效率是算法代码执行的时间。但是,如何在不运行代码的情况下,用“肉眼”获得代码执行时间呢? 这里有一个很简单的代码,请求 1,2,3n 累加和。现在,我将带您一起估计代码的执行时间。 int cal(int n) { int sum = 0; int i = 1; for (; i <= n; ++i) {https://www.tulingxueyuan.cn/tlzx/jsp/5158.html
8.C语言快速排序算法及代码快速排序是对冒泡法排序的一种改进。那么有关C语言快速排序算法和代码分别又是怎样的呢?以下仅供参考! 快速排序算法 的基本思想是:将所要进行排序的数分为左右两个部分,其中一部分的所有数据都比另外一 部分的数据小,然后将所分得的两部分数据进行同样的划分,重复执行以上的划分操作,直 到所有要进行排序的数据变https://www.oh100.com/kaoshi/c/542712.html
9.算法和编程面试题精选TOP50!(附代码+解题思路+答案)这份面试资源主要包含五部分内容:数组、链表、字符串、二叉树和重要算法(如排序算法)的编程面试题,其中每部分内容我们都列出了一些最常被问到的热门问题,并且在每个题目后给出了可以参考的解决思路和代码,因为题目较多,我们没有罗列所有的方法和代码,只给出了访问地址。相信大家在掌握了这些内容后,一定可以提升实力、https://cloud.tencent.com/developer/article/1483807
10.Delphi采用LZ77算法的一段压缩代码window基础Delphi采用LZ77算法的一段压缩代码 核心提示:const MAX_WND_SIZE=1024;procedure Write12BitStream(pbuffer: pchar; bitoffset: ULONG);var bytebound, const MAX_WND_SIZE=1024;procedure Write12BitStream(pbuffer: pchar; bitoffset: ULONG); varhttp://www.2ccc.com/news/Html/?875.html
11.科学网—二维三次卷积插值算法及Fortran代码更新二维三次卷积插值算法及Fortran代码【更新】 |个人分类:数学轮子|系统分类:科研笔记|Fortran程序, 插值算法 最近有人问起二维三次卷积插值算法(Cubic Convolution Interpolation)及其程序的问题,我想到这种插值算法也能用于图像的插值,所以也就有了兴趣,稍微了解了一下,并试着用Fortran实现了一下,同时也顺便复习了一下https://blog.sciencenet.cn/blog-2277-595297.html