参考文献:XGBoost: A Scalable Tree Boosting System, Tianqi Chen, 2016.
XGBoost是Boosting算法的一种,假设原始样本为
即样本量n,特征个数m。集成学习器形式为
其中
是回归树(CART)空间,L是树的叶子结点的数量,q是代表树的结构的函数,其将自变量映射到相应的叶子结点的编号上,\vec{w}是叶子结点的取值向量(w_j是第j个叶子结点的取值)。
假设l是可微凸函数,表示集成学习器和数据的拟合程度。我们将集成学习器的损失函数取成
其中
是正则项,代表对树的复杂度的惩罚,其第一项代表对叶子结点数进行惩罚,第二项是对叶子结点的取值的平方和进行惩罚,前者和树的深度等价,都能反映一棵树的复杂度,后者太大则在集成学习器的预测中占比太高,也会过拟合。γ和λ是正则系数(非负)。
基学习器(回归树)训练准则
回顾Boosting算法的流程我们知道得到前t-1棵树后,我们要定义第t棵树的损失函数,假设树的结构q已知的情况下,其损失定义为
上标(t-1)表示第t-1步迭代时的预测值。我们对上式右边第一项进行二阶泰勒展开:
由于前t-1棵树中不含未知参数,因此g和h的值是已知的并且优化上述目标函数等价于优化
定义
即叶子结点j包含的实例集(instance set),则损失展开式可以写成
由于我们假设l是可微凸函数,因此其二阶导大于零,因此上式中w_j的函数是关于未知参数的开口向上二次函数,我们可以求得w_j的最小值点
以及损失的最小值
注意上式的得出建立在我们已经确定了整棵树的结构q的前提下,其可以作为一个评分函数来衡量树结构q的质量(再次重申g和h的值是已知的)。
显然不可能遍历所有可能得树结构q来选出损失最小的结构,实际上我们是使用贪婪算法来生成树的结构q的。假设我们确定了一个节点分裂后左右子结点上的样本子集(记为I_L和I_R,并记I=I_L∪I_R),通过如下损失降低值(定义为分裂前的损失减去分裂后的损失)判断是否进行这一分裂:
若其大于0则分裂后损失降低,分裂,若其小于0则分裂后损失增加,不分裂。可以设置一个极小的正数当l_split小于此数值时就不分裂。上式中-γ是因为分裂后多了一个结点。
收缩和列采样
除了损失函数中的正则项外,我们还有另外两个防止过拟合的技术,即收缩(shrinkage)和列采样(column subsampling)。收缩在新产生的树前面加一个小于等于1的常数η(注意这里是第t棵树训练完了才给它乘以η然后加在前t-1步训练出的学习器上得到前t步训练出的学习器,然后再去训练第t+1棵树),降低每棵树的影响,让后面的树可以更好的提升模型。列采样则是通过随机选取部分特征用于树的训练(其他特征直接不考虑)来降低过拟合风险,列采样方式分为全局和局部两种,前者在树构建的初始阶段选取全部特征的子集,后续就只考虑这些被选中的特征,后者则是在划分每个结点时从全部特征中随机选取其子集,选中的特征只针对本结点的划分,后续结点用到的候选特征再重新选取。
树结构求解算法
精确贪婪算法
我们希望用l_split作为准则来划分回归树,考虑所有特征和所有可能的划分时,算法叫做精确贪婪算法(Basic Exact Greedy Algorithm),算法考虑某一连续特征时,会现将其按此特征大小将样本排序。
近似算法
精确贪婪算法是非常强大的,因为它列举了所有可能的分裂点。但是,当数据不能完全放入内存时,或在分布式设置中,此算法都没法实现,在这两种情况下,需要一个近似算法来替代精确算法。
我们将第k个特征和h_i^(t)的集合记为
然后定义rank函数为
即特征k的取值小于z的那些样品所占比例。我们想要找到备选的切分点
使得
本算法有两种变体,即全局分割和局部分割。全局分割在树构建的初始阶段提出所有的候选分割,并在所有的层次上使用相同的分割方案。局部分割(一般都用这个)在每次结点分裂后重新选定候选分割。全局方法比局部方法需要更少的建议步骤。然而,全局分割通常需要更多的候选点,因为候选点每次分裂后没有被refine。局部分割在每次结点分裂后都会refine候选点,因此更适合更深的树。局部分割需要的候选点个数较少,但如果有足够多的候选点,全局分割可以和局部分割一样准确。算法中候选点的多少通过epsilon的大小来反映,其越小则候选点越多。
稀疏感知分割
现实问题中输入x常常是稀疏的,稀疏性有多种可能的成因:1. 数据中存在缺失值;2. 统计中经常出现零项;3. 特征工程的产物,one-hot编码。重要的是要使算法意识到数据中的稀疏模式。稀疏感知分割(Sparsity-aware Split Finding)首先将缺失值样品放在一边不管,然后使用算法2的方式处理非缺失值。然后在每个树节点中添加一个默认方向(假设是右边R),将特征k的值缺失的个体全部分入默认方向R,先计算默认方向的反方向L(不含缺失值)的G_L和H_L,然后用G-G_L和H-H_L作为默认方向的G_R和H_R值。默认方向取成左和右分别计算损失降低值,较大者作为默认方向。
总结
XGBoost算法作为Boosting算法的一种,其流程和其他Boosting算法相同,即逐个训练基学习器,然后将基学习器集成为最终学习器(XGBoost的集成方式为直接将基学习器相加)。
XGBoost的特色部分是其基学习器为回归树,回归树的训练方式为先用上节算法确定树结构,再用第一节结论得到每个叶子结点预测值。具体的,有了前t-1棵树的结果后,我们开始训练第t棵树,首先根据数据集和前t-1棵树,我们能够直接算出g_i和h_i,然后从根节点开始进行结点分裂,分裂一个结点时挨个考虑每个特征,首先按一个特征的样本观测值将样品实例从小到大排序,然后考虑按候选切分点分裂后的损失降低值,取损失降低最多的候选切分点作为该特征的最佳切分点,然后对比所有特征的最佳切分点,取其中损失降低值最大的那个特征及其最佳切分点来分裂当前结点,其中可以考虑所有可能的候选切分点(精确算法,耗时多但准确),也可以按一定准则选取全部候选切分点的子集从中选取最佳切分点(近似算法,牺牲一定精确度换取耗时少)。结点停止分裂的准则可以是损失降低值小于一个给定正实数、结点上的数据集包含样品数小于一个给定正整数等。
注意XGBoost的树分裂是Level-wise的,即先分裂根节点(第一层),产生两个子结点(第二层)后,再依次分裂这两个子结点得到第三层的结点,这样依次按层分裂下去。直至一层中全部是叶子结点时停止。此方法容易进行多线程优化,也好控制模型复杂度,不容易过拟合。但是不加区分的对待同一层的所有结点,实际上很多结点的分裂增益较低,没必要进行搜索和分裂,因此也会带来不必要的计算开销。
需要注意的时XGBoost只接受数值型特征,若是类别特征则需要先行预处理转化成数值型。
作为GBDT的改进,XGBoost与之不同之处包括:对损失函数做了2阶泰勒展开,并在损失函数中加入正则项抑制过拟合;每个弱学习器的学习过程是并行的;可以处理缺失值。