参考文章:https://blog.csdn.net/qq_24519677/article/details/81869196 一、泰坦尼克数据用sklearn调用XGBoost 用原生版本调用 二、鸢尾花数据 补充: 一、调用方式 1、调用自己的XGBoost库 import XGBoost as XGB 读取数据xgb.Dmatrix()、设置参数param={}、训练模型bst=xgb.train(param) 、预测结果bst.predict() 2、使用xgboost库的sklearnAPI,用sklearn中惯用的实例化,fit与predict流程运行,也可以调用属性coef_等等 使用xgboost中设定的建模流程来建模,和使用sklearnAPI中的类来建模,模型效果是比较相似的,但是xgboost库本身的运算速度(尤其是交叉验证)以及调参手段比sklearn要简单
二、梯度提升回归树工作原理 首先,梯度提升回归树是专注于回归的树模型的提升集成模型,其建模过程大致如下:最开始先建立一棵树,然后逐渐迭代,每次迭代过程中都增加一棵树,逐渐形成众多树模型集成的强评估器。 对于决策树而言,每个被放入模型的任意样本最终一个都会落到一个叶子节点上。而对于回归树,每个叶子节点上的值是这个叶子节点上所有样本的均值。 对于梯度提升回归树来说,每个样本的预测结果可以表示为所有树上的结果的加权求和:
XGB vs GBDT 核心区别1:求解预测值的方式不同 GBDT中预测值是由所有弱分类器上的预测结果的加权求和,其中每个样本上的预测结果就是样本所在的叶子节点的均值。而XGBT中的预测值是所有弱分类器上的叶子权重直接求和得到,计算叶子权重是一个复杂的过程。
三、重要参数 1、超参数n_estimators:与随机森林表现出的状态类似,建议优先调整n_estimators,一般都不会建议一个太大的数目,300以下为佳。 2、有放回随机抽样重要参数subsample: 在梯度提升树中,每构建一个评估器都让模型集中于数据集中容易被判错的样本。在有放回的抽样中加大了上次抽样被判断错误的样本的权重,基于这个有权重的训练集来建模,新建的决策树就会更加倾向于这些权重更大的,很容易被判错的样本。建模完毕之后,又将判错的样本反馈给原始数据集。下一次迭代的时候,被判错的样本的权重会更大,新的模型会更加向于很难被判断的这些样本。如此反复迭代,越后面建的树,越是之前的树们判错样本上的专家,越专注于攻克那些之前的树们不擅长的数据。对于一个样本而言,它被预测错误的次数越多,被加大权重的次数也就越多。我们相信,只要弱分类器足够强大,随着模型整体不断在被判错的样本上发力,这些样本会渐渐被判断正确。如此就一定程度上实现了我们每新建一棵树模型的效果都会提升的目标。 在xgb和sklearn中,这个参数都默认为1且不能取到0,这说明我们无法控制模型是否进行随机有放回抽样,只能控制抽样抽出来的样本量大概是多少 那除了让模型更加集中于那些困难样本,采样还对模型造成了什么样的影响呢?采样会减少样本数量,而从学习曲线来看样本数量越少模型的过拟合会越严重,因为对模型来说,数据量越少模型学习越容易,学到的规则也会越具体越不适用于测试样本。所以subsample参数通常是在样本量本身很大的时候来调整和使用。我们的模型现在正处于样本量过少并且过拟合的状态,根据学习曲线展现出来的规律,我们的训练样本量在200左右的时候,模型的效果有可能反而比更多训练数据的时候好,但这不代表模型的泛化能力在更小的训练样本量下会更强。正常来说样本量越大,模型才不容易过拟合,现在展现出来的效果,是由于我们的样本量太小造成的一个巧合。 从这个角度来看,subsample参数对模型的影响应该会非常不稳定,大概率应该是无法提升模型的泛化能力的,但也不乏提升模型的可能性。
3、迭代决策树的参数eta 除了保证模型逐渐倾向于困难样本的方向,还必须控制新弱分类器的生成,必须保证,每次新添加的树一定得是对这个新数据集预测效果最优的那一棵树。 类比逻辑回归,首先找到一个损失函数,这个损失函数应该可以通过带入预测结果来衡量梯度提升树在样本的预测效果。然后,我们利用梯度下降来迭代集成算法: 梯度提升树可是说是由三个重要的部分组成: 1). 一个能够实现预测的弱评估器 2). 一种能够让弱评估器集成的手段,包括我们讲解的迭代方法,抽样手段,样本加权等等过程 3). 一个能够衡量集成算法效果的,能够被最优化的损失函数 XGBoost是在梯度提升树的这三个核心要素上运行,它重新定义了损失函数和弱评器,并且对提升算法的集成手段进行了改进,实现了运算速度和模型效果的高度平衡。并且,XGBoost将原本的梯度提升树拓展开来,让XGBoost不再是单纯的树的集成模型,也不只是单单的回归模型。
4、选择弱评估器:booster(都默认为"gbtree") 5、XGB的目标函数:重要参数objective(objective参数的默认值是二分类,必须手动调节) 梯度提升算法中都存在着损失函数。不同于逻辑回归和SVM等算法中固定的损失函数写法,集成算法中的损失函数是可选的,要选用什么损失函数取决于我们希望解决什么问题,以及希望使用怎样的模型。比如说,如果我们的目标是进行回归预测,那我们可以选择调节后的均方误差RMSE作为我们的损失函数。如果我们是进行分类预测,那我们可以选择错误率error或者对数损失log_loss。只要我们选出的函数是一个可微的,能够代表某种损失的函数,它就可以是我们XGB中的损失函数. 在众多机器学习算法中,损失函数的核心是衡量模型的泛化能力,即模型在未知数据上的预测的准确与否,我们训练模型的核心目标也是希望模型能够预测准确。在XGB中,预测准确自然是非常重要的因素,但我们之前提到过,XGB的是实现了模型表现和运算速度的平衡的算法。普通的损失函数,比如错误率,均方误差等,都只能够衡量模型的表现,无法衡量模型的运算速度。回忆一下,我们曾在许多模型中使用空间复杂度和时间复杂度来衡量模型的运算效 率。XGB因此引入了模型复杂度来衡量算法的运算效率。因此XGB的目标函数被写作:传统损失函数 + 模型复杂度。 6、求解XGB的目标函数 在XGB中我们无法使用梯度下降,原因是XGB的损失函数没有需要求解的参数。我们在传统梯度下降中迭代的是参数,而我们在XGB中迭代的是树,树不是数字组成的向量,并且其结构不受到特征矩阵取值大小的直接影响,尽管这个迭代过程可以被类比到梯度下降上,但真实的求解过程却是完全不同。 GBDT和XGB的区别之中,GBDT求一阶导数,XGB求二阶导数,这两个过程根本是不可类比的。XGB在求解极值为目标的求导中也是求解一阶导数
7、参数化决策树:参数alpha,lambda XGB vs GBDT 核心区别2:正则项的存在 在普通的梯度提升树中是不在目标函数中使用正则项的,但XGB借用正则项来修正树模型天生容易过拟合这个缺陷,在剪枝之前让模型能够尽量不过拟合 根据以往的经验,往往认为两种正则化达到的效果是相似的,只不过细节不同。比如在逻辑回归当中,两种正则化都会压缩参数的大小,只不过L1正则化会让为0,而L2正则化不会。在XGB中也是如此。当和越大,惩罚越重,正则项所占的比例就越大,在尽全力最小化目标函数的最优化方向下,叶子节点数量就会被压制,模型的复杂度就越来越低,所以对于天生过拟合的XGB来说,正则化可以一定程度上提升模型效果。 对于两种正则化如何选择的问题,**从XGB的默认参数来看,优先选择的是L2正则化。**当然,如果想尝试L1也不是不可。两种正则项还可以交互,因此这两个参数的使用其实比较复杂。在实际应用中,正则化参数往往不是调参的最优选择,如果真的希望控制模型复杂度,会调整γ而不是调整这两个正则化参数,因此不必过于在意这两个参数最终如何影响了我们的模型效果。对于树模型来说,还是剪枝参数地位更高更优先,只需要理解这两个参数从数学层面上如何影响我们的模型就足够了。如果希望调整往往会使用网格搜索。
#使用网格搜索来查找最佳的参数组合 from sklearn.model_selection import GridSearchCV param = {"reg_alpha":np.arange(0,5,0.05),"reg_lambda":np.arange(0,2,0.05)} gscv = GridSearchCV(reg,param_grid = param,scoring = "neg_mean_squared_error",cv=cv)8、寻找最佳树结构: 贪婪算法求解
9、求解最佳分枝 贪婪算法指的是控制局部最优来达到全局最优的算法,决策树算法本身就是一种使用贪婪算法的方法。XGB作为树的集成模型,自然也想到采用这样的方法来进行计算,所以我们认为,如果每片叶子都是最优,则整体生成的树结构就是最优,如此就可以避免去枚举所有可能的树结构。 决策树中是使用基尼系数或信息熵来衡量分枝之后叶子节点的不纯度,分枝前的信息熵与分治后的信息熵之差叫做信息增益,信息增益最大的特征上的分枝就被我们选中,当信息增益低于某个阈值时,就让树停止生长。在XGB中,使用的方式是类似的:首先使用目标函数来衡量树的结构的优劣,然后让树从深度0开始生长,每进行一次分枝,我们就计算目标函数减少了多少,当目标函数的降低低于我们设定的某个阈值时,就让树停止生长。 在现实中,会对所有特征的所有分枝点进行如上计算,然后选出让目标函数下降最快的节点来进行分枝。对每一棵树的每一层都进行这样的计算,比起原始的梯度下降,实践证明这样的求解最佳树结构的方法运算更快,并且在大型数据下也能够表现不错。
10、让树停止生长:gamma 从目标函数和结构分数之差的式子中来看, γ是我们每增加一片叶子就会被剪去的惩罚项。增加的叶子越多,结构分数Gain之差会被惩罚越重,又被称之为是“复杂性控制”(complexity control),所以是用来防止过拟合的重要参数。实践证明, γ是对梯度提升树影响最大的参数之一,其效果丝毫不逊色于n_estimators和防止过拟合的神器max_depth。同时, 还是我们让树停止生长的重要参数。 在逻辑回归中,我们使用参数来设定阈值,并规定如果梯度下降时损失函数减小量小于下降就会停止。在XGB中,我们规定,只要结构分数之差是大于0的,即只要目标函数还能够继续减小就允许树继续进行分枝。 可以直接通过设定γ的大小来让XGB中的树停止生长,因此被定义为,**在树的叶节点上进行进一步分枝所需的最小目标函数减少量,**在决策树和随机森林中也有类似的参数(min_split_loss,min_samples_split)。设定越大,算法就越保守,树的叶子数量就越少,模型的复杂度就越低。 为了调整γ,需引入XGBoost中新的类sklearn.cv 11、过拟合:剪枝参数 作为天生过拟合的模型,XGBoost应用的核心之一就是减轻过拟合带来的影响。作为树模型,减轻过拟合的方式主要是靠对决策树剪枝来降低模型的复杂度,以求降低方差。用来防止过拟合的参数,包括复杂度控制,正则化的两个参数,控制迭代速度的参数以及管理每次迭代前进行的随机有放回抽样的参数subsample。所有的这些参数都可以用来减轻过拟合。但除此之外,还有几个影响重大的,专用于剪枝的参数: 通常当我们获得了一个数据集后,我们先使用网格搜索找出比较合适的n_estimators和eta组合,然后使用gamma或者max_depth观察模型处于什么样的状态(过拟合还是欠拟合,处于方差-偏差图像的左边还是右边?),最后再决定是否要进行剪枝。通常来说,对于XGB模型,大多数时候都是需要剪枝的。
四、模型的保存与调用 1、pick是比较标准的用于模型保存与调用的库,pickle和open函数的连用
#保存模型 pickle.dump(bst, open("xgboostonboston.dat","wb"))open中我们往往使用w或者r作为读取的模式,但其实w与r只能用于文本文件,当我们希望导入的不是文本文件,而是模型本身的时候,我们使用"wb"和"rb"作为读取的模式。其中wb表示以二进制写入,rb表示以二进制读入
import pickle #导入模型 loaded_model = pickle.load(open("xgboostonboston.dat", "rb")) #做预测 ypreds=loaded_model.predict(dtest)2、使用Joblib保存与调用模型与pickle API非常相似,是Scipy生态系统中的一部分,它为python提供保存和调用管道和对象的功能,处理NumPy结构的数据尤其高效,对于很大的数据集和巨大的模型非常有用。
import joblib #同样可以看看模型被保存到了哪里 joblib.dump(bst,"xgboost-boston.dat") loaded_model = joblib.load("xgboost-boston.dat") ypreds = loaded_model.predict(dtest) MSE(Ytest, ypreds)