论文:https://arxiv.org/pdf/1603.02754.pdf
XGBoost的全称是eXtreme Gradient Boosting,是2014年3月陈天奇博士提出的,是基于CART树的一种boosting算法。
1. 定义目标函数
XGboost采用的是加法训练,首先优化第一棵树,之后再优化第二棵树,直至优化完k棵树。
在优化第t棵树时,前t-1课已定, y t = y t − 1 + f t ( x ) y^t = y^{t-1}+f_t(x) yt=yt−1+ft(x)。
n为样本数量,Obj为预测值与真实值之间的损失 l ( y , y ^ ) l(y,\hat{y}) l(y,y^)(如MSE)与惩罚项 Ω \Omega Ω 之和。
2. 二阶泰勒展开
XGboost使用二阶泰勒展开进行优化。泰勒公式为:
二次展开公式:
此处将 l ( y i , y ^ i t − 1 ) l(y_i,\hat{y}_i^{t-1}) l(yi,y^it−1)看做 f ( x ) f(x) f(x), f t ( x ) f_t(x) ft(x)看做△x,得:
其中 l ( y i , y ^ i t − 1 ) l(y_i,\hat{y}_i^{t-1}) l(yi,y^it−1)为常数项(前t-1棵树已经优化完了),所以可以去掉,对函数没有影响;
g i g_i gi和 h i h_i hi分别表示对x(即 y ^ t − 1 \hat{y}^{t-1} y^t−1)的一阶、二阶导(函数中没有 f t ( x ) f_t(x) ft(x),也是常数)。
3. 惩罚项量化
树的复杂度由叶子结点个数T和各个叶子结点的w表示:
进一步将 f t ( x ) f_t(x) ft(x)替换为 w w w,其中 I j I_j Ij表示被分到第j个叶子结点下的样本的下标集合:
至此,我们完成了第t棵树的叶子结点的权重计算。那么我们如何构建这个数的结构呢?
1. 贪心算法
构建树有多种算法,这里我们以贪心算法为例,说明构建树的过程。
算法流程
因为我们想要得到最小值,所以判断当前节点是否继续划分的标准是:划分后的score应比划分前的score要更小;确定划分点的标准为:选择(划分前score-划分后score)最大的切分点作为这一次的划分点。
设 I = I L ∪ I R I = I_L\cup I_R I=IL∪IR,则有:
2. 近似算法:分桶
用贪心算法来寻找最佳划分点,准确度非常不错,但是时间复杂度和空间复杂度都太高了,作者提出一种近似法分位法,先对数据进行分桶(Bucket),然后桶内的数据相加起来,作为一个代表来进行计算。
分桶有两种方式:
作者测试对几种不同的切分算法的AUC结果比较。可以看得出,当eps=0.05,也就是将数据分成20个Bucket的时候,AUC的分数跟精准的贪心算法一样。
Boosting不是一种串行的结构吗?怎么并行的?注意Xgboost的并行不是tree粒度的并行,Xgboost也是一次迭代完才能进行下一次迭代的(第t次迭代的损失函数里包含了前面t−1次迭代的预测值)。Xgboost的并行是在特征粒度上的。决策树的学习最耗时的一个步骤就是对特征的值进行排序(因为要确定最佳分割点),Xgboost在训练之前,预先对数据进行了排序,然后保存为block(块)结构,后面的迭代中重复地使用这个结构,大大减小计算量。这个block结构也使得并行成为了可能,在进行节点的分裂时,需要计算每个特征的增益,最终选增益最大的那个特征去做分裂,那么各个特征的增益计算就可以开多线程进行
Shrinkage(缩减):相当于学习速率。XGBoost 在进行完一次迭代后,会将叶子节点的权重乘上该系数,主要是为了削弱每棵树的影响,让后面有更大的学习空间。传统GBDT的实现也有学习速率;
每次计算Gain的时候分别遍历将含有缺失值的结点分别加到左边或者右边,选择Gain最大的方向作为缺失值应该在的方向。
xgboost本质上还是一个基于现有特征的分类器,并不能实现特征交叉的功能,需要手动手工的对特征进行交叉发现新的有效特征。
Python xgboost库中有两种训练模型的方法。
import xgboost as xgb
xgm = xgb.XGBClassifier()
xgm.fit(X_train, y_train)
y_pred = xgm.predict(X_test)
param = {'max_depth':2, 'eta':1, 'silent':1, 'objective':'binary:logistic' }
dtrain = xgb.DMatrix(X_train, y_train)
dtest = xgb.DMatrix(X_test)
bst = xgb.train(list(param), dtrain)
preds = bst.predict(dtest)
参见这篇博客
XGboost documentation