XGBOOST

在了解xgboost之前我们先了解一下梯度提升树(gbt)

梯度提升树

梯度提升是构建预测模型的最强大技术之一,它是集成算法中提升法(Boosting)的代表算法。
原理:集成算法通过在数据上构建多个弱评估器,汇集所有弱评估器的建模结果,以获取比单个模型更好的回归或分类表现。
caution:弱评估器被定义为是表现至少比随机猜测更好的模型,即预测准确率不低于50%。
随机森林的中,使用的是一次性建立多个平行独立的弱评估器的装袋法(bagging)。
提升法(boosting)逐一构建弱评估器,经过多次迭代逐渐累积多个弱评估器的方法。
Boosting算法中,学习器之间是存在先后顺序的,同时,每一个样本是有权重的,初始时,每一个样本的权重是相等的。首先,第1个学习器对训练样本进行学习,当学习完成后,增大错误样本的权重,同时减小正确样本的权重,再利用第2个学习器对其进行学习,依次进行下去,最终得到n个学习器,最终,合并这n个学习器的结果.同时,与Bagging中不同的是,每一个学习器的权重也是不一样的。

在梯度提升树中,每构建一个评估器,都让模型更加集中于数据集中容易被判错的那些样本。基于这个有权重的训练集来建模,我们新建的决策树就会更加倾向于这些权重更大的,很容易被判错的样本。随着模型整体不断在被判错的样本上着重学习,这些样本会渐渐被判断正确

gradient boosting

caution:梯度提升回归树来说,每个样本的预测结果可以表示为所有树上的结果的加权求和
XGBoost就是由梯度提升树发展而来的。梯度提升树中可以有回归树也可以有分类树,两者都以CART树算法作为主流,XGBoost背后也是CART树,也就是说都是二叉树

对于XGB来说,每个叶子节点上会有一个预测分数(prediction score),也被称为叶子权重。这个叶子权重就是所有在这个叶子节点上的样本在这一棵树上的回归取值,用 或者 来表示,其中 表示第 棵决策树, 表示样本 对应的特征向量

XGB 和 GBDT 核心区别1:求解预测值 的方式不同

  • GBDT中预测值是由所有弱分类器上的预测结果的加权求和,其中每个样本上的预测结果就是样本所在的叶子节点的均值。
  • XGBT中的预测值是所有弱分类器上的叶子权重直接求和得到,计算叶子权重是一个复杂的过程。

xgb

class xgboost.XGBRegressor (max_depth=3, 
                            learning_rate=0.1,
                            n_estimators=100,
                            silent=True,
                            objective='reg:linear', 
                            booster='gbtree', 
                            n_jobs=1, 
nthread=None, gamma=0, min_child_weight=1, max_delta_step=0,
subsample=1, colsample_bytree=1, colsample_bylevel=1, reg_alpha=0, reg_lambda=1, scale_pos_weight=1,
base_score=0.5, random_state=0, seed=None, missing=None, importance_type='gain', **kwargs)

xgb重要参数n_estimators

随机森林中的n_estimators:n_estimators越大,模型的学习能力就会越强,模型也越容易过拟合。随机森林中,我们调整的第一个参数就是n_estimators,这个参数非常强大,常常能够一次性将模型调整到极限。
xgb虽然集成的方式不同但是,都是建立多个弱评估器使得模型效果得到提高。

from xgboost import XGBRegressor as XGBR
from sklearn.ensemble import RandomForestRegressor as RFR
from sklearn.linear_model import LinearRegression as LinearR
from sklearn.datasets import load_boston
from sklearn.model_selection import KFold, train_test_split, cross_val_score as CVS
from sklearn.metrics import mean_squared_error as MSE
from sklearn.metrics import r2_score
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt

# 导入数据集
data = load_boston()
X = data.data
y = data.target
Xtrain, Xtest, Ytrain, Ytest =  train_test_split(X,y, test_size=.3, random_state=77)

# XGBoost的模型
reg = XGBR(n_estimators=100).fit(Xtrain, Ytrain)
reg.predict(Xtest)

# 我们看看模型的评价标准到底是什么
print('score:', reg.score(Xtest, Ytest))
print('R2:', r2_score(Ytest, reg.predict(Xtest)))
print('MSE', MSE(Ytest, reg.predict(Xtest)))
# 每个特征的重要性
print([*zip(data.feature_names, reg.feature_importances_)])

因为xgbreg是不推荐使用mse,它使用的时R2作为评价标准。


image.png
# 交叉验证对比XGBReg和LinearReg,randomForest
reg = XGBR(n_estimators=100)
CVS(reg, Xtrain, Ytrain, cv=5, scoring='neg_mean_squared_error').mean()

# 使用线性回归进行一个对比
lr = LinearR()
CVS(lr, Xtrain, Ytrain, cv=5, scoring='neg_mean_squared_error').mean()

# 使用随机森林进行对比
rfr = RFR(n_estimators=100) 
CVS(rfr,Xtrain,Ytrain,cv=5,scoring='neg_mean_squared_error').mean()

xgbReg得出的负均分误差为-11.43
LinearReg得出的负均分误差为-25.48
RandomForestReg得出的负均分误差为-11.96

参数silent

在数据巨大,预料到算法进行非常缓慢的时候可以使用这个参数监控模型的训练进度

reg = XGBR(n_estimators=100, silent=False)
CVS(reg, Xtrain, Ytrain, cv=5, scoring='neg_mean_squared_error').mean()
image.png

使用参数学习曲线观察n_estimators对模型的影响

axisx = range(10,500,50)
rs = []
for i in axisx:
    reg = XGBR(n_estimators=i,random_state=420)
    rs.append(CVS(reg,Xtrain,Ytrain,cv=cv).mean())
print(axisx[rs.index(max(rs))],max(rs))
plt.figure(figsize=(20,5))
plt.plot(axisx,rs,c="red",label="XGB")
plt.legend()
plt.show()
n_estimators学习曲线

可见在大约40~70的地方就明显提升很小了

顺带一个知识,方差与泛化误差

我们之前选择最佳的模型是模型泛化误差比较小的情况下选择的参数,那是因为模型极度不稳定,方差很大的情况其实比较少见。但如果我们的数据量非常少,模型会相对不稳定,因此我们应当将方差也纳入考虑的范围。所以我们在交叉验证的时候应该考虑方差和泛化误差。

n_estimators summary

XGB中的树的数量决定了模型的学习能力,树的数量越多,模型的学习能力越强。只要XGB中树的数量足够了,即便只有很少的数据, 模型也能够学到训练数据100%的信息,XGB天生过拟合的模型。过拟合情况下,模型会变得非常不稳定。
XGB中树的数量很少的时候,对模型的影响较大,当树的数量已经很多的时候,对模型的影响比较小,只能有微弱的变化。当数据本身就处于过拟合的时候,再使用过多的树能达到的效果甚微,反而浪费计算资源。当唯一指标或者准确率给出的n_estimators看起来不太可靠的时候,我们可以改造学习曲线来帮助我们。
树的数量提升对模型的影响有极限,最开始,模型的表现会随着XGB的树的数量一起提升,但到达某个点之后,树的数量越多,模型的效果会逐步下降,这也说明了暴力增加n_estimators不一定有效果
这些都和随机森林中的参数n_estimators表现出一致。在随机森林中我们总是先调整n_estimators,当n_estimators的极限已达到,我们才考虑其他参数,但XGB中的状况明显更加复杂,当数据集不太寻常的时候会更加复杂。这是我们要给出的第一个超参数,因此还是建议优先调整n_estimators,一般都不会建议一个太大的数目,300以下为佳。

有放回随机抽样:重要参数subsample

控制我们随机抽样,控制抽样抽出来的样本量大概是多少!
默认是1,代表一次抽取百分百的数据,那么0.1则代表一次抽取百分之十的数据。
由于对模型来说,数据量越少模型学习越容易,学到的规则也会越具体,所以subsample参数通常是在样本量本身很大的时候来调整和使用

迭代决策树: 重要参数eta(learning_rate)

除了保证模型倾向于困难样本的方向,我们还必须控制新弱分类器的生成,我们必须保证,每次新添加的树一定得是对这个新数据集预测效果最优的那一棵树。
eta是迭代决策树的步长,又叫学习率。和逻辑回归的阿尔法类似,eta越大迭代速度越快,算法的极限很快就达到了,有可能无法收敛到最佳,eta越小,越有可能找到更精确的最佳值,更多空间被留给后面建立的树,但是迭代速度可能比较慢。这个可以用逻辑回归里的步长去理解。

选择弱评估器:重要参数booster

梯度提升算法中不只有梯度提升树,XGB作为梯度提升算法的进化,自然也不只有树模型一种弱评估器。在XGB中,除了树模型,我们还可以选用线性模型,比如线性回归,来进行集成。
虽然主流的XGB依然是树模型,但我们也可以使用其他的模型。
xgb

booster 评估器
gbtree 梯度提升树
gblinear 线性模型。
dart 抛弃提升树,在建树的过程中会抛弃一部分树,比梯度提升树有更好的防过拟合功能
for booster in ['gbtree', 'gblinear', 'dart']:
    reg = XGBR(n_estimators=100, learning_rate=0.1, random_state=1, booster=booster, scoring='neg_mean_squared_error')
    reg = reg.fit(Xtrain, Ytrain)
    print(booster, f"score: {reg.score(Xtest, Ytest)}")

XGB的目标函数:重要参数objective

梯度提升算法中都存在着损失函数。集成算法中的损失函数是
可选的,要选用什么损失函数取决于我们希望解决什么问题,以及希望使用怎样的模型。
如果我们的目标是进行回归预测,那我们可以选择调节后的均方误差RMSE作为我们的损失函数。
如果我们是进行分类预测,那我们可以选择错误率error或者对数损失log_loss。只要我们选出的函数是一个可微的,能够代表某种损失的函数,它就可以是我们XGB中的损失函数。
XGB是实现了模型表现和运算速度的平衡的算法。普通的损失函数,比如错误率,均方误差等,都只能够衡量模型的表现,无法衡量模型的运算速度.XGB引入了模型复杂度来衡量算法的运算效率。因此XGB的目标函数被写作:传统损失函数 + 模型复杂度

输入 选用的损失函数
reg:linear 使用线性回归的损失函数,均方误差,回归时使用
binary:logistic 使用逻辑回归的损失函数,对数损失log_loss,二分类时使用
binary:hinge 使用支持向量机的损失函数,Hinge Loss,二分类时使用
multi:softmax 使用softmax损失函数,多分类时使用

参数化决策树 :参数alpha,lambda

class xgboost.XGBRegressor (max_depth=3, learning_rate=0.1, n_estimators=100, silent=True,
objective='reg:linear', booster='gbtree', n_jobs=1, nthread=None, gamma=0, min_child_weight=1,
max_delta_step=0, subsample=1, colsample_bytree=1, colsample_bylevel=1, reg_alpha=0, reg_lambda=1,scale_pos_weight=1, base_score=0.5, random_state=0, seed=None, missing=None, importance_type='gain',
s**kwargs)*

image.png

在XGB中。当 alpha和 lambda越大,惩罚越重,正则项所占的比例就越大,在尽全力最小化目标函数的最优化方向下,叶子节点数量就会被压制,模型的复杂度就越来越低,所以对于天生过拟合的XGB来说,正则化可以一定程度上提升模型效果.

对于树模型来说,还是剪枝参数地位更高更优先
调整 正则项 ,我们往往会使用网格搜索来帮助我们
XGB vs GBDT 核心区别2:正则项的存在
在普通的梯度提升树GBDT中,我们是不在目标函数中使用正则项的。但XGB借用正则项来修正树模型天生容易
过拟合这个缺陷,在剪枝之前让模型能够尽量不过拟合

让树停止生长:重要参数gamma

gamma是我们每增加一片叶子就会被剪去的惩罚项。增加的叶子越多,结构分数之差 会被惩罚越重,所以 gamma又被称之为是“复杂性控制”,是我们用来防止过拟合的重要参数
gamma是对梯度提升树影响最大的参数之一,其效果丝毫不逊色于n_estimators和防止过拟合的神器max_depth。同时, 还是我们让树停止生长的重要参数

在XGB中,我们规定,只要结构分数之差 是大于0的,即只要目标函数还能够继续减小,我们就允许树继续进行分枝.

通过设定 的大小来让XGB中的树停止生长。 因此被定义为,在树的叶节点上进行进一步分枝所需的最小目标函数减少量,这很像在决策树和随机森林中的参数(min_split_loss,min_samples_split)。 设定越大,算法就越保守,树的叶子数量就越少,模型的复杂度就越低

过拟合:剪枝参数与回归模型调参

参数含义 xgb.XGBRegressor()
树的最大深度 max_depth,默认6
每次生成树时随机抽样特征的比例 colsample_bytree,默认1
每次生成树的一层时随机抽样特征的比例 colsample_bylevel,默认1
每次生成一个叶子节点时随机抽样特征的比例 colsample_bynode,默认1 N.A.
一个叶子节点上所需要的最小即叶子节点上的二阶导数之和类似于样本权重 min_child_weight,默认1

通常当我们获得了一个数据集后,我们先使用网格搜索找出比较合适的n_estimators和eta组合,然后使用gamma或者max_depth观察模型处于什么样的状态(过拟合还是欠拟合,处于方差-偏差图像的左边还是右边?),最后再决定是否要进行剪枝。通常来说,对于XGB模型,大多数时候都是需要剪枝的。

使用网格搜索调参

使用网格搜索的时候,最好不要一次性将所有的参数都放入进行搜索,最多一次两三个。有一些互相影响的参数需要放在一起使用,比如学习率eta和树的数量n_estimators

建议调参顺序是
n_estimators与eta共同调节
gamma或者max_depth
采样和抽样参数(纵向抽样影响更大)
正则化

你可能感兴趣的:(XGBOOST)