【原创】XGBoost分类器原理及应用实战

article/2025/9/13 8:38:11

本文结合作者对xgboost原理的理解及使用xgboost做分类问题的经验,讲解xgboost在分类问题中的应用。内容主要包括xgboost原理简述、xgboost_classifier代码、xgboost使用心得和几个有深度的问题

XGBoost原理简述

xgboost并没有提出一种新的机器学习算法,而是基于现有的GBDT/lambdaMART等tree boosting算法在系统及算法层面(主要是系统层面)进行了改进;系统层面改进点包括:带权重的分位点分割算法(weighted quantile sketch)、稀疏特征的处理(sparsity-aware splitting)、缓存(cache-aware access)、out-of-core computation、特征并行、基于rabit的分布式训练等,这些改进使得xgboost无论是在单机训练还是分布式训练上的耗时都比pGBRT/scikit-learn/spark MLLib/R gbm等有至少几倍的提升;算法层面的改进主要包括:L1/L2正则化、目标函数二阶导的应用等;
boosting基本思想是叠加多个弱分类器的结果组合成一个强分类器,叠加方法是各个基分类器的结果做加法,在生成下一个基分类器的时候,目标是拟合历史分类器结果之和与label之间的残差,预测的时候是将每个基分类器结果相加;每个基分类器都是弱分类器,目前xgboost主要支持的基分类器有CART回归树、线性分类器;

CART回归树

CART(Classification And Regression Tree)回归树,顾名思义,是一个回归模型,同C4.5分类树一样,均是二叉树模型;父节点包含所有的样本,每次分裂的时候将父节点的样本划分到左子树和右子树中,划分的原则是找到最优特征的最优划分点使得目标函数最小,CART回归树的目标函数是平方误差,而C4.5的目标函数是信息增益(划分后的信息增益最大);
对CART回归树来说,孩子节点中样本的预测值是所有样本label的平均值(why?因为CART的目标函数是平方误差,使得平方误差最小的预测值就是平均值,可以证明一下),
而C4.5决策树中孩子节点的预测值一般采用投票法;在构建树的时候,两者都采用贪心算法,即每次节点分裂时找本次所有分裂点中目标函数最小的分裂点,该方法不一定能找到全局最优的树结构,但能有效的降低计算量;

XGBoost

多数情况下,xgboost将CART回归树作为基分类器(tree-based booster);xgboost不断生成新的CART回归树,每生成一颗树即是在学习一个新的函数,这个函数将每个样本映射到唯一确定的一个叶子节点中,同一叶子节点中的所有样本共享相同的预测值,函数的目标则是去拟合所有叶子节点中样本的历史残差;损失函数可以是与CART回归树相同的均方误差,也可以是交叉熵(一般用于分类问题中)或各种rank loss(用于rank问题中);
xgboost的目标函数可以表示如下:
在这里插入图片描述
其中第一项是训练损失(平方误差、交叉熵等),第二项是正则化损失(L1、L2等);为了便于计算,对上式进行泰勒展开,并取0/1/2阶项作为目标函数的近似表示:
在这里插入图片描述
将正则化项(L1和L2正则化项均不为0,其系数分别为gamma和lambda)带入上式,并进一步化简(将各个叶子节点中样本合并)得到如下:
在这里插入图片描述
不难发现,这个函数是关于叶子节点权重wj的二次函数,其最值点和最值分别为:
在这里插入图片描述
这样近似及化简之后,针对每个候选划分能快速计算其孩子节点的预测值和目标函数值,构建树的时候同样使用了贪心算法;
更详细的推导请参考XGBoost: A Scalable Tree Boosting System和tianqi的ppt;

xgboost_classifier代码

代码地址:https://github.com/suvedo/xgboost_classifier

线下训练

首先按照xgboost官方教程 clone源码,并安装python包。(不详述)
配置train_dir/config.py中的参数,包括:1)XGBoostConifg中的与xgboost模型相关的参数(参数含义详见下文的调参心得);2)Config中的与输入输出及其它训练相关的参数;
配置完参数后运行sh run.sh即可训练、验证并测试模型,程序会保存训练好的模型,将训练好的模型拷贝到deploy/c++目录下即可在线预测

在线预测

deploy/c++目录下运行make编译代码,然后运行./test_xgb_cls即可运行预测demo,预测之前先配置conf/xgb_cls.conf,包括模型路径、特征维度、树数量;若要把在线预测代码集成在自己的代码中,只需要拷贝 include/, lib/, xgboost_classifier.h, xgboost_classifier.cpp即可。

XGBoost使用心得

调参心得

booster:指明使用的基分类器,默认为gbtree,还可以选择gblinear和dart。gbtree则表示CART树,gblinear表示线性分类器,dart也是使用CART作为基分类器,只不过对各个CART树使用类似于nn里的drop-out,可以配置rate_drop来指明drop-out的比例;一般情况下,都使用默认的gbtree;
eta:收缩因子,或者学习率,每颗树的结果乘以eta为样本在这颗树的最终得分,eta一般小于1,eta越小,后续基分类器的学习空间就更大,同时也可以避免过拟合,如果发现树的颗树比较少,可以适当调低eta;默认值为0.3;
gamma:参数中的gamma不是公式中的L1正则化系数(L1正则化系数对应的参数为alpha),而是最小的分类损失降低(loss reduction),只有当节点分裂带来的损失降低大于gamma时才进行分裂,可以有效避免过拟合;默认值为0,注意:因为有正则化项的存在(特别是L1正则化),分裂节点不一定能带来正向的损失减小,所以gamma为0不一定表示所有的分裂均满足要求(均能分裂);
max_depth:树的最大深度,这个比较好理解;默认值为6,如果过拟合严重,可以适当减小该参数值;
subsample:生成下一颗树时训练样本的采样率(row subsampling),类似随机森林,默认为1,如果样本数量比较大或者过拟合严重,可以考虑减小该参数值;
colsample_bytree:生成每一颗树时对特征的采样率(column subsampling),类似随机森林,默认为1;
colsample_bylevel:生成每一层时特征的采用率,在每颗树的特征的基础上采样,colsample_bytree*colsample_bylevel,默认值为1
colsample_bynode:节点分裂时特征的采样率,在每颗树、每层的基础上采样,colsample_bytree*colsample_bylevel*colsample_bynode,默认值为1
lambda:叶子节点输出值的L2正则化系数,默认为1
alpha:叶子节点输出值的L1正则化系数,默认为0,即不做L1正则化系数
tree_method:构建树算法,候选值有exact、approx、hist、auto等,exact代表论文中的Basic Exact greedy algorithm,即每次生成孩子节点时遍历所有的特征的所有可能的分裂点,从而找到最优分裂点;approx表示带权的分位点分割算法,由(泰勒展开后的)损失函数可以推导出每个样本的损失是带权的平方误差,其权重为样本的二阶导数,而分位点算法是为了节省计算时间而提出的近似计算方法,将样本划分到多个bucket中,各个bucket之间有序,但bucket中的元素不需要有序,划分点就是每个bucket中最大值,使用分位点算法可以将候选划分点减小至m个(m表示bucket的个数),生成bucket的时候每个样本都是有权重的,权重为二阶导数;hist表示基于bin strategy的近似算法,具体原理还有待研究;auto表示根据数据量自动选择tree_method,数据量小时选择exact,数据量大时选择approx;
sketch_eps:当tree_method=approx时用于指明近似误差的大小,一般可以认为最终的bucket个数为O(1 / sketch_eps),因此sketch_eps越小,approx越接近exact;
objective:目标函数,默认为reg:squarederror,即平方误差;可以取binary:logistic/multi:softmax/rank:pairwise等;我在最先调参的时候使用reg:squarederror,而线上的xgboost版本比较老旧,不支持此目标函数,因此只能换成binary:logistic重新训练,换成binary:logistic并且early-stop的eval_metric选用auc反倒效果变好,分析原因为:我的任务中正负例样本比例悬殊比较大,使用rmse、error等对正负例敏感的eval_metric反倒效果不好,auc的含义及计算方法见机器学习一般流程总结;
base_score:样本的初始得分,相当于全局偏置,默认值为0.5;
eval_metric:验证集的metric,在训练的日志中能看到train和eval的metric;候选值有rmse(均方误差根)、error(分类错误率)、auc、ndcg等;根据目标函数的不同设置默认值;
enable_early_stop:是否使用early-stop,一般都需要使用验证集做训练时的验证和早停避免过拟合,也可以通过早停的情况了解自己的模型是否过拟合了;如果在xgb.train()的参数中指名了使用早停,则必须要指定evals列表;
early_stopping_rounds:eval_metric在early_stopping_rounds轮没有增加或减少则停止训练,一般设置为10轮;

XGBoost有哪些优点

我一开始使用nn做分类问题,nn比较擅长特征抽取,而我的任务的特征基本上是抽取好的,不需要nn的特征抽取能力,且nn训练慢,必须依赖gpu(公司内部训练工具导致),任务排队现象严重,效果低下;后来选用xgboost,训练速度极快,内存友好,且不依赖gpu,效果与nn基本持平;另外还有一点xgboost可以计算每个特征的重要性(get_fscore()或get_score()接口),这对于特征筛选、模型可解释性、模型透明、模型调优等都有好处;计算特征的重要性的原理:通过指明的important_type计算,比如important_type=weight时,则重要性就是该特征被用于节点分裂的次数,important_type=gain时就是特征分裂带来的平均收益,important_type=cover时就是每个节点中的所有样本的hessian值之后;xgboost还可以以明文的形式保存树模型,方便模型可视化和调优;xgboost不需要对特征做normalization;

几个有深度的问题

问题一:xgboost模型的参数是什么?
答:每颗树的树结构:针对非叶子节点则是其分裂特征及分裂点,针对叶子节点,则是其得分或者权重;或者理解成一个函数集合(参考线性booster);
问题二:gradient boosting tree中的梯度怎么理解?
答:xgboost的损失函数利用泰勒展开近似,对当前树(或函数)在0处求了一阶梯度和二阶梯度,由于是在0处求梯度,所以本质上是损失函数对历史基分类器和的梯度;如果是MART或者GBDT等tree boosting模型,其只使用一阶导近似,则可以得出当前树的目标就是拟合历史残差的梯度,而每颗树存在一个收缩因子eta,因此每颗树的贡献其实是eta * grad,这跟nn等模型中使用的sgd等优化算法有异曲同工之妙:sgd计算每轮的loss及其梯度,对应到boosting方法中则是每颗树的残差及其梯度,sgd的学习率则对应boosting的收缩因子,从这个角度看,boosting本质上也是利用梯度下降的方法一步步的逼近训练样本的真实值,从而达到模型训练的目的,而sgd优化方法也可以利用xgboost中的泰勒展开去理解,也可以使用loss的二阶导,目前一些更先进的基于梯度的优化方法或自适应学习率的优化方法已经引入了二阶导;
问题三:base_score有什么作用?
答:base_score永远存在,因为在生成第一颗树的时候也要使用历史分类器的和来计算损失和梯度,如果不指明,则表示历史分类器和为0;在对第一颗树的损失函数近似时,当前树节点的score如果越接近0,近似效果越好,因此可以选用一个base_score使得第一颗树的score尽量接近0,对于二分类问题(label为0和1),0.5是较好的选择(因为样本残差为-0.5或0.5),我猜测这也是为什么base_score的默认值是0.5的原因;
问题四:特征分裂点怎么找的?类别特征怎么处理?
答:针对连续特征值,划分点分别取所有的值(可以事先将特征值排好序),采用每个特征值进行划分,详见tree_method参数的解释;类别特征要转化为one-hot encoding,之后的划分方法与连续特征无两样;
问题五:孩子节点的值计算都是平均值吗?还是针对不同的loss有不同的计算方法?
答:孩子节点的取值目标是使得损失函数最小,如果损失函数是平方误差,由于平方误差的三阶导为0,因此泰勒展开近似后与原损失函数一样(即没有任何近似),此时孩子节点的值就是平均值;如果针对不同的loss,则是根据泰勒展开近似后得到二次函数(与平方误差一样),然后根据二次函数的最值点得到孩子节点的值;
问题六:利用泰勒展开做近似有什么作用?会对结果有多大程度的影响?
答:首先考虑不使用泰勒展开近似时,针对每个候选分裂点,都需要计算所有样本的损失,损失函数计算量大,更要命的是孩子节点的score怎么选,针对某些损失函数是否要遍历所有可能的值,遍历的话计算量可想而知,不遍历该如何保证精度,是否也需要使用近似;而使用泰勒展开近似后,将历史分类器的结果(梯度部分)与当前结果ft(x)分开,损失函数变成了关于两个孩子节点的二次函数,针对二次函数求最值,再简单不过了,在工程上也可以并行处理,针对不同的损失函数也可以很好的实现;至于对结果的影响有多大,取决于高阶梯度和ft(x)有多接近0,越接近近似效果越好,就算是近似效果不好,由于是多个分类器结果的叠加,影响面也不至于很大,而模型训练时本身就要使用各种手段防止过拟合,近似是否也有防止过拟合的效果呢;并且,基于问题二的分析,训练是不断逼近样本真实值的过程,引入收缩因子,可以将泰勒高阶项的影响进一步减小,尽量保证训练是按照正确的方向在进行(负梯度的方向);
问题七:xgboost如何并行?
答:xgboost的并行是在求特征分裂点时的并行,在泰勒展开近似后,损失函数的结构特别清晰明确,历史梯度只需要求一次,所有分裂点共享,不同特征的分裂点之间完全独立,完全可以并行;可以事先针对每个特征对所有样本排个序,在分裂的时候能快速找到分裂点前后的样本并计算历史梯度和;具体实现的时候csc格式的block存储有序的特征;

参考文献

xgboost官方教程
一文读懂机器学习大杀器XGBoost原理
XGBoost: A Scalable Tree Boosting System
xgboost之分位点算法


http://chatgpt.dhexx.cn/article/hDVW40r5.shtml

相关文章

xgboost 算法原理

1、xgboost是什么 全称:eXtreme Gradient Boosting 作者:陈天奇(华盛顿大学博士) 基础:GBDT 所属:boosting迭代型、树类算法。 适用范围:分类、回归 优点:速度快、效果好、能处理大规模数据、支持多种…

xgboost入门与实战(原理篇)

xgboost入门与实战(原理篇) 前言: xgboost是大规模并行boosted tree的工具,它是目前最快最好的开源boosted tree工具包,比常见的工具包快10倍以上。在数据科学方面,有大量kaggle选手选用它进行数据挖掘比赛,其中包括两个以上kaggle比赛的夺冠方案。在工业界规模方面,x…

xgboost原理分析以及实践

摘要 本文在写完GBDT的三篇文章后本来就想写的,但一直没有时间,终于刚好碰上需要,有空来写这篇关于xgboost原理以及一些实践的东西(这里实践不是指给出代码然后跑结果,而是我们来手动算一算整个xgboost流程&#xff0…

机器学习—XGboost的原理、工程实现与优缺点

文章目录 一、xgboost简介二、xgboost原理1.从目标函数生成一棵树1.1学习第t颗树1.2xgboost的目标函数1.3泰勒公式展开1.4定义一棵树1.5定义树的复杂度1.6叶子节点归组1.7树结构打分 2.一棵树的生成细节2.1最优切分点划分算法2.1.1贪心算法2.1.2近似算法 2.2加权分位数缩略图2.…

XGBoost原理介绍

1. Introduction 在这篇文章中,我将介绍XGBoost(eXtreme Gradient Boosting),一种tree boosting的可扩展机器学习系统。这个系统可以作为开源的软件包使用。该系统的影响已经在大量的机器学习和数据挖掘挑战中被广泛地认可。这些…

XGBoost算法介绍

XGBoost算法介绍 一、简介二、基本原理三、目标函数三、节点分裂3.1 贪心算法3.2 近似算法 四、其它特点4.1 缺失值处理4.2 防止过拟合 五、总结 一、简介 XGBoost(eXtreme Gradient Boosting)又叫极度梯度提升树,是boosting算法的一种实现方式。针对分类或回归问题…

xgboost原理(无推导就轻易理解)

一、模型训练过程 贪心优化算法。多颗决策树串行训练,第一棵树拟合训练目标、第二颗树拟合前面的残差、第三棵树拟合前两棵树留下的残差。 1、残差来源: (1)第k颗树训练时,行采样列采样(即仅有部分样本、…

一文读懂机器学习大杀器XGBoost原理

【导读】XGBoost是boosting算法的其中一种。Boosting算法的思想是将许多弱分类器集成在一起形成一个强分类器。因为XGBoost是一种提升树模型,所以它是将许多树模型集成在一起,形成一个很强的分类器。而所用到的树模型则是CART回归树模型。讲解其原理前,先讲解一下CART回归树…

XGBoost详解(原理篇)

入门小菜鸟,希望像做笔记记录自己学的东西,也希望能帮助到同样入门的人,更希望大佬们帮忙纠错啦~侵权立删。 目录 一、XGBoost简介 二、XGBoost原理 1、基本组成元素 2、整体思路 (1)训练过程——构建XGBoost模型…

XGBoost 原理介绍

1.简介 XGBoost的全称是eXtreme Gradient Boosting,它是经过优化的分布式梯度提升库,旨在高效、灵活且可移植。XGBoost是大规模并行boosting tree的工具,它是目前最快最好的开源 boosting tree工具包,比常见的工具包快10倍以上。…

「Flink实时数据分析系列」6.基于时间和窗口的算子

来源 | 「Stream Processing with Apache Flink」 作者 | Fabian Hueske and Vasiliki Kalavri 翻译 | 吴邪 大数据4年从业经验,目前就职于广州一家互联网公司,负责大数据基础平台自研、离线计算&实时计算研究 校对 | gongyouliu 编辑 | auroral-L 全…

大数据Hadoop之——Flink DataStream API 和 DataSet API

文章目录 一、DataStream API概述二、什么是DataStream ?三、DataStream 数据处理过程1)Data Sources(数据源)1、Data Sources 原理2、Data Sources 实现方式1)基于文件2)基于套接字3)基于集合4…

数据挖掘常用算法整理

前言: 找工作时(IT行业),除了常见的软件开发以外,机器学习岗位也可以当作是一个选择,不少计算机方向的研究生都会接触这个,如果你的研究方向是机器学习/数据挖掘之类,且又对其非常感…

C++ 26 常用算法

目录 一、概述 1.1 常用遍历算法 1.1.1 算法简介 1.1.2 for_each遍历算法 1.1.3 transform遍历算法 1.2 常用查找算法 1.2.1 算法简介 1.2.2 find 查找算法 1.2.3 find_if 查找算法 1.2.4 adjacent_find 查找算法 1.2.5 binary_search 查找算法 1.2.6 count 查找算法…

干货 | 轻松看懂机器学习十大常用算法

通过本篇文章可以对ML的常用算法有个常识性的认识,没有代码,没有复杂的理论推导,就是图解一下,知道这些算法是什么,它们是怎么应用的,例子主要是分类问题。 每个算法都看了好几个视频,挑出讲的最…

常用十种算法

目录 1、二分查找算法(非递归)二分查找算法(非递归)介绍二分查找算法(非递归)代码实现 2、分治算法分治算法介绍分治算法的基本步骤分治算法最佳实践汉诺塔 3、动态规划动态规划算法介绍应用场景——背包问题 4、KMP算法*next数组生成KMP 算法介绍应用场…

Java常用算法

Java常用算法 一、二分查找算法(非递归) 1、介绍 ​ 二分查找法只适用于从有序的数列中进行查找(比如数字和字母等),将数列排序后再进行查找。 ​ 二分查找法的运行时间为对数时间O(㏒₂n) ,即查找到需要的目标位置最多只需要㏒…

五大常用算法学习笔记

一。分治算法:快速排序、归并排序、大整数乘法、二分查找、递归(汉诺塔) 基本概念:把一个复杂的问题分成若干个相同或相似的子问题,再把子问题分成更小的子问题… , 知道最后子问题可以简单的直接求解&…

常见算法

首页 论坛 新闻 文章 下载 源码 网友作品 合作开发 招聘 刻盘服务 编程爱好者光盘 请登陆或者注册新用户 用户名 密 码 记住密码 注册新用户 忘记密码了 您所在位置:编程爱好者论坛 — C/C语言讨论区 — 我见到过的一些常用算法 C/C语言讨论区:…

最常用算法汇总(一)

一、贪心算法 贪心算法(又称贪婪算法)是指,在对问题求解时,总是做出在当前看来是最好的选择。也就是说,不从整体最优上加以考虑,他所做出的仅是在某种意义上的局部最优解。贪心算法不是对所有问题都能得到整…