xgboost原理

XGBoost其实是由一群训练出来的CART回归树集成出来的模型。

目标

目标其实就是训练一群回归树,使这树群的预测值尽量接近真实值,并且有尽可能强大的泛化能力。来看看我们的优化函数:

优化函数

i表示的是第i个样本,前一项是表示的是预测误差。后一项表示的是树的复杂度的函数,值越小表示复杂度越低,泛化能力越强。我们来看看后一项的表达式:

树的复杂度函数

其中T表示叶子节点的个数,w表示的是节点的预测值(回归树的节点才有预测值)。

 

我们要做的就是使预测误差尽量小,叶子节点数尽量少,预测值尽量不极端(什么叫预测值尽量不极端?举个栗子,一个人的真实年龄是4岁,有两个模型,第一个模型的第一颗回归树预测值是3岁,第二颗回归树预测值是1岁,第二个模型的第一颗回归树预测值是2岁,第二颗预测值也是2岁,那我们更倾向于选择第二个模型,因为第一个模型学习的太多,有过拟合的风险)

那么我们如何才能把优化函数和回归树的参数联系在一起呢?回归树的参数我们知道有两个:(1)选哪个feature进行分裂(2)如何求取节点的预测值,上述公式并没有很好地反映出这两个问题的答案,那么是如何解决上述两个问题的呢?

答案就是:贪心策略+最优化(二次最优化)

 

贪心策略

那么是如何运用贪心策略(眼前利益最大化,每个节点的预测值都选最优)的呢?假设我们有一堆样本,放在第一个节点,这时T=1,w是多少呢?暂时不知道,w是计算出来的,这时所有的样本的w都相等,将wT代入优化函数中

第一步的损失函数

如果我们这里的l(w-y_i)损失函数使用的是平方损失函数,那么上式就变成了一个关于w的二次函数,最小的点就是极值点也就是该节点的预测值。

 

到这你可能发现了,这不就是二次函数的最优化问题吗?

那如果损失函数不是平方误差函数怎么办?我们采用的是泰勒展开的方式,任何函数总能用泰勒展开的方法表示,不是二次函数我们总能想办法让它变成二次函数。

 

那么我们再来看我们的两个问题:

(1)选哪个feature进行分裂?最粗暴的枚举法,用损失函数效果最好的那一个(粗暴枚举和XGBoost的并行化等我们在后面介绍)

(2)如何求取节点的预测值,对!就是我们刚刚说到的二次函数求最值(固定套路:二次函数求导为零的点就是最优值)!

 

那么步骤就是:枚举第一个feature,计算loss_function的最小值,枚举第二个feature,计算loss_function的最小......直到遍历完所有的feature,选择效果最好的feature,将feature的值分成大于w和小于w的两类,这不就把树给分成两叉了吗?

接下来继续分裂,在上一个分类的基础上,又形成一棵树,再形成一棵树,每次都是在最优的基础上进行分裂,不就是我们的贪心策略么。

但是一般这种循环迭代的方式都需要一个终止条件,总不能让它一直跑下去吧。

 

停止条件

停止条件大概有以下几种:

(1)当引入的分裂带来的增益(loss_function的降低量)小于一个阈值的时候,可以剪掉当前的分裂,所以并不是每一次分裂loss_function都会增加的。

(2)当树达到最大深度时,停止建树,因为树的深度太深容易出现过拟合,这里需要设置一个超参数max_depth。

(3)当样本权重和(跟AdaBoost一样,每个样本都有一个权重,这里的样本是指的节点的样本,不是全部的样本,所以权重相加不为1)小于某一个阈值时也停止建树,涉及到一个超参数:最小样本权重和,大意就是如果每个叶子节点包含的样本数量太少也停止,同样是过拟合的原因。

 

XGBoost的亮点

节点权值

XGBoost的权值是通过最优化二次函数(求导)求出来的,算是一种创新吧,和普通的求均值的或者其他什么规则不一样。

 

避免过拟合(正则化、shrinkage与采样技术)

 

正则化

一说起过拟合,我们的第一反应就是正则化。XGBoost也是这样做的。

我们在loss_function里看到了正则化项(树的复杂度函数),正则化的目的就是防止过拟合。我们再看看这个函数:

这里出现了γ和λ,这是XGBoost自己定义的,在使用XGBoost时,你可以设定它们的值,显然,γ越大,表示越希望获得结构简单的树,因为要整体最小化的话就要最小化T。λ越大也是越希望获得结构简单的树。

 

Shrinkage

 

除了使用正则化,我们还有shrinkage与采样技来避免过拟合的出现。

所谓的shrinkage就是在每次的迭代产生的树中,对每个叶子结点乘以一个缩减权重,主要的目的就是缩减该次迭代产生的树的影响力,留给后边迭代生成的树更多发挥的空间。

举个栗子:比如第一棵树预测值为3.3,label为4.0,第二棵树才学0.7,那后面的树就没啥可学的了,所以给他打个折扣,比如3折,那么第二棵树训练的残差为4.0-3.3*0.3=3.01,这就可以发挥了啦,以此类推,作用的话,就是防止过拟合。

 

采样技术

采样技术有两种,分别是行采样和列采样。

列采样效果比较好的是按层随机的方法:之前提到,每次分裂节点的时候我们都要遍历所有的特征和分割点,来确定最优分割点。如果加入列采样,我们会在同一层的结点分割前先随机选一部分特征,遍历的时候只用遍历这部分特征就行了。

行采样则是采用bagging的思想,每次只抽取部分样本进行训练,不使用全部的样本,可以增加树的多样性。

 

损失函数

这个点也是XGBoost比较bug的地方,因为XGBoost能够自定义损失函数,只要能够使用泰勒展开(能求一阶导和二阶导)的函数,都可以拿来做损失函数。你开心就好!

 

支持并行化

XGBoost的并行不是在模型上的并行,而是在特征上的并行,将特征列排序后以block的形式存储在内存中,在后面的迭代中重复使用这个结构。这个block也使得并行化成为了可能,其次在进行节点分裂时,计算每个特征的增益,最终选择增益最大的那个特征去做分割,那么各个特征的增益计算就可以开多线程进行。
posted @ 2018-12-12 22:21  下路派出所  阅读(557)  评论(0编辑  收藏  举报