5.5 集成学习- XGBoost

发布时间 2023-07-17 17:05:22作者: 哎呦哎(iui)

1 XGBoost的基础思想与实现

1.1 XGBoost pk 梯度提升树

极限提升树XGBoost(Extreme Gradient Boosting,XGB,发音/æks-g-boost/)是基于梯度提升树GBDT全面升级的新一代提升算法,也是提升家族中最富盛名、最灵活、最被机器学习竞赛所青睐的算法。不同于我们之前学过的任意单一算法,XGBoost是一个以提升树为核心的算法系统,它覆盖了至少3+建树流程、10+损失函数,可以实现各种类型的梯度提升树,它可以实现梯度提升树,可以实现基于提升树的随机森林,可以实现提升算法的逻辑回归、线性回归,灵活性无与伦比。同时,XGBoost天生被设计成支持巨量数据,因此可以自由接入GPU/分布式/数据库等系统、还创新了众多工程上对传统提升算法进行加速的新方法。可以说,XGBoost是21世纪中Boosting算法的又一个里程碑,它开创了后GBDT时代中Boosting算法的新辉煌。

需要注意的是,学习XGBoost需要大量梯度提升树(GBDT)相关知识,本课程将假设你已经非常熟悉梯度提升树的原理与特点、并且熟悉sklearn中的交叉验证的用法。如果你不熟悉梯度提升树,强烈建议你回顾之前的课程。

作为Boosting算法,XGBoost中自然包含Boosting三要素:

  • 损失函数\(L(y,\hat{y})\) :用以衡量模型预测结果与真实结果的差异。
  • 弱评估器\(f(x)\) :(一般为)决策树,不同的boosting算法使用不同的建树过程。
  • 综合集成结果\(H(x)\):即集成算法具体如何输出集成结果

并且,XGBoost也遵循Boosting算法的基本流程进行建模:


依据上一个弱评估器\(f(x)_{k-1}\)的结果,计算损失函数\(L\)

并使用\(L\)自适应地影响下一个弱评估器\(f(x)_k\)的构建。
集成模型输出的结果,受到整体所有弱评估器\(f(x)_0\) ~ \(f(x)_K\)的影响。

当然,XGBoost真实的流程比上述过程复杂得多。虽然梯度提升树的流程本身已经比较复杂,XGBoost还是在此流程上做出了众多关键的改进。综合来看,这些改进都是基于XGBoost中两种非常关键的思想实现的:

  • 第一,实现精确性与复杂度之间的平衡

树的集成模型是机器学习中最为强大的学习器之一,这一族学习器的特点是精确性好、适用于各种场景,但运行缓慢、且过拟合风险很高,因此从学习单一决策树时起,我们就持续为大家提供丰富的剪枝策略,目的就是为了降低各种树模型的模型复杂度,从而控制住过拟合。树模型的学习能力与过拟合风险之间的平衡,就是预测精确性与模型复杂度之间的平衡,也是经验风险与结构风险之间的平衡,这一平衡对决策树以及树的集成模型来说是永恒的议题。

在过去,我们总是先建立效果优异的模型,再依赖于手动剪枝来调节树模型的复杂度,但在XGBoost中,精确性与复杂度会在训练的每一步被考虑到。主要体现在:

  • 1. XGBoost为损失函数\(L(y,\hat{y})\)加入结构风险项,构成目标函数\(O(y,\hat{y})\)


    在AdaBoost与GBDT当中,我们的目标是找到损失函数\(L(y,\hat{y})\)的最小值,也就是让预测结果与真实结果差异最小,这一流程只关心精确性、不关心复杂度和过拟合情况。为应对这个问题,XGBoost从决策树的预剪枝流程、逻辑回归、岭回归、Lasso等经典算法的抗过拟合流程吸取经验,在损失函数中加入了控制过拟合的结构风险项,并将【\(L(y,\hat{y})\) + 结构风险】定义为目标函数\(O(y,\hat{y})\)


    这一变化让XGBoost在许多方面都与其他Boosting算法不同:例如,XGBoost是向着令目标函数最小化的目标进行训练,而不是令损失函数最小化的方向。再比如,XGBoost会优先利用结构风险中的参数来控制过拟合,而不像其他树的集成模型一样依赖于树结构参数(例如max_depthmin_impurity_decrease等)。

  • 2. 使用全新不纯度衡量指标,将复杂度纳入分枝规则


    在之前学过的算法当中,无论Boosting流程如何进化,建立单棵决策树的规则基本都遵循我们曾经学过的CART树流程,在分类树中,我们使用信息增益(information gain)来衡量叶子的质量,在回归树中,我们使用MSE或者弗里德曼MSE来衡量叶子的质量。这一流程有成熟的剪枝机制、预测精度高、能够适应各种场景,但却可能建立复杂度很高的树。


    为实现精确性与复杂度之间的平衡,XGBoost重新设定了分枝指标【结构分数】(原论文中写作Structure Score,也被称为质量分数Quality Score),以及基于结构分数的【结构分数增益】(Gain of structure score),结构分数增益可以逼迫决策树向整体结构更简单的方向生长。


    这一变化让XGBoost使用与传统CART略有区别的建树流程,同时在建树过程中大量使用残差(Residuals)或类残差对象作为中间变量,因此XGBoost的数学过程比其他Boosting算法更复杂。
  • 第二,极大程度地降低模型复杂度、提升模型运行效率,将算法武装成更加适合于大数据的算法

在任意决策树的建树过程中,都需要对每一个特征上所有潜在的分枝节点进行不纯度计算,当数据量巨大时,这一计算将消耗巨量的时间,因此树集成模型的关键缺点之一就是计算缓慢,而这一缺点在实际工业环境当中是相当致命的。为了提升树模型的运算速度、同时又不极大地伤害模型的精确性,XGBoost使用多种优化技巧来实现效率提升:

  • 1. 使用估计贪婪算法、平行学习、分位数草图算法等方法构建了适用于大数据的全新建树流程

  • 2. 使用感知缓存访问技术与核外计算技术,提升算法在硬件上的运算性能

  • 3. 引入Dropout技术,为整体建树流程增加更多随机性、让算法适应更大数据


    不仅在数学方法上有所改进,XGBoost正式拉开了Boosting算法工程优化的序幕。后续更多的Boosting算法,包括LightGBM,CatBoost等也都是在工程方法上做出了大量的优化。遗憾的是,XGBoost的平行学习、估计贪婪算法等知识点将不会被包括在本次课程当中。在讲解LightGBM的时候,我们将详解基于直方图的估计算法,那时我们就能够很容易地理解XGBoost所使用的估计贪婪算法了。

除此之外,XGBoost还保留了部分与梯度提升树类似的属性,包括:

  • 弱评估器的输出类型与集成算法输出类型不一致

对于AdaBoost或随机森林算法来说,当集成算法执行的是回归任务时,弱评估器也是回归器,当集成算法执行分类任务时,弱评估器也是分类器。但对于GBDT以及基于GBDT的复杂Boosting算法们而言,无论集成算法整体在执行回归/分类/排序任务,弱评估器一定是回归器。GBDT通过sigmoid或softmax函数输出具体的分类结果,但实际弱评估器一定是回归器,XGBoost也是如此。

  • 拟合负梯度,且当损失函数是0.5倍MSE时,拟合残差

任意Boosting算法都有自适应调整弱评估器的步骤。在GBDT当中,每次用于建立弱评估器的是样本\(X\)以及当下集成输出\(H(x_i)\)与真实标签\(y\)之间的伪残差(也就是负梯度)。当损失函数是\(\frac{1}{2}MSE\)时,负梯度在数学上等同于残差(Residual),因此GBDT是通过拟合残差来影响后续弱评估器结构。XGBoost也是依赖于拟合残差来影响后续弱评估器结构,但是与GBDT一样,这一点需要通过数学来证明。

  • 抽样思想

GBDT借鉴了大量Bagging算法中的抽样思想,XGBoost也继承了这一属性,因此在XGBoost当中,我们也可以对样本和特征进行抽样来增大弱评估器之间的独立性

因为存在这些相似之处,因此我们将会在XGBoost的参数中看到部分熟悉的参数,如果你对梯度提升树足够熟悉,那XGBoost的许多参数对你来说应该并不难懂。需要注意的是,作为2014年才被正式提出的Boosting算法,XGBoost是一个独立于经典算法的算法系统,因此xgboost库是需要单独安装的。

你可以使用以下代码在cmd中非常简单地安装xgboost,通常来说无需配置环境变量。

#!pip install xgboost #安装xgboost库
#!pip install --upgrade xgboost #更新xgboost库
import xgboost as xgb #导入成功则说明安装正确
xgb.__version__

image
需要注意的是,windows与linux系统下支持单GPU运算,但Mac系统不支持GPU运算。同时,只有Linux系统支持多GPU联合运算,其他系统不支持。如果pip安装失败,则可以删除后参考该页面进行具体安装:https://xgboost.readthedocs.io/en/stable/install.html

2 XGBoost回归的sklearnAPI实现

其实sklearn中有他的一套建模流程的,像fit等,然后这个XGBootst也有它的一套建模流程。
不同于内嵌在sklearn框架中的其他算法,xgboost是独立的算法库,因此它有一套不同于sklearn代码的原生代码。大部分时候我们使用原生代码来运行xgboost,因为这套原生代码是完全为集成学习所设计的,不仅可以无缝使用交叉验证、默认输出指标为RMSE,还能够默认输出训练集上的结果帮我们监控模型。然而对于熟悉sklearn的我们来说,这一套代码略有难度,因此许多人也会倾向于使用xgboost自带的sklearn接口来实现算法。

XGBoost自带sklearn接口(sklearn API),通过这个接口,我们可以使用跟sklearn代码一样的方式来实现xgboost,即可以通过fit和predict等接口来执行训练预测过程,也可以调用属性比如coef_等。在XGBoost的sklearn API中,我们可以看到下面五个类:

说明
XGBRegressor() 实现xgboost回归
XGBClassifier() 实现xgboost分类
XGBRanker() 实现xgboost排序
XGBRFClassifier() 基于xgboost库实现随机森林分类
XGBRFRegressor() 基于xgboost库实现随机森林回归

其中XGBRF的两个类是以XGBoost方式建树、但以bagging方式构建森林的类,通常只有在我们使用普通随机森林效果不佳、但又不希望使用Boosting的时候使用。这种使用XGBoost方式建树的森林在sklearn中已经开始了实验,不过还没有正式上线。

另外两个类就很容易理解了,一个是XGBoost的回归,一个是XGBoost的分类。这两个类的参数高度相似,我们可以以XGBoost回归为例查看:

class xgboost.XGBRegressor(n_estimators, max_depth, learning_rate, verbosity, objective, booster, tree_method, n_jobs, gamma, min_child_weight, max_delta_step, subsample, colsample_bytree, colsample_bylevel, colsample_bynode, reg_alpha, reg_lambda, scale_pos_weight, base_score, random_state, missing, num_parallel_tree, monotone_constraints, interaction_constraints, importance_type, gpu_id, validate_parameters, predictor, enable_categorical, eval_metric, early_stopping_rounds, callbacks,**kwargs)

class xgboost.XGBClassifier(n_estimators, use_label_encoder, max_depth, learning_rate, verbosity, objective, booster, tree_method, n_jobs, gamma, min_child_weight, max_delta_step, subsample, colsample_bytree, colsample_bylevel, colsample_bynode, reg_alpha, reg_lambda, scale_pos_weight, base_score, random_state, missing, num_parallel_tree, monotone_constraints, interaction_constraints, importance_type, gpu_id, validate_parameters, predictor, enable_categorical, **kwargs)

然后这些参数可以参考官网

可以看到,两个类的参数两都很多,其中不乏一些我们非常熟悉的参数,例如n_estimatorslearning_rate, max_depth等。但大部分参数还是需要我们重新学习和认识,这与xgboost复杂的原理有很大的关系,但由于是sklearn API,所以所有这些参数都有相应的默认值。我们可以在不认识参数的情况下调用这个类。以回归类为例我们来看:

from xgboost import XGBRegressor
from sklearn.model_selection import cross_validate, KFold
from sklearn.model_selection import train_test_split
data = pd.read_csv(r"D:\Pythonwork\2021ML\PART 2 Ensembles\datasets\House Price\train_encode.csv",index_col=0)

data.head()

image

#回归数据
X = data.iloc[:,:-1]
y = data.iloc[:,-1]

X.shape

y.describe()

image
在这个数据集上我们曾经达到过如下的分数:

算法 RF AdaBoost GBDT RF
(TPE)
AdaBoost
(TPE)
GBDT
(TPE)
5折验证
运行时间
1.29s 0.28s 0.49s 0.22s 0.27s 1.54s(↑)
测试最优分数
(RMSE)
30571.267 35345.931 28783.954 28346.673 35169.730 26415.835(↓)
然后是skrlean中的代码三部曲:
#sklearn普通训练代码三步走:实例化,fit,score

Xtrain,Xtest,Ytrain,Ytest = train_test_split(X,y,test_size=0.3,random_state=1412)

xgb_sk = XGBRegressor(random_state=1412) #实例化模型
xgb_sk.fit(Xtrain,Ytrain)
xgb_sk.score(Xtest,Ytest) #默认指标R2

#0.8707175563742298

image
交叉验证三步走:

#sklearn交叉验证三步走:实例化,交叉验证,对结果求平均

xgb_sk = XGBRegressor(random_state=1412) #实例化模型
#定义所需的交叉验证方式
cv = KFold(n_splits=5,shuffle=True,random_state=1412)

result_xgb_sk = cross_validate(xgb_sk,X,y,cv=cv
                               ,scoring="neg_root_mean_squared_error" #负根均方误差
                               ,return_train_score=True
                               ,verbose=True
                               ,n_jobs=-1)

image
然后用这个result_xgb_sk可以看训练过程

result_xgb_sk

image

def RMSE(result,name):
    return abs(result[name].mean())

RMSE(result_xgb_sk,"train_score")
#940.7718003131752

RMSE(result_xgb_sk,"test_score")
#29753.814742669765

image
可以看到,在默认参数下,xgboost模型极度不稳定,并且过拟合的情况非常严重,在训练集上的RMSE达到了前所未有的低点940.77,这说明XGBoost的学习能力的确强劲,现有数据量对xgboost来说可能有点不足。在没有调整任何参数的情况下,XGBoost的表现没能胜过梯度提升树,这可能是因为在默认参数下梯度提升树的过拟合程度较轻。我们可以尝试使用之前学过的知识,对XGBoost的参数略微进行调整,例如将最可能影响模型的参数之一:max_depth设置为一个较小的值。

xgb_sk = XGBRegressor(max_depth=5,random_state=1412) #实例化

result_xgb_sk = cross_validate(xgb_sk,X,y,cv=cv
                               ,scoring="neg_root_mean_squared_error" #负根均方误差
                               ,return_train_score=True
                               ,verbose=True
                               ,n_jobs=-1)

RMSE(result_xgb_sk,"train_score")

RMSE(result_xgb_sk,"test_score")

image
过拟合程度立刻减轻了,这说明模型是有潜力的,经过精密的调参之后xgboost上应该能够获得不错的结果。

当sklearn API训练完毕之后,我们可以调用sklearn中常见的部分属性对训练后的模型进行查看,例如查看特征重要性的属性feature_importances_,以及查看XGB下每一棵树的get_booster()方法、查看总共有多少棵树的get_num_boosting_rounds()方法、以及查看当前所有参数的方法get_params

xgb_sk = XGBRegressor(max_depth=5,random_state=1412).fit(X,y)

#查看特征重要性
xgb_sk.feature_importances_

#调出其中一棵树,不过无法展示出树的细节,只能够调出建树的Booster对象
xgb_sk.get_booster()[2]

image
一棵树都是一个单独的Booster提升树,Booster就相当于sklearn中DecisionTreeRegressor,只不过是使用xgboost独有的建树规则进行计算。

#查看一共建立了多少棵树,相当于是n_estimators的取值
xgb_sk.get_num_boosting_rounds()

#获取每一个参数的取值
xgb_sk.get_params()

{'objective': 'reg:squarederror',
'base_score': 0.5,
'booster': 'gbtree',
'colsample_bylevel': 1,
'colsample_bynode': 1,
'colsample_bytree': 1,
'enable_categorical': False,
'gamma': 0,
'gpu_id': -1,
'importance_type': None,
'interaction_constraints': '',
'learning_rate': 0.300000012,
'max_delta_step': 0,
'max_depth': 5,
'min_child_weight': 1,
'missing': nan,
'monotone_constraints': '()',
'n_estimators': 100,
'n_jobs': 16,
'num_parallel_tree': 1,
'predictor': 'auto',
'random_state': 1412,
'reg_alpha': 0,
'reg_lambda': 1,
'scale_pos_weight': 1,
'subsample': 1,
'tree_method': 'exact',
'validate_parameters': 1,
'verbosity': None}
image
查看参数对xgboost来说很有意义,因为XGBRegressor的说明中没有注明默认参数,因此通过查看参数,我们可以了解到xgboost在sklearn API中都设置了怎样的参数,作为未来调参的参考。对于xgboost分类器,我们还可以调用predict_proba这样的方法来输出概率值,除此之外我们一般不会再用到xgboost sklearn API中的其他功能。

3 XGBoost回归的原生代码实现

XGBoost的原生代码与我们已经习惯了的sklearn代码有很大的不同。首先,原生代码必须使用XGBoost自定义的数据结构DMatrix,这一数据结构能够保证xgboost算法运行更快,并且能够自然迁移到GPU上运行,类似于列表、数组、Dataframe等结构都不能用于原生代码,因此使用原生代码的第一步就是要更换数据结构。

当设置好数据结构后,我们需要以字典形式设置参数。XGBoost也可以接受像sklearn一样,将所有参数都写在训练所用的类当中,然而由于xgboost的参数列表过长、参数类型过多,直接将所有参数混写在训练模型的类中会显得代码冗长且混乱,因此我们往往会使用字典单独呈现参数。准备好参数列表后,我们将使用xgboost中自带的方法xgb.trainxgb.cv进行训练,train是正常的验证,cv就是交叉验证,训练完毕后,我们再train之后不能得到结果,只可以使用predict方法对结果进行预测,cv就没有这个烦恼了。虽然xgboost原生代码库所使用的数据结构是DMatrix,但在预测试输出的数据结构却是普通的数组,因此可以直接使用sklearn中的评估指标,或者python编写的评估指标进行评估。接下来,我们来认识一下xgboost原生代码中最关键的方法:

*class* `xgboost.DMatrix`(data, label=None, *, weight=None, base_margin=None, missing=None, silent=False, feature_names=None, feature_types=None, nthread=None, group=None, qid=None, label_lower_bound=None, label_upper_bound=None, feature_weights=None, enable_categorical=False)

*function* `xgboost.train`(*params, dtrain, num_boost_round=10, *, evals=None, obj=None, feval=None, maximize=None, early_stopping_rounds=None, evals_result=None, verbose_eval=True, xgb_model=None, callbacks=None, custom_metric=None)

*function* `xgboost.cv`(*params, dtrain, num_boost_round=10, nfold=3, stratified=False, folds=None, metrics=(), obj=None, feval=None, maximize=None, early_stopping_rounds=None, fpreproc=None, as_pandas=True, verbose_eval=None, show_stdv=True, seed=0, callbacks=None, shuffle=True, custom_metric=None)

其中,方法xgb.trainxgb.cv的第一个参数params就是我们需要使用字典自定义的参数列表,第二个参数dtrain就是DMatrix结构的训练数据,这里注意这个dtrain是不分训练数据和标签的,都打包成dtrian,第三个参数num_boost_round其实就等同于sklearn中的n_estimators,表示总共建立多少棵提升树,也就是提升过程中的迭代次数。

在之后的课程中,我们将会详细讲解训练中涉及到的每一个参数,在这里我们了解前三个参数就可以。和sklearn中一样,xgboost中的这些参数也都拥有默认值,因此我们可以不填写任何参数就运行xgboost算法。现在,我们来简单看看原生代码是如何实现的:

import xgboost as xgb
  • 将数据转换为DMatrix

XGBoost模块的三步走:将数据转换为DMatrix,定义需要输入的参数params,直接调用训练。

3.1 第一步,先转换数据格式:

X.head() #DataFrame

image

data_xgb = xgb.DMatrix(X,y)

data_xgb

type(data_xgb)

image
如上所示,DMatrix会将特征矩阵与标签打包在同一个对象中,且一次只能转换一组数据。并且,我们无法通过索引或循环查看内部的内容,一旦数据被转换为DMatrix,就难以调用或修改了:
image
因此,数据预处理需要在转换为DMatrix之前做好。如果我们有划分训练集和测试集,则需要分别将训练集和测试集转换为DMatrix:

#如果有分割训练集和测试集
from sklearn.model_selection import train_test_split
Xtrain,Xtest,Ytrain,Ytest = train_test_split(X,y,test_size=0.3,random_state=1412)
dtrain = xgb.DMatrix(Xtrain,Ytrain)
dtest = xgb.DMatrix(Xtest,Ytest)

3.2 定义所需要输出的参数,直接进行训练

params={'booster':'gbtree',
	    'nthread':12,
	    'objective':          'rank:pairwise',
	    'eval_metric':'auc',
	    'seed':0,
	    'eta': 0.01,
	    'gamma':0.1,
	    'min_child_weight':1.1,
	    'max_depth':5,
	    'lambda':10,
	    'subsample':0.7,
	    'colsample_bytree':0.7,
	    'colsample_bylevel':0.7
	    'tree_method':'exact'
	    }

下面先来介绍一下各个参数的含义:

1、通用参数

1.1. booster【默认gbtree】

xgboost有两种booster可以选择:

gblinear:线性模型; gbtree:基于树的模型。其中的linear很少用到。

1.2. nthread【默认值为最大可能的线程数】:输入系统的核数

2、学习目标参数

2.1. objective[默认reg:linear]

这个参数定义需要被最小化的损失函数(一般二分类问题就用“binary:logistic”和“rank:pairwise”)。最常用的值有(可自定义):

binary:logistic 二分类的逻辑回归,返回预测的概率(不是类别)。

multi:softmax 使用softmax的多分类器,返回预测的类别(不是概率)。在这种情况下,你还需要多设一个参数:num_class(类别数目)。

multi:softprob 和multi:softmax参数一样,但是返回的是每个数据属于各个类别的概率。

2.2. eval_metric[默认值取决于objective参数的取值]

对于回归问题,默认值是rmse,对于分类问题,默认值是error。

可选值有:rmse、mae、logloss、error、merror、mlogloss、auc

2.3. seed(默认0):随机数的种子,用于复现随机数据的结果,也可以用于调整参数。

3、booster参数

3.1. eta[默认0.3]:和learning rate类似,通过减小每一步的权重,可以提高模型的鲁棒性。

3.2. gamma[默认0]:这个参数的值越大,算法越保守。这个参数的值和损失函数息息相关。

3.3. min_child_weight[默认1]:最小样本权重的和;这个参数用于避免过拟合,当它的值较大时,可以避免模型学习到局部的特殊样本。但是如果这个值过高,会导致欠拟合。这个参数需要使用CV来调整。

3.4. max_depth[默认6]:这个值为树的最大深度,也是用来避免过拟合的。max_depth越大,模型会学到更具体更局部的样本,需要使用CV函数来进行调优。

3.5. lambda[默认1]:这个参数是用来控制XGBoost的正则化部分的。在减少过拟合上可挖掘更多用处。

3.6. subsample[默认1]:这个参数控制对于每棵树,随机采样的比例。减小这个参数的值,可以避免过拟合。但如果设置得过小,可能会导致欠拟合。

3.7. colsample_bytree[默认1]:用来控制每棵随机采样的列数的占比(每一列是一个特征)。

3.8. colsample_bylevel[默认1]:用来控制树的每一级的每一次分裂,对列数的采样的占比。

3.9. tree_method[默认为近似]:要使用精确的贪婪算法,需要将tree_method设置为“exact”

3.10. num_boost_round:迭代次数,也就是树的个数

3.11. evals:形式是evals = [(dtrain,’train’),(dval,’val’)]或者是evals = [(dtrain,’train’)],对于第一种情况,它使得我们可以在训练过程中观察验证集的效果。

这里先写两个熟悉的函数进行训练:

params = {"max_depth":5,"seed":1412}

reg = xgb.train(params, data_xgb, num_boost_round=100)

不难发现,XGBoost不需要实例化,xgb.train函数包揽了实例化和训练的功能,一行代码解决所有问题。同时,XGBoost在训练时没有区分回归和分类器,它默认是执行回归算法,因此当我们执行回归任务时,代码是最为简单的。

在运行完xgb.train后,我们就已经训练完毕后,训练到的reg可以直接用于预测:

3.3 预测

y_pred = reg.predict(data_xgb)

y_pred

image
我们可以使用sklearn中的评估指标进行评估,对回归类算法,xgboost的默认评估指标是RMSE

from sklearn.metrics import mean_squared_error as MSE
MSE(y,y_pred,squared=False) #RMSE

image
前面说过有两种训练方式一种.train,一种交叉验证cv

params = {"max_depth":5,"seed":1412}
result = xgb.cv(params,data_xgb,num_boost_round=100
                ,nfold=5 #补充交叉验证中所需的参数,nfold=5表示5折交叉验证
                ,seed=1412 #交叉验证的随机数种子,params中的是管理boosting过程的随机数种子
               )

result

image
如上所示,result返回了一个100行,4列的矩阵,格式为DataFrame。

该矩阵行数与迭代次数一致,当我们规定迭代次数为100时,这个矩阵就有100行,如果我们规定的迭代次数为10,这个矩阵就只会有10行。每一行代表了每次迭代后进行交叉验证的结果的均值,例如索引为0的行就表示迭代了一次时(刚建立第一棵树时),进行5折交叉验证的结果,最后一行的结果也就是当前模型迭代完毕后(建好了全部的nun_boost_round棵树时)输出的结果,也是之前我们使用sklearn API时得到过的结果:测试集上5折交叉验证结果28623.22。

每次迭代后xgboost会执行5折交叉验证,并收集交叉验证上的训练集RMSE均值、训练集RMSE的标准差、测试集RMSE的均值、测试集RMSE的标准差,这些数据构成了4列数据。实际上,这个矩阵展示了每次迭代过后,进行5折交叉验证的结果,也展示出了随着迭代次数增多,模型表现变化的趋势,因此输出结果可以被用于绘制图像。

plt.figure(dpi=300)
plt.plot(result["train-rmse-mean"])
plt.plot(result["test-rmse-mean"])
plt.legend(["train","test"])
plt.title("xgboost 5fold cv");

image

4 XGBoost实现分类

from xgboost import XGBClassifier

这里我们用手写字体识别那个数据集

from sklearn.datasets import load_digits
from sklearn.model_selection import train_test_split
data = load_digits()
X = data.data
y = data.target
print(X.shape,y.shape)

定义参数,这里我们

data_xgb = xgb.DMatrix(X,y)

image

定义参数,注意这里如果是多分类的话要加一个'num_class':10 参数

'''
objective:
“reg:linear” 线性回归.
“reg:logistic" 逻辑回归.
“binary:logistic” 二分类的逻辑回归问题,输出为概率.
“binary:logitraw” 二分类的逻辑回归问题,输出的为wTx.
“count:poisson” 计数问题的poisson回归,输出结果为poisson分布.max_delta_step默认为0.7.(used to safeguard optimization)
“multi:softmax” softmax处理多分类问题,同时需要设置参数num_class(类别个数).
“multi:softprob” 输出各个分类概率,ndata*nclass向量,表示样本所属于每个类别的概率.
“rank:pairwise” set XGBoost to do ranking task by minimizing the pairwise loss.
'''
params = {'learning_rate':0.1
         ,'max_depth':5
         ,'objective':'multi:softmax'
         # ,'objective':'multi:softprob'
         ,'num_class':10 # 10分类
         ,'random_state':1412
         , 'eta':0.8 # boosting算法中的学学习率
         }

.train

model = xgb.train(params, data_xgb, num_boost_round=10)
y_pred = model.predict(data_xgb)

image

这里我们用sklearn中的accuracy_score来判断其正确率

from sklearn.metrics import accuracy_score

accuracy_score(y_pred, y)

image