前言
最近在研究FATE的secureboost算法模块,发现secureboost算法在金融银行等数据集上表现的非常不错,了解到secureboost是基于XGBoost实现的,因此打算了解一下有关XGboost算法相关的内容,并在此记录一下。此篇博客参考了很多前辈的博客和内容,如果本篇内容有不懂的可以点入给出的链接中查看。
参考链接xgboost的原理没你想像的那么难 - 简书 (jianshu.com)
XGBoost的全称是Extreme Gradient Boosting,xgboost本质上对应的模型是一堆CART树。
什么是cart树?以下有关cart树的内容参考决策树算法--CART分类树算法 - 知乎 (zhihu.com)
CART分类树算法使用基尼系数选择特征,基尼系数代表了模型的不纯度,基尼系数越小,纯度越高,特征越好。
CART树
基尼系数
数据集D的纯度可用基尼值来度量
其中,p(x) 是分类xi 出现的概率,n是分类的数目。Gini(D)反映了从数据集D中随机抽取两个样本,其类别标记不一致的概率。因此,Gini(D)越小,则数据集D的纯度越高。
对于样本D,个数为|D|,根据特征A 是否取某一可能值a,把样本D分成两部分 D1和D2 。所以CART分类树算法建立起来的是二叉树,而不是多叉树。
对连续特征和离散特征的处理
连续特征
与C4.5思想相同,都是将连续的特征离散化。区别在选择划分点时,C4.5是信息增益率,CART是基尼系数。
具体思路:
1、m个样本的连续特征A有m个值,从小到大排列 a1,a2,...,am ,则CART取相邻两样本值的平均数做划分点,一共有m-1个,其中第i个划分点Ti表示为: Ti=(ai+ai+1)/2 。
2、分别计算以这m-1个点作为二元分类点时的基尼系数。选择基尼系数最小的点为该连续特征的二元离散分类点。比如取到的基尼系数最小的点为 at ,则小于at 的值为类别1,大于 at 的值为类别2,这样就做到了连续特征的离散化。
注意的是,与ID3、C4.5处理离散属性不同的是,如果当前节点为连续属性,则该属性在后面还可以参与子节点的产生选择过程。
离散特征
思路:不停的二分离散特征。
在ID3、C4.5,特征A被选取建立决策树节点,如果它有3个类别A1,A2,A3,我们会在决策树上建立一个三叉点,这样决策树是多叉树,而且离散特征只会参与一次节点的建立。
CART采用的是不停的二分,且一个特征可能会参与多次节点的建立。CART会考虑把特征A分成 A1 和 A2,A3、A2和A1,A3、A3和A1,A2 三种情况,找到基尼系数最小的组合,比如 A2 和 A1,A3 ,然后建立二叉树节点,一个节点是 A2 对应的样本,另一个节点是对 A1,A3 对应的样本。由于这次没有把特征A的取值完全分开,后面还有机会对子节点继续选择特征A划分 A1 和 A3 。
建立CART分类树步骤
输入:训练集D,基尼系数的阈值,切分的最少样本个数阈值
输出:分类树T
算法从根节点开始,用训练集递归建立CART分类树。
对于当前节点的数据集为D,如果样本个数小于阈值或没有特征,则返回决策子树,当前节点停止递归;
计算样本集D的基尼系数,如果基尼系数小于阈值,则返回决策树子树,当前节点停止递归 ;
计算当前节点现有各个特征的各个值的基尼指数,
在计算出来的各个特征的各个值的基尼系数中,选择基尼系数最小的特征A及其对应的取值a作为最优特征和最优切分点。 然后根据最优特征和最优切分点,将本节点的数据集划分成两部分 D1 和 D2 ,同时生成当前节点的两个子节点,左节点的数据集为 D1 ,右节点的数据集为 D2 。
对左右的子节点递归调用1-4步,生成CART分类树;
对生成的CART分类树做预测时,假如测试集里的样本落到了某个叶子节点,而该节点里有多个训练样本。则该测试样本的类别为这个叶子节点里概率最大的类别。
XGBoost
回到XGBoost算法,前文说到XGBoost模型是由一堆CART树构成的。XGBoost是由k个基模型(CART树)组成的一个加法模型,通过将每棵树的预测值加到一起作为最终的预测值.
下图就是CART树和一堆CART树的示例,用来判断一个人是否会喜欢计算机游戏:
其数学表达式可以用以下等式表达。
这里的K就是树的棵数,F表示所有可能的CART树,f表示一棵具体的CART树。这个模型由K棵CART树组成。
模型的目标函数如下:
目标函数包含两部分,第一部分是损失函数,第二部分是正则项。
训练XGboost
首先明确两个问题,训练XGBoost模型需要哪些内容 1、各个叶子节点的最佳值 2、确定树的结构。
一般运用加法训练来训练XGBoost模型,我们的目标不再是直接优化整个目标函数,这已经被我们证明是行不通的。而是分步骤优化目标函数,首先优化第一棵树,完了之后再优化第二棵树,直至优化完K棵树。整个过程如下图所示:
在第t步时,我们添加了一棵最优的CART树f_t,这棵最优的CART树f_t是怎么得来的呢?非常简单,就是在现有的t-1棵树的基础上,使得目标函数最小的那棵CART树,如下图所示:
constant就是前t-1棵树的复杂度,暂时忽略。
对上述公式进行泰勒二阶展开,可以得到以下
其中
这里对泰勒二阶展开进行一个详细的描述过程
泰勒展开的形式
因此有
在此处f(x)是
而当训练第t颗树时yi,还有y^(t-1)都是已知的,我们可以把他们当作常数项,因此未知项只有f_t(xi),所以在此次我们可以把f_t(xi)当作x来看待因此f(0)就等于
f'(0)就等于
f''(0)就等于
这里需要声明一些gi和hi的含义。gi和hi是我们的损失函数关于y i ^ ( t − 1 ) 的一阶导数和二阶导数,只要损失函数确定那么gi和hi也就确定了。具体举例参考:xgboost的原理没你想像的那么难 - 简书 (jianshu.com)
为了使得目标函数最小化,我们可以将常数项去除,因为常数对于最小化是没有影响的。所以目标函数此时可以变为以下形式:
上述目标函数可以用来判断一个第t棵树的好坏,但是对于正则化项
仍然不够清晰。因此我们现在来定义如何衡量一颗树的正则化项。首先对CART树做出另一番的定义:
其中T代表一颗树中叶子节点的个数,w是一个T维向量,由T个叶子节点的值组成。q(x)是一个映射,用来将样本映射成1到T的某个值,也就是把它分到某个叶子节点,q(x)其实就代表了CART树的结构。w_q(x)自然就是这棵树对样本x的预测值了。
有了这个定义,xgboost就使用了如下的正则化项:
注意:这里出现了γ和λ,这是xgboost自己定义的,在使用xgboost时,你可以设定它们的值,显然,γ越大,表示越希望获得结构简单的树,因为此时对较多叶子节点的树的惩罚越大。λ越大也是越希望获得结构简单的树
继续对目标函数进行简化:
解释:首先这里边Ij表示一个叶子节点的集合,集合中每个值代表一个训练样本的序号,整个集合就是被第t棵CART树分到了第j个叶子节点上的训练样本。因为所有的样本最后都会被归属到一个确定的叶子节点上,因此可以将目标函数从样本数的遍历转换为了从叶子节点上的遍历。而归属到同一叶子节点的样本的Wq(x)是相同的,因此对于归属于同一叶子节点集合的样本我们可以用Wj来代替Wq(x)。
进一步简化
对于第t棵树来说,前t-1棵树都已经确定了,因此G和H都是确定的而叶子节点的个数T确定的情况下变化只有w,因此目标函数此时只和w相关。
易知:对w j求偏导,偏导数为0时的w值,代入目标函数将取得最小值。如下图所示:
此时已经回答了最开始的第一个问题如何获得各个叶子节点的最佳值。同时当一个树的结构确定时,我们也能够通过目标函数来判定树结构的好坏。
然而树的结构应该怎么确定?贪心算法和近似算法
贪心算法:
最原始的猜想就是枚举出所有可能的树结构,即特征值和分裂阀值,然后再根据目标函数计算比较出最优的选择。比如,当我们的结点按如下方式进行划分:(这里做了一个简单的年龄排序)
按照这个图从左至右扫描,我们就可以找出所有的切分点。对每一个确定的切分点,我们衡量切分好坏的标准如下:
这个Gain实际上就是单节点的obj*减去切分后的两个节点的树obj*,Gain如果是正的,并且值越大,表示切分后obj*越小于单节点的obj*,就越值得切分。同时,我们还可以观察到,Gain的左半部分如果小于右侧的γ,则Gain就是负的,表明切分后obj反而变大了。γ在这里实际上是一个临界值,它的值越大,表示我们对切分后obj下降幅度要求越严。这个值也是可以在xgboost中设定的。
扫描结束后,我们就可以确定是否切分,如果切分,对切分出来的两个节点,递归地调用这个切分过程,我们就能获得一个相对较好的树结构。
近似算法:
由于贪心算法需要对每个特征进行排序,因此成为计算速度的瓶颈。近似算法就是根据特征的分布提前计算得到分l个分位点,Sk=Sk1,Sk2,…,Skl, 有了这些分为点,就可以将样本映射到对应的区间内,然后再次聚合区间内的信息,得到所有区间的最佳分裂点。很直观, 这种方式免去了贪心算法需要对每个特征进行排序的操作。
参考:从XGB到SecureBoost:看联邦学习XGB的算法原理 - 知乎 (zhihu.com)
本文详细介绍了XGBoost中的核心概念,包括它是如何基于CART决策树构建的,以及CART树的原理,如基尼系数和分裂策略。文章还探讨了XGBoost的优化目标函数和训练过程,包括贪婪算法和近似算法在构建树结构中的应用。

被折叠的 条评论
为什么被折叠?



