下面推荐两篇写得最权威最官方(没有之一)的文档
参考文档:
XGBoost官方文档(全英文)
LightGBM官方文档(全英文)
关于GBDT算法,优点非常多,可以算是将boosting的思想发挥到了极致,处理许多数据效果都是非常好,但是正所谓人无完人,算法也没有一个是完美了,只有在特定条件下表现最佳的算法,没有在任何情况下表现都最好的算法。GBDT的缺点一个是只能串行实现,训练时间比较长,还有一个就是计算复杂度高,面对高维数据时计算非常耗时耗资源,吃力,而且相对其他后面两个算法来说容易产生过拟合。所以才有了它的优化版本,XGBoost,以及后面更加优化的版本LightGBM
基于传统GBDT算法的工程改进实现,和GBDT的思想是一样的,算法过程也是大致相同,最最主要的区别是针对传统GBDT算法的缺点不足进行改良,改良后大大提升了其准确率和泛化能力。
1.正则项
传统GBDT是没有加入正则项的,紧紧对损失函数进行最小化,但是这样产生的问题就是容易过拟合,所以为了优化过拟合问题,XBGoost加入了正则项,则目标函数就变成了如下:
前者为损失函数,后者为正则项(复杂度),而对于正则项如何工作,可以参考论文,涉及公式推导
XGBoost中将复杂度定义为如上,也可以定义为其他,但是这种定义是效果最好的
注:公式中两个参数对应模型参数中lambda ,gamma
2.损失函数二阶泰勒展开
传统GBDT在模型训练时只是用了损失函数的一阶导数信息,XGBoost对损失函数进行二阶泰勒展开,可以同时使用一阶和二阶导数。GBDT仅仅采用一阶导的一个不足就是最终找到的不能保证是全局最优,XGBoost采用二阶泰勒展开可以挖掘更多关于梯度的信息,可以更为精准的逼近真实的损失函数。(需要注意的是,损失函数需要二阶可导)
3.分裂算法
XGBoost在寻找特征最佳分裂点时的算法有许多种,针对不同数据类型和数据量可以选择不同不同寻找最佳分割点的算法。传统GBDT算法寻找最佳分裂点往往通过采用精确贪心算法计算增益,枚举所有可能的分裂点,然后选择最佳增益的点进行分裂,但是贪心法的计算量非常大,会让模型训练复杂度变高,消耗更多时间。所以XGBoost提供了更多的分裂点寻找算法。
3.1 精确贪心算法
这就是上面说的最原始也最笨的一种方法,在面对小数据量的时候可以用。
3.2 近似贪心算法
首先根据特征分布的百分位数提出候选分割点,基于候选分割点,将连续特征映射到各个桶里,最后根据聚合后的分割点效果找出最优的分割点。
3.3 加权分位数算法
对于大型数据集合而言,计算候选分割点比较困难,当数据具有不同的权重时,不好计算候选分割点,所以才提出的这种方法(说实话,这种方法还不是特别懂!)
3.4 稀疏感知分裂发现算法
对于数据中的稀疏数据(缺失值,one-hot编码的类别特征,许多0值),在树节点中提出一个默认的方向,那么这个样本将被划分到默认的方向上去,而默认的方向时通过算法从数据中学习出来的,这种方式可以大大提升算法的效率。
4.并行学习
我们都知道boosting算法是串行实现的,并不能像bagging一样同时进行多颗树的训练,那XGBoost是怎样进行并行的呢?这里说的XGBoost并行并不是建树时的并行,而是在特征粒度上的。决策树的学习最耗时的一个步骤就是对特征的值进行排序(因为要算增益),XGBoost在训练之前,预先对数据进行了排序,然后保存为block结构,后面的迭代中重复地使用这个结构,大大减小计算量。这个block结构也使得并行成为了可能,在进行节点的分裂时,需要计算每个特征的增益,最终选增益最大的那个特征去做分裂,那么各个特征的增益计算就可以开多线程进行。
5.列采样
列采样的思想是借鉴随机森林的构建思想,这样支持进行特征采样的方法有一个好处就是可以有效防止过拟合,不得不说XGBoost在防止过拟合方面真的做得不错!
6.缺失值处理
缺失值的处理方面就是出于XGBoost在寻找最优分割点时的稀疏感知分裂算法,在训练阶段寻找分裂点的时候,计算的分裂增益不包含缺失值样本,为了保证完备性,会分别将缺失该特征值的样本分配到左叶子结点和右叶子结点的两种情形,计算增益后选择增益大的方向归类含缺失值样本。
7.基分类器多样化
传统的GBDT采用CART作为基分类器,XGBoost支持多种类型的基分类器,比如线性分类器。
不得不说,这个世界的一切都在进步,尽管有些事情看似已经很完美了,但是总有人能创造出更好的东西。像XGBoost这样优秀的算法模型也会被 “吹毛求疵” ,LightGBM的提出改进了XGBoost的一个大缺陷-----慢。。用过XGBoost的人就知道,我跑个几百万的数据都要十几或者几十分钟,前面已经提到,相比于GBDT来说,XGBoost已经在速度上提升了非常多了,但是在这个数据量动不动就上亿的大数据时代,XGBoost的快也相对于慢了,所以“Light”顾名思义就是更加轻量级,可以让模型效率更高的算法。
LightGBM和XGBoost相比更好吗?作为一个用它们做过几个项目的人,我觉得他们在预测准确率上面不相上下,对于不同的数据和不同的特征维度谁好谁差不好说,因为Lightgbm的提升主要并不是在核心算法进行改动,而是在内存占用和计算复杂度方面进行改进,所以我个人感觉XGBoost和LightGBM在预测准确性方面都差不太多。最最主要的,也是最最明显,也是最最毋庸置疑的差别就是LightGBM比XGBoost快很多!!!
1.GOSS算法
LightGBM的优化之一是使用这个算法,GOSS算法全称Gradient-based One-Side Sampling(基于梯度的单边采样)。传统的boosting算法需要对每一个特征都要扫描所有的样本点来选择最好的切分点,这是非常的耗时,所以lgb(LightGBM简称)就想针对性地对一些特殊的样本进行训练(这里有点adaboost的思想,但是实现方法不同,可以参考下我前面写的adaboost算法原理),GOSS算法的思想是:梯度大的样本点在信息增益的计算上扮演着主要的作用,也就是说这些梯度大的样本点会贡献更多的信息增益(因为如果一个样本点的梯度小,那么该样本点的训练误差就小并且已经经过了很好的训练),因此为了保持信息增益评估的精度,当我们对样本进行下采样的时候保留这些梯度大的样本点,而对于梯度小的样本点按比例进行随机采样。
下图是截取自英文论文的GOSS算法流程(抱歉没找到中文版):
这里不具体去推导GOSS算法具体每一步的公式,我主要是讲解该算法在lgb中起到的重要作用。
2.EFB算法
EFB算法全称Exclusive Feature Bundling(互斥特征合并)。lgb实现中不仅进行了数据采样,也进行了特征抽样,但是该特征抽样又与一般的特征抽样有所不同,是将互斥特征绑定在一起从而减少特征维度。主要思想就是,通常在实际应用中高纬度的数据往往都是稀疏数据,这使我们有可能设计一种几乎无损的方法来减少有效特征的数量。尤其,在稀疏特征空间中许多特征都是互斥的。这就使我们可以安全的将互斥特征绑定在一起形成一个特征,从而减少特征维度。
下图为EFB算法中找到最佳合并特征和合并特征的步骤(抱歉没找到中文版):
3.直方图算法
直方图算法其实在XGBoost中也有应用,就是上面提到的近似贪心算法,只不过lgb在运用了GOSS和EFB算法后将直方图算法发挥出了比XGBoost更好的作用。
4.Leaf-wise构建树
传统的GBDT和XGBoost构建树都是采用Level-wise,但实Level-wise是一种低效的算法,因为它不加区分的对待同一层的叶子,带来了很多没必要的开销。lgb对于树的生长使用的是Leaf-wise,而不是Level-wise。其实通常来说,Level-wise对于防止过拟合还是很有作用的,Leaf-wise能够追求更好的精度,让产生更好精度的节点做分裂,但这样带来过拟合的问题,但是因为lgb在做数据合并,EFB和GOSS等各个操作,其实都有天然正则化的作用,而且可以通过控制树的深度来防止过拟合,所以使用Leaf-wise来提高精度是一个很不错的选择。
关于LGB最最重要的改进我觉得就是上面的这些了,当然还有一些小的改进,比如支持类别特征,并行的优化,内存优化等等
其他的不敢说,LightGBM比XGBoost更快,更省内存,这是毋庸置疑的!
本人才疏学浅,有理解错误或者不到位的地方欢迎提出并改正!