机器学习--详解CART树剪枝原理和过程

article/2025/9/24 15:52:16

       这一节主要讲前面多次的提到的决策树问题,前面的决策树生成算法递归的产生决策树,直到不能继续分支或者达到要求为止,这样的决策树往往对训练数据的分类很准确,因为他就是基于训练数据的熵或者基尼不存度进行分类的,因此对训练数据的会产生过拟合现象,而对未知的数据则没有那么准确。过拟合的本质原因是决策树在训练时追求如何提高训练数据的准确度,而没有考虑构件出的决策树的复杂性,直观上我们能想象出当决策树越复杂时,训练数据的分类效果越好,因为复杂意味着分支多,分支多意味着对数据的分类效果越好。决策树复杂是对训练数据过拟合的本质原因,因此为了提高决策树的泛化能力,需要兼顾决策树的复杂度问题,这个问题如何考虑才能得到比较好的决策树呢?

先弄清楚几个概念,这里的概念很重要,请大家一定要注意,因为这也是下面搞晕的原因:

决策树由节点和有向边组成,其中节点有两种类型: 内部节点和叶节点,内部节点表示一个特征或者属性(如A,B,C都为内部节点),叶节点表示一个类(如D1,D2,,都是叶节点)

       目前比较好的解决这个问题的方法就是决策树的剪枝算法,这个算法是怎么工作的呢?或者工作的原理是什么呢?下面我们就一起来看看:

       为了让大家更容易理解,在这里先简单的讲解一下李航的《统计学习方法》中的一个例子,这个例子所给的训练数据是贷款申请的数据,根据特征决策是否批准贷款申请,特征有年龄、是否有工作、是否有房子、信贷情况这4个特征:

这里通过熵计算,详情就不说了,直接给出公式和决策树图:

 

好,我们来详细的看看决策树的决策过程,他是依据信息增益进行决策的,增益越大说明这个特征对最后的分类影响越大,因此从上层到下层信息增益是逐渐下降的,为了追求训练数据的准确率,会不停的进行分支下去,直到信息增益0.此时只有一类了,因此也是最纯净的,所以增益为0 ,但是这也带来了问题就是决策树的分支会很复杂,且对训练数据过拟合,对新数据没有很好的准确度,因此为了提高决策树的泛化能力,就需要决策树不要只追求训练数据的准确度,还要考虑泛化能力,而这个泛化能力的提高是希望决策树对训练数据不要分的那么“仔细”,想要达到这样的效果,一个可行的办法是控制决策树的树枝的复杂性,我们知道决策树的树枝越多说明分的越细,因此可以通过控制树枝的多少来提高决策树的泛化能力,到这里我们找到了,如何解决这个问题的思路了,但是问题是我还要考虑决策的准确率,不能以大幅度降低准度度来提高决策树的的泛化能力,这个是不可取的,因此为了兼顾两者,前辈们提出了剪枝的方法,这个方法是怎么工作呢?其实很简单,首先我还是按照之前的决策生成决策树,此时的决策树对训练数据具有很高的准确度但是泛化能力不好,在此基础上,提出了控制决策树的复杂度,为了兼顾准确度,把二者结合定义一个目标表达式,这个目标表达式是怎么定义呢?这个稍后解释,先引入一个概念,我们知道对分类的数据我们同个信息增益进行决策的,那么这个信息增益充当什么角色呢?如使用决策树进行回归那么我们引入的试试损失函数或者误差函数这个又是充当什么呢?这两个有什么相同之处呢?其实这个两个就是我们决策树的决策依据,在分类中我们以最大的信息增益为决策依据,而在回归中,我们以损失函数作为我们的优化目标,使其达到最小就是我们的最终目的。我们从这里可不可以加入我们的一些限制决策树复杂度的条件呢?其实我们新的目标表达式就是这样来的,我们下面详细看看:

在这里我就不码字了,直接从李航老师的书中解图过来,大家多包涵,我尽量把剪枝的过程说清楚,我看好多博客都说的不清不楚,还有的就是错的,本篇是从问题从发,一步步到表达式,这样才不会觉得很突兀:

 这里需要解释一下此时定义的,此时的定义就把决策依据的损失函数和决策树的复杂的联系起来了,这也是最不好理解的,也是很多博客说不清的地方,在这里只代表本人的理解,有什么问题请留言,我们一起探讨。首先定义时是一个完整的树就是对训练数据准确度很高但是泛化能力不好的原始树,假设这颗树的叶节点个数为|T|,t为树T的某个叶节点(如上图的有自己的房子和有工作都是叶节点),这个叶节点有N_t个样本点,其中K类的样本点个数为N_{tk},就这些样本点中有N_{tk}个样本数据属于K类的,H_t(T)是指在叶节点的熵,我们知道每个叶节点往下分支的依据是信息增益,其来源就是熵的变化,而且分支越细,熵就越小,因为确定性越来越大了。因此损失函数的定义为:

                                                          C_\alpha (T)=\sum_{t=1}^{T}N_tH_t(T)+\alpha |T|

我们来看看这个公式的意义,等式的右边的第一项求和是 对树T的所有的叶节点的样本数据的熵进行求和(我们知道在回归中损失函数是真实值和预测值的差的平方),而在分类中,以熵为分类依据,理论熵分类完全正确,熵应该为0(因为都是同一类,带来为1),但是如果树叶节点的熵不为零说明分类的不完全正确,同时此时的熵就是损失了或者误差了(这里好多人没解释为什么这样,这里我解释,有疑问的请留言),而后面的一项\alpha |T|,是说明这颗树T的叶节点的个数乘以一个系数\alpha,这表明什么呢?简单来说就是衡量了树的复杂度,我们知道一颗树越复杂表明他的树叶越多,因此个数就可以衡量树的复杂度,而\alpha就是用来调整树的复杂度的,稍后会详解\alpha的,好,到这里我们再看看上面的损失函数的合理性,大家应该都可以理解了,如果是回归更容易理解因为是误差函数,这个时候我们求其C_\alpha (T)的最小值,此时一方面是要求正确率尽可能的高,另一方面是希望复杂度尽可能的低,这样目标公式就建立起来了,我们再看看这个目标公式会发现,此时的损失函数是正对全局优化的即整棵树的所有叶节点的损失和,因此求出来的一定是全局最优的,到这里大家应该都可以理解,我们继续深入:

这里的内容就是我们上面说的,只是作者没详细说明为什么这样算,然而这里也是让人困惑的地方,只有这里搞懂,下面才能深入理解他的剪枝过程,我们接着看李航的书:

下面就详细的介绍一下 \alpha是怎样影响复杂度的,首先大家需要明确,我们的损失函数的第一项和第二项是矛盾的:

                                                      C_\alpha (T) = C(T) + \alpha \left | T \right |

因为我们整体是希望求的最小值,而上式的第一项是损失误差,希望尽量的小,而要想使损失尽量的小,那么表现在决策树上就是决策树越来越复杂即树叶节点很多,即|T|很多,但是第二项呢?也是希望尽可能的小,在给定 \alpha时,希望|T|尽可能的小,因此矛盾就出来了,因此需要找到平衡的|T|,而这个平衡值T就和\alpha有关了,大家还记得岭回归的目标式子么?和那里的岭参数一个道理,在这里我们单独的解释一下这个\alpha的作用:

对任意内部节点t,

剪枝前的状态:有\left | T_t \right |个叶子节点,预测误差是C_\left | T_t \right |

剪枝后的状态:只有本身一个叶子节点,预测误差是C(t)

因此剪枝前的以t节点为根节点的子树的损失函数是 :

                                                                  C_\alpha (T_t) = C(T_t) + \alpha \left | T_t \right |

剪枝后的损失函数是:

                                                                   C_{\alpha }(t) = C(t) + \alpha

在这里需要解释一下,剪枝后为什么是这样,剪之后就只有他本身的叶节点了,因此直接计算误差,因为只有一个叶节点,所以\alpha |T|就是\alpha

好,到这里我们需要好好探讨一下了,我们知道,决策树随着树叶的增加是损失值是减小的,那么如果我剪掉这个叶节点,是不是就意味着的损失值在增大呢,是的,但是此时的\left | T_t \right |减小为1了,一个增大,一个减小,最后求和的结果是增大还是减小呢?答案是不一定的,这里理解很关键,我们看看剪枝前的公式,发现误差是最小的,但是决策树此时复杂度是最大的,因此对应一个值,那么剪枝后呢?剪之后就是我们知道损失是增大的,但是复杂度即叶节点从\left | T_t \right |直接变为1了,,因此他们的求和后的结果就有三种情况,要么相等,要么是增大或者减小,这个大家应该可以理解。对于剪枝后的求和如果小于剪枝前的求和,说明复杂度在其中起到关键的作用,而损失函数起的作用很小,简单来说就是剪枝前的叶节点并没有很好的提高准确度但是却带来更复杂的树,因此可以考虑剪去这个叶节点,,这就是剪枝的过程和原理了,这也是李航书中提到的:

 到这里,相信大家还是能理解的,不理解的请留言,我们继续讨论,我们知道,剪枝前和剪枝后的大小还取决于\alpha,因为\alpha不同,得到的结果可能不同,那么\alpha取何止更好呢?这个值怎么取才能是全局最优剪枝呢?我们继续深入探讨:

此时我们令剪枝前和剪枝后的两式相等:

                                                                C_\alpha (T_t) = C_\alpha (t)

即得到:

                                                                C(T_t) + \alpha \left | T_t \right | = C(t) + \alpha

求出\alpha

                                                                 \alpha = \frac{C(t) - C(T_t)}{\left | T_t \right | - 1 }           

也就是说当\alpha等于这个值时剪枝前和剪枝后的损失结果是一样的,这个就是灵界条件了,好,我们知道临界条件了,下面是到底如何取\alpha才能取到全局最优的剪枝后的决策树呢?

这时我们需要再看看这个表达式:

                                                                  C_\alpha (T_t) = C(T_t) + \alpha \left | T_t \right |

我们发现\alpha在中间起着制约的作用,但是它到底代表什么物理意义呢?我们来分析一下,我们知道,我们求C_\alpha (T_t)的最小值,如果\alpha很大时加入为无穷大,则此时要想最小,就需要\left | T_t \right |最小,如果\alpha很小假如为0时,此时\left | T_t \right |可以取到很大,同时也说明了,当\alpha=0时,树很复杂,训练数据准确率很高即过拟合,因此可以看出\alpha是衡量损失函数剪枝后的损失程度的量。

这里\alpha如何选择参数呢?哪个参数对应的损失最小同时复杂度最小呢?我们知道,一旦给定一个\alpha值,则就会对应一个最优的剪枝树,只是哪个是最优的,则需要遍历了,如何遍历呢?

此时大家应该可以看懂了吧,人们是找到所有可能剪枝的剪枝后树,然后通过数据交叉验证,看看哪个的错误率和泛化能力最好就选择哪个。

好,剪枝过程基本讲完了,下面我们以CART数的创建和剪枝为例进行系统的讲解:

CART树的生成是以二叉树为分支的,分为分类和回归,这里就不详细讲了,请看李航的《统计学习方法》第68页,下面直接给出生成算法了:

 生成还是和以前的决策树一样,我们看看剪枝算法:

CART剪枝:

先说明一下,该算法是采用动态规划进行设计的,因此他先计算树T的所有节点的损失值,剪枝是从下到上进行剪枝的:

上面的第6步有错误,应该返回到底三步,要不然最小值永远不变了 ,之所以返回到第三步就是计算全局的\alpha,在此更新。李航网上已经勘误了,大家需要注意

刚开始设置\alpha为无穷大,,然后计算所有内部节点的 \alpha,然后取一个最小的值赋值给\alpha,我们知道,所有的节点的\alpha肯定是不一样的,\alpha最小说明|T|很大,那么就可以剪枝了,此时记录对应的剪枝后的树,存储起来,减掉以后,全局的节点的\alpha都会变化,此时在次计算所有的\alpha,然后继续剪枝,这里需要强调的是这是递归实现动态规划,因此它是在第一个剪枝的基础上进行再次剪枝的,因为重新计算了\alpha,那么那个最小的\alpha一定比之前的要大,直到根节点结束。下面能解释我的理解:

就是说因为是递归,所以只要满足条件才会全部返回,我也不知道这样理解对不对,感觉有问题的请留言我们一起交流,机器学习算法写完后我会开一篇算法专栏,把常用的算法总结一下。 

好,本篇到此结束,有疑问请留言,这是本人的理解难免会有错误,请多包涵,可以一起讨论,微信号:zsffuture


http://chatgpt.dhexx.cn/article/eMUVdfN3.shtml

相关文章

【树模型与集成学习】(task2)代码实现CART树(更新ing)

学习心得 task2学习GYH大佬的回归CART树,并在此基础上改为分类CART树。 更新ing。。 这里做一些对决策树分裂依据更深入的思考引导:我们在task1证明离散变量信息增益非负时曾提到,信息增益本质上就是联合分布和边缘分布乘积的kl散度&#xf…

CART 决策树

ID3使用信息增益,而C4.5使用增益比率进行拆分。 在此,CART是另一种决策树构建算法。 它可以处理分类和回归任务。 该算法使用名为gini索引的新度量标准来创建分类任务的决策点。 CART树的核心是决策规则将通过GINI索引值决定。 停止条件。 如果我们继续…

CART决策树算法

在进行自动识别窃漏电用户分析实战时,用到了CART决策树算法,所以整理记录该算法的内容。内容整理参考文档决策树——CART算法及其后的参考文章。 一、CART(classification and regression tree)分类与回归树,既可用于…

CART树算法解析加举例

算法步骤 CART假设决策树是二叉树,内部结点特征的取值为“是”和“否”,左分支是取值为“是”的分支,右分支是取值为“否”的分支。这样的决策树等价于递归地二分每个特征,将输入空间即特征空间划分为有限个单元,并在…

ID3、C4.5与CART树的联系与区别

ID3、C4.5与CART树的联系与区别: 参考博客: 链接1 链接2 特征选择准则: ID3的特征选择准则为信息增益,即集合D的经验熵H(D)与给定特征A下条件经验熵H(D|A)之差,即: H(D)表现了数据集D进行分类的不确定性…

决策树构建算法—ID3、C4.5、CART树

决策树构建算法—ID3、C4.5、CART树 决策树构建算法—ID3、C4.5、CART树 构建决策树的主要算法ID3C4.5CART三种算法总结对比 决策树构建算法—ID3、C4.5、CART树 构建决策树的主要算法 ID3C4.5CART (Classification And Rsgression Tree) ID3 ID3算法…

3-6 决策树、CART树、GBDT、xgboost、lightgbm一些关键点梳理

目录 1、决策树 2、CART树 2.1 CART分类树-输入样本特征;输出样本对应的类别(离散型) 2.2 CART回归树-输入样本特征;输出样本的回归值(连续型) 3、GBDT 3.1 提升树 3.2 GBDT 4、xgboost 4.1 损失函数及节点展开 4.2 精确贪心算法及相关近似算法…

CART树回归

说明:本博客是学习《python机器学习算法》赵志勇著的学习笔记,其图片截取也来源本书。 基于树的回归算法是一类基于局部的回归算法,通过将数据集切分成多份,在每一份数据中单独建模。与局部加权线性回归不同的是,基于…

剪枝、cart树

一、剪枝 1. 为什么要剪枝 在决策树生成的时候,更多考虑的是训练数据,而不是未知数据,这会导致过拟合,使树过于复杂,对于未知的样本不准确。 2. 剪枝的依据——通过极小化决策树的损失函数 损失函数的定义为&#x…

【机器学习】决策树——CART分类回归树(理论+图解+公式)

🌠 『精品学习专栏导航帖』 🐳最适合入门的100个深度学习实战项目🐳🐙【PyTorch深度学习项目实战100例目录】项目详解 数据集 完整源码🐙🐶【机器学习入门项目10例目录】项目详解 数据集 完整源码&…

CART树(分类回归树)

主要内容 (1)CART树简介 (2)CART树节点分裂规则 (3)剪枝 --------------------------------------------------------------------------------------------------------------------- 一、简介 CART…

CART树

算法概述 CART(Classification And Regression Tree)算法是一种决策树分类方法。 它采用一种二分递归分割的技术,分割方法采用基于最小距离的基尼指数估计函数,将当前的样本集分为两个子样本集,使得生成的的每个非叶子节点都有两个分支。因此…

Pytorch之view,reshape,resize函数

对于深度学习中的一下数据,我们通常是要变成tensor格式,并且需要对其调整形状,很多时候我们往往只关注view之后的结果(比如输出的尺寸),而不关心过程。但有时候还是要关注一下这个到底是怎么变换过来的&…

OpenCV-Python图像处理:插值方法及使用resize函数进行图像缩放

☞ ░ 前往老猿Python博客 https://blog.csdn.net/LaoYuanPython ░ 图像缩放用于对图像进行缩小或扩大,当图像缩小时需要对输入图像重采样去掉部分像素,当图像扩大时需要在输入图像中根据算法生成部分像素,二者都会利用插值算法来实现。 一…

vector的resize函数和reserve函数

博客原文:C基础篇 -- vector的resize函数和reserve函数_VampirEM_Chosen_One的博客-CSDN博客,写的特别好,谢谢原博主。 正文: 对于C的vector容器模板类,存在size和capacity这样两个概念,可以分别通过vect…

OpenCV 图片尺寸缩放——resize函数

文章目录 OpenCV中的缩放:resize函数代码案例 OpenCV中的缩放: 如果要放大或缩小图片的尺寸,可以使用OpenCV提供的两种方法: resize函数,是最直接的方式;pyrUp,pyrDown函数,即图像…

OpenCV的resize函数优化

背景 在使用OpenCV做图像处理的时候,最常见的问题是c版本性能不足,以resize函数为例来说明,将size为[864,1323,3]的函数缩小一半: Mat img0;gettimeofday(&t4, NULL);cv::resize(source, img0, cv::Size(cols_out,rows_out)…

C++ | resize函数的用法

最近在leetcode用C刷题,刚遇到一题需要给重新弄一个容器,并给容器初始化。新建容器要在private类中声明resize函数用来初始化preSum容器。 resize函数是C中序列式容器的一个共性函数,vv.resize(int n,element)表示调整容器vv的大小为n&#x…

opencv的resize函数

一、Opencv官方文档中resize的描述: resize Resizes an image. C: void resize(InputArray src, OutputArray dst, Size dsize, double fx0, double fy0, int interpolationINTER_LINEAR ) Python: cv2.resize(src, dsize[, dst[, fx[, fy[, interpolation]]]]) …

resize()函数

resize(),设置大小(size); reserve(),设置容量(capacity); size()是分配容器的内存大小,而capacity()只是设置容器容量大小,但并没有真正分配内存。 打个比方:正在建造…