XGBoost-原理推导(上)

XGBoost简介

XGBoost(eXtreme Gradient Boosting)是华盛顿大学博士陈天奇创造的一个梯度提升(Gradient Boosting)的开源框架。至今可以算是各种数据比赛中的大杀器,被大家广泛地运用。

之前的文章我已经介绍了GBDT,如果对GBDT原理不太懂的,强烈建议先把GBDT的原理搞清楚再回过头来看XGBoost,接下来我会分上中下三篇文章详细介绍XGBoost,包括目标函数,学习策略,重要超参数,系统设计,优缺点等。

目标函数

我们知道 XGBoost 是由 K 个基模型组成的一个加法运算式:
在这里插入图片描述
其中fkf_kfk表示第kkk个模型,y^i\widehat{y}_iyi为第iii个样本的预测值。

损失函数可由预测值 y^i\widehat{y}_iyi 与真实值 yiy_iyi 进行表示:
在这里插入图片描述
我们知道模型的预测精度由模型的偏差和方差共同决定,损失函数代表了模型的偏差,想要方差小则需要简单的模型,所以目标函数由模型的损失函数 LLL 与抑制模型复杂度的正则项 Ω\OmegaΩ 组成,所以我们有:
在这里插入图片描述
Ω\OmegaΩ 为模型的正则项,由于 XGBoost 支持决策树也支持线性模型,所以这里再不展开描述。

我们知道 boosting 模型是前向加法,以第 ttt 步的模型为例,模型对第 iii 个样本 xix_ixi 的预测为:
在这里插入图片描述
其中 y^it−1\widehat{y}^{t-1}_iyit1 由第 t−1t-1t1 步的模型给出的预测值,是已知常数,ft(xi)f_t(x_i)ft(xi) 是我们这次需要加入的新模型的预测值,此时,目标函数就可以写成:
在这里插入图片描述
求此时最优化目标函数,就相当于求解 ft(xi)f_t(x_i)ft(xi)

根据泰勒公式我们把函数 f(x+Δx)f(x+\Delta x)f(x+Δx) 在点 xxx 处进行泰勒的二阶展开,可得到如下等式:
在这里插入图片描述
我们把 y^it−1\widehat{y}^{t-1}_iyit1 视为 xxxft(xi)f_t(x_i)ft(xi) 视为 Δx\Delta xΔx ,故可以将目标函数写为:
在这里插入图片描述
其中 gig_igi 为损失函数的一阶导, hih_ihi 为损失函数的二阶导,注意这里的导是对 y^it−1\widehat{y}^{t-1}_iyit1 求导。

在这里插入图片描述
我们以平方损失函数为例:
在这里插入图片描述
则:
在这里插入图片描述
由于在第 ttt 步时 y^it−1\widehat{y}^{t-1}_iyit1 其实是一个已知的值,所以 l(yi,y^it−1)l(y_i,\widehat{y}^{t-1}_i)l(yi,yit1) 是一个常数,其对函数的优化不会产生影响,因此目标函数可以写成:
在这里插入图片描述
所以我们只需要求出每一步损失函数的一阶导和二阶导的值(由于前一步的 y^t−1\widehat{y}^{t-1}yt1 是已知的,所以这两个值就是常数),然后最优化目标函数,就可以得到每一步的 f(x)f(x)f(x) ,最后根据加法模型得到一个整体模型。

注意:其实推导到这里我们还可以将上式子进一步简化,式子中的第二项是每个基学习器求和的结果,前面的 t−1t-1t1 个学习器是已知的,所以正则化的前 t−1t-1t1 项也是已知的,可以看作一个常数。

在这里插入图片描述

基于决策树的目标函数

我们知道 Xgboost 的基模型不仅支持决策树,还支持线性模型,这里我们主要介绍基于决策树的目标函数。
在这里插入图片描述xxx 为某一样本,这里的 q(x)q(x)q(x) 代表了该样本在哪个叶子结点上,而 wqw_qwq 则代表了叶子结点取值 www ,所以 wq(x)w_{q(x)}wq(x) 就代表了每个样本的取值 www(即预测值)。

决策树的复杂度可由叶子数 TTT 组成,叶子节点越少模型越简单,此外叶子节点也不应该含有过高的权重 www (类比 LR 的每个变量的权重),所以目标函数的正则项可以定义为:
在这里插入图片描述
即决策树模型的复杂度由生成的所有决策树的叶子节点数量,和所有节点权重所组成的向量的 L2L2L2 范式共同决定。
在这里插入图片描述
这张图给出了基于决策树的 XGBoost 的正则项的求解方式。
我们设 Ij={i∣q(xi)=j}I_j = \{i\mid q(x_i) = j\}Ij={iq(xi)=j} 为第 jjj 个叶子节点的样本集合,故我们的目标函数可以写成:
在这里插入图片描述
第二步到第三步可能看的不是特别明白,这边做些解释:第二步是遍历所有的样本后求每个样本的损失函数,但样本最终会落在叶子节点上,所以我们也可以遍历叶子节点,然后获取叶子节点上的样本集合,最后在求损失函数。即我们之前样本的集合,现在都改写成叶子结点的集合,由于一个叶子结点有多个样本存在,因此才有了 ∑i∈Ijgi\sum_{i\in I_j}g_iiIjgi∑i∈Ijhi\sum_{i\in I_j}h_iiIjhi 这两项,wjw_jwj 为第 jjj 个叶子节点取值。

为简化表达式,我们定义 Gj=∑i∈IjgiG_j = \sum_{i\in I_j}g_iGj=iIjgiHj=∑i∈IjhiH_j = \sum_{i\in I_j}h_iHj=iIjhi ,则目标函数为:
在这里插入图片描述
这里我们要注意 GjG_jGjHjH_jHj 是前 t−1t-1t1 步得到的结果,其值已知可视为常数,只有最后一棵树的叶子节点 wjw_jwj 不确定,那么将目标函数对 wjw_jwj 求一阶导,并令其等于 000 ,则可以求得叶子结点 jjj 对应的权值:
在这里插入图片描述
所以目标函数可以化简为:
在这里插入图片描述
在这里插入图片描述
上图给出目标函数计算的例子,求每个节点每个样本的一阶导数 gig_igi 和二阶导数 hih_ihi ,然后针对每个节点对所含样本求和得到的 GiG_iGiHiH_iHi ,最后遍历决策树的节点即可得到目标函数。

到了这里,大家可能已经注意到了,比起最初的损失函数 + 复杂度的样子,我们的目标函数已经发生了巨大变化。我们的样本量已经被归结到了每个叶子当中去,我们的目标函数是基于每个叶子节点,也就是树的结构来计算。所以,我们的目标函数又叫做“结构分数”(structure score),分数越低,树整体的结构越好。如此,我们就建立了树的结构(叶子)和模型效果的直接联系。

最优切分点划分算法

在决策树的生长过程中,一个非常关键的问题是如何找到叶子的节点的最优切分点,Xgboost 支持两种分裂节点的方法——贪心算法和近似算法。

1.贪心算法

贪心算法指的是控制局部最优来达到全局最优的算法,决策树算法本身就是一种使用贪婪算法的方法。XGB作为树的集成模型,自然也想到采用这样的方法来进行计算,所以我们认为,如果每片叶子都是最优,则整体生成的树结构就是最优,如此就可以避免去枚举所有可能的树结构
在这里插入图片描述
回忆一下决策树中我们是如何进行计算:我们使用基尼系数或信息熵来衡量分枝之后叶子节点的不纯度,分枝前的信息熵与分治后的信息熵之差叫做信息增益,信息增益最大的特征上的分枝就被我们选中,当信息增益低于某个阈值时,就让树停止生长。在XGB中,我们使用的方式是类似的:我们首先使用目标函数来衡量树的结构的优劣,然后让树从深度0开始生长,每进行一次分枝,我们就计算目标函数减少了多少,当目标函数的降低低于我们设定的某个阈值时,就让树停止生长。

具体步骤:

  1. 从深度为 [公式] 的树开始,对每个叶节点枚举所有的可用特征;
  2. 针对每个特征,把属于该节点的训练样本根据该特征值进行升序排列,通过线性扫描的方式来决定该特征的最佳分裂点,并记录该特征的分裂收益;
  3. 选择收益最大的特征作为分裂特征,用该特征的最佳分裂点作为分裂位置,在该节点上分裂出左右两个新的叶节点,并为每个新节点关联对应的样本集
  4. 回到第 1 步,递归执行到满足特定条件为止

那么如何计算每个特征的分裂收益呢?

假设我们在某一节点完成特征分裂,则分列前的目标函数可以写为:
在这里插入图片描述
分裂后的目标函数为:
在这里插入图片描述
则对于目标函数来说,分裂后的收益为:
在这里插入图片描述

注意该特征收益也可作为特征重要性输出的重要依据。对于每次分裂,我们都需要枚举所有特征可能的分割方案,如何高效地枚举所有的分割呢?

我假设我们要枚举所有 x<ax<ax<a 这样的条件,对于某个特定的分割点 aaa 我们要计算 aaa 左边和右边的导数和。
在这里插入图片描述
我们可以发现对于所有的分裂点 aaa ,我们只要做一遍从左到右的扫描就可以枚举出所有分割的梯度和 GLG_LGLGRG_RGR 。然后用上面的公式计算每个分割方案的分数就可以了。

CART树全部是二叉树,因此这个式子是可以推广的。从这个式子我们可以总结出,其实分枝后的结构分数之差为:
在这里插入图片描述
其中 GLG_LGLHLH_LHL 从左节点上计算得出, GRG_RGRHRH_RHR 从右节点上计算得出,而 (GL+GR)(G_L + G_R)(GL+GR)(HL+HR)(H_L + H_R)(HL+HR) 从中间节点上计算得出。对于任意分枝,我们都可以这样来进行计算。

在现实中,我们会对所有特征的所有分枝点进行如上计算,然后选出让目标函数下降最快的节点来进行分枝。对每一棵树的每一层,我们都进行这样的计算,比起原始的梯度下降,实践证明这样的求解最佳树结构的方法运算更快,并且在大型数据下也能够表现不错。至此,我们作为XGBoost的使用者,已经将需要理解的XGB的原理理解完毕了。

2.近似算法

贪婪算法可以的到最优解,但当数据量太大时则无法读入内存进行计算,近似算法主要针对贪婪算法这一缺点给出了近似最优解。

对于每个特征,只考察分位点可以减少计算复杂度。

该算法会首先根据特征分布的分位数提出候选划分点,然后将连续型特征映射到由这些候选点划分的桶中,然后聚合统计信息找到所有区间的最佳分裂点。

在提出候选切分点时有两种策略:

Global:学习每棵树前就提出候选切分点,并在每次分裂时都采用这种分割;
Local:每次分裂前将重新提出候选切分点。

直观上来看,Local 策略需要更多的计算步骤,而 Global 策略因为节点没有划分所以需要更多的候选点。

下图给出不同种分裂策略的 AUC 变换曲线,横坐标为迭代次数,纵坐标为测试集 AUC,eps 为近似算法的精度,其倒数为桶的数量。
在这里插入图片描述
我们可以看到 Global 策略在候选点数多时(eps 小)可以和 Local 策略在候选点少时(eps 大)具有相似的精度。此外我们还发现,在 eps 取值合理的情况下,分位数策略可以获得与贪婪算法相同的精度。
在这里插入图片描述
第一个 for 循环:对特征 k 根据该特征分布的分位数找到切割点的候选集合 Sk={sk1,sk2,...,skl}S_k = \{ s_{k1},s_{k2},...,s_{kl}\}Sk={sk1,sk2,...,skl} 。XGBoost 支持 Global 策略和 Local 策略。

第二个 for 循环:针对每个特征的候选集合,将样本映射到由该特征对应的候选点集构成的分桶区间中,即 sk,v≥xjk≥sk,v−1s_{k,v} \geq x_{jk} \geq s_{k,v-1}sk,vxjksk,v1 ,对每个桶统计 G,HG,HG,H 值,最后在这些统计量上寻找最佳分裂点。

下图给出近似算法的具体例子,以三分位为例:
在这里插入图片描述
根据样本特征进行排序,然后基于分位数进行划分,并统计三个桶内的 [公式] 值,最终求解节点划分的增益。

加权分位数缩略图

事实上, XGBoost 不是简单地按照样本个数进行分位,而是以二阶导数值 [公式] 作为样本的权重进行划分,如下:
在这里插入图片描述
那么问题来了:为什么要用 hih_ihi 进行样本加权?

我们知道模型的目标函数为:
在这里插入图片描述
我们稍作整理,便可以看出 hih_ihi 有对 loss 加权的作用。
在这里插入图片描述
其中 121\over221gi2hig_i^2\over h_ihigi2CCC 皆为常数。我们可以看到 hih_ihi 就是平方损失函数中样本的权重。

对于样本权值相同的数据集来说,找到候选分位点已经有了解决方案(GK 算法),但是当样本权值不一样时,该如何找到候选分位点呢?(作者给出了一个 Weighted Quantile Sketch 算法,这里将不做介绍。)

稀疏感知算法

在决策树的第一篇文章中我们介绍 CART 树在应对数据缺失时的分裂策略,XGBoost 也给出了其解决方案。

XGBoost 在构建树的节点过程中只考虑非缺失值的数据遍历,而为每个节点增加了一个缺省方向,当样本相应的特征值缺失时,可以被归类到缺省方向上,最优的缺省方向可以从数据中学到。至于如何学到缺省值的分支,其实很简单,分别枚举特征缺省的样本归为左右分支后的增益,选择增益最大的枚举项即为最优缺省方向。

在构建树的过程中需要枚举特征缺失的样本,乍一看该算法的计算量增加了一倍,但其实该算法在构建树的过程中只考虑了特征未缺失的样本遍历,而特征值缺失的样本无需遍历只需直接分配到左右节点,故算法所需遍历的样本量减少,下图可以看到稀疏感知算法比 basic 算法速度块了超过 50 倍。
在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

redis深度历险_Redis的数据结构(内存具体怎么优化的)

上一篇我们讲解了Redis中SDS的组成以及优势&#xff0c;这一篇我们讨论下Redis中的Hash数据类型是怎么构成的呢&#xff1f;Java中存在HashMap和HashTable的数据类型。而Hash的数据结构可以近似于HashTable&#xff0c;依据数组链表的形式构成。在Redis中&#xff0c;Hash在元素…

.NET Core开发实战(第19课:日志作用域:解决不同请求之间的日志干扰)--学习笔记...

19 | 日志作用域&#xff1a;解决不同请求之间的日志干扰开始之前先看一下上一节的代码// 配置的框架 var configBuilder new ConfigurationBuilder(); configBuilder.AddCommandLine(args); configBuilder.AddJsonFile("appsettings.json", optional: false, reloa…

递归算法(二)-分治法

分治法 分治算法的基本思想是将一个规模为N的问题分解为K个规模较小的子问题&#xff0c;这些子问题相互独立且与原问题性质相同。求出子问题的解&#xff0c;就可得到原问题的解。即一种分目标完成程序算法&#xff0c;简单问题可用二分法完成。 分治法解题的一般步骤&#…

自适应滤波器在matlab仿真的程序_电气信息类专业课程之matlab系统仿真 第五章 BPSK通信系统(3)...

继续讲解&#xff01;上一篇文章提出了那么多问题&#xff0c;不知道大家是否能回答上来啊&#xff1f;如果回答不了&#xff0c;有没有去问问度娘呢&#xff1f;程序写完了&#xff0c;回想了一下辅导2017届学生毕业设计的过程&#xff0c;那是真累。我要求他们在现有程序基础…

阿捷外传之Git代码统计:DotNetCore + PowerBI 实现Git仓库日志分析

前言2020年3月初春&#xff0c;虽然春节已经过去一个多月&#xff0c;大街上还未恢复往年的热闹。由于春节前夕突然降临的冠状病毒&#xff0c;导致很多员工无法回到城市复工。春节之后&#xff0c;阿捷所在的公司考虑到复工带来的风险&#xff0c;通知所有员工以远程的方式在家…

递归算法(三)- 回溯法Backtracking

回溯法 回溯法Backtracking&#xff08;找所有的可能&#xff09;递归&#xff1a; 类似枚举&#xff0c;一层一层向下递归&#xff0c;尝试搜索答案。找到答案&#xff1a; > 返回答案&#xff0c;并尝试别的可能未找到答案&#xff1a; > 返回上一层递归&#xff0c;…

一个全栈式的应用集成平台,打破“信息孤岛”

源宝导读&#xff1a;随着企业数字化进程的逐渐深入&#xff0c;企业存在大量的异构系统&#xff0c;各个系统之间信息传输、资源利用困难。本文将介绍明源云ERP为了打破这种“信息孤岛”&#xff0c;而进行的思考与实践。一、前言随着企业信息化进程的逐步深入&#xff0c;互联…

【朝夕技术专刊】Core3.1WebApi_Filter多种注册方式支持依赖注入

欢迎大家阅读《朝夕Net社区技术专刊》第5期我们致力于.NetCore的推广和落地&#xff0c;为更好的帮助大家学习&#xff0c;方便分享干货&#xff0c;特创此刊&#xff01;很高兴你能成为忠实读者&#xff0c;文末福利不要错过哦&#xff01;01PARTCoreFilter多种注册方式在上一…

SQL(一)- 数据库介绍与基础操作

数据库介绍 一、常用的数据库分为两大类&#xff1a; 关系型数据库非关系型数据库&#xff08;NoSql&#xff09; 关系型数据库 概念&#xff1a;是建立在关系模型基础上的数据库&#xff0c;借助于集合代数等数学概念和方法来处理数据库中的数据。 关系型数据库的优势&am…

opencv +数字识别

现在很多场景需要使用的数字识别&#xff0c;比如银行卡识别&#xff0c;以及车牌识别等&#xff0c;在AI领域有很多图像识别算法&#xff0c;大多是居于opencv 或者谷歌开源的tesseract 识别.由于公司业务需要&#xff0c;需要开发一个客户端程序&#xff0c;同时需要在xp这种…

SQL(二)- 基础查询语句

简单的查询语句&#xff08;DQL&#xff09; 下面我们正式来学习查询语句&#xff0c;下面所有查询用到的表均为前面提到的三张表&#xff1a; 员工表中的数据&#xff1a; 部门表中的数据&#xff1a; 薪资表中的数据&#xff1a; 基本查询语句的语法&#xff1a; sele…

SQL(三)- 连接查询

连接查询概念 一、什么是连接查询&#xff1f; 在实际开发中&#xff0c;大部分的情况下都不是从单张表中查询数据&#xff0c;一般都是多张表联合查询最终取出最终结果。在实际再发中&#xff0c;一般一个业务都会对应多张表&#xff0c;比如学生和班级&#xff0c;最起码两…

远程办公也可以很高效

题图&#xff1a;我的站立办公环境因为疫情&#xff0c;全中国人民都过了一个难忘的春节&#xff0c;而身在武汉的我&#xff0c;更是没有出家门半步&#xff0c;坚决做到不过国家添乱。从开始的2月14到后来的2月20日&#xff0c;再到现在的3月10日&#xff0c;官方发布的复工日…

SQL(四) - 子查询和union以及limit分页

子查询概念 什么是子查询&#xff1f;子查询都可以出现在哪里&#xff1f; select语句当中嵌套select语句&#xff0c;被嵌套的select语句是子查询。 子查询可以出现在哪里&#xff1f; select..(select). from..(select). where..(select).1.where子句中使用子查询 案例&a…

ASP.NET Core中的Http缓存

ASP.NET Core中的Http缓存Http响应缓存可减少客户端或代理对 web服务器发出的请求数。响应缓存还减少了 web服务器生成响应所需的工作量。响应缓存由 Http请求中的 header控制。而 ASP.NETCore对其都有相应的实现&#xff0c;并不需要了解里面的工作细节&#xff0c;即可对其进…

SQL(五) - 表的创建以及操作

创建表 建表语句的语法格式&#xff1a; create table 表名(字段名1 数据类型,字段名2 数据类型,字段名3 数据类型,....);MySql常用数据类型 BLOB 二进制大对象&#xff08;存储图片、视频等流媒体信息&#xff09; Binary Large OBject &#xff08;对应java中的Object&…

Istio 2020 年 Roadmap——一切为了商用

原文地址&#xff1a;https://preliminary.istio.io/zh/blog/2020/tradewinds-2020/&#xff0c;由 ServiceMesher 社区翻译。Istio 解决了人们在运行微服务时遇到的实际问题。甚至早期的预发行版本就已经可以帮助用户诊断其体系架构中的延迟&#xff0c;提高服务的可靠性以及透…

SQL(七) - 事务、索引、视图

事务&#xff08;Transaction&#xff09; 3.1、什么是事务&#xff1f; 一个事务是一个完整的业务逻辑单元&#xff0c;不可再分。 比如&#xff1a;银行账户转账&#xff0c;从A账户向B账户转账10000.需要执行两条update语句&#xff1a; update t_act set balance balan…

如何编写高性能的C#代码(二)

使用Benchmark.NET对C# 代码进行基准测试的简介在我以前的文章中[10]&#xff0c;我介绍了该系列文章[11]&#xff0c;在其中我将分享我的经验&#xff0c;同时了解C&#xff03;和.NET Core&#xff08;corefx&#xff09;框架的新性能。在本文中&#xff0c;我想着重于对现有…

如何编写高性能的C#代码(一)

原文来自互联网&#xff0c;由长沙DotNET技术社区编译。如译文侵犯您的署名权或版权&#xff0c;请联系小编&#xff0c;小编将在24小时内删除。作者介绍&#xff1a;史蒂夫戈登&#xff08;Steve Gordon&#xff09;是Microsoft MVP&#xff0c;Pluralsight的作者&#xff0c;…