在上一篇Boosting方法的介绍中,对XGBoost有过简单的介绍。为了更还的掌握XGBoost这个工具。我们再来对它进行更加深入细致的学习。
XGBoost 所应用的算法就是 gradient boosting decision tree,既可以用于分类也可以用于回归问题中。那什么是 Gradient Boosting?Gradient boosting 是 boosting 的其中一种方法。所谓 Boosting ,就是将弱分离器 f_i(x) 组合起来形成强分类器 F(x) 的一种方法。所以 Boosting 有三个要素:
Gradient boosting 就是通过加入新的弱学习器,来努力纠正前面所有弱学习器的残差,最终这样多个学习器相加在一起用来进行最终预测,准确率就会比单独的一个要高。之所以称为 Gradient,是因为在添加新模型时使用了梯度下降算法来最小化的损失。一般来说,gradient boosting 的实现是比较慢的,因为每次都要先构造出一个树并添加到整个模型序列中。而 XGBoost 的特点就是计算速度快,模型表现好,这两点也正是这个项目的目标。
XGBoost算法可以给预测模型带来能力的提升。当我对它的表现有更多了解的时候,当我对它的高准确率背后的原理有更多了解的时候,你会发现它具有很多优势:
XGBoost是在GBDT的基础上对boosting算法进行的改进,内部决策树使用的是回归树,简单回顾GBDT如下:
回归树的分裂结点:
对于平方损失函数,拟合的就是残差;
对于一般损失函数(梯度下降),拟合的就是残差的近似值,分裂结点划分时枚举所有特征的值,选取划分点。
最后预测的结果是每棵树的预测结果相加。
1、把树拆分成树结构部分q和叶子权重部分w
2、树的复杂度函数和样例
定义树的结构和复杂度的原因很简单,这样就可以衡量模型的复杂度了啊,从而可以有效控制过拟合。
和传统的boosting tree模型一样,XGBoost的提升模型也是采用的残差(或梯度负方向),不同的是分裂结点选取的时候不一定是最小平方损失。
最终的目标函数只依赖于每个数据点的在误差函数上的一阶导数和二阶导数。这么写的原因很明显,由于之前的目标函数求最优解的过程中只对平方损失函数时候方便求,对于其他的损失函数变得很复杂,通过二阶泰勒展开式的变换,这样求解其他损失函数变得可行了。当定义了分裂候选集合的时候
可以进一步改目标函数。分裂结点的候选集是很关键的一步,这是xgboost速度快的保证,怎么选出来这个集合,后面会介绍。
Obj代表了当指定一个树的结构的时候,在目标上面最多减少多少?
对于每一次尝试去对已有的叶子加入一个分割
这样就可以在建树的过程中动态的选择是否要添加一个结点。
假设要枚举所有x < a 这样的条件,对于某个特定的分割a,要计算a左边和右边的导数和。对于所有的a,我们只要做一遍从左到右的扫描就可以枚举出所有分割的梯度和GL、GR。然后用上面的公式计算每个分割方案的分数就可以了。
1、暴力枚举
2、近似方法 ,近似方法通过特征的分布,按照百分比确定一组候选分裂点,通过遍历所有的候选分裂点来找到最佳分裂点。两种策略:全局策略和局部策略。
前者需要较大的分裂集合,后者可以小一点。对比补充候选集策略与分裂点数目对模型的影响。全局策略需要更细的分裂点才能和局部策略差不多
3、Weighted Quantile Sketch
陈天奇提出并从概率角度证明了一种带权重的分布式的Quantile Sketch。
参考链接:
网上很多教程教的是如何进行编译安装,过程比较繁琐,比较简单的方式是下载已经编译好的.whl文件进行安装。
XGBoost的作者把所有的参数分成了三类:
在这里我们会类比GBM来讲解,所以作为一种基础知识。
这些参数用来控制XGBoost的宏观功能。
因为tree booster的表现远远胜过linear booster,所以linear booster很少用到。针对tree booster 的参数(适用于booster=gbtree,dart) :
,0 表示没有限制。
XGBoost基本上都是组合大量小学习率的回归树。在这种情况,越晚添加的树比越早添加的树更重要。Rasmi根据深度神经网络社区提出一个新的使用dropout的boosted trees,并且证明它在某些情况有更好的结果。以下是新的tree boosterdart的介绍。
DART booster 原理:为了缓解过拟合,采用dropout 技术,随机丢弃一些树。
由于引入了随机性,因此dart 和gbtree 有以下的不同:
DART算法和MART(GBDT)算法主要有两个不同点:
dropout
计算下一棵树要拟合的梯度的时候,仅仅随机从已经生成的树中选取一部分。假设经过n次迭代之后当前模型为M,
,当中
是第i次学习到的树。DART算法首先选择一个随机子集
,创建模型
。树T从
学习得到,当中
表示求损失函数的梯度作为下一次的标签,GDBT中使用损失函数的梯度作为下一个树的输入标签。
归一化
DART和MART第二点不同就是DART添加一棵树时需要先归一化。归一化背后的原理是:树T是尝试减少
和最优预测器之间的差距,dropped trees也是为了减少这个差距。因此引入new tree和dropped trees都是为了达到相同的目标。进一步说,假设通过I建立模型
时drop掉k棵树。所以新的树T大概是dropped trees中每一个独立的树的k倍。因此,DART算法将树T乘以1/k,这使T的大小和每一个单独的dropped trees相同。然后,新的树和dropped trees都乘以k/(1+k),再将新的树加入集成模型中。乘以k/(k+1)是为了保证新的树的引入和不引入的效果一样。
XGBoost官方文档:
原始链接:Rashmi Korlakai Vinayak, Ran Gilad-Bachrach. “DART: Dropouts meet Multiple Additive Regression Trees.
DART booster继承了gbtree,所以dart也有eta.gamma,max_depth等参数,额外增加的参数如下:
;被丢弃的子树被缩放为
。其中v为学习率,K为被丢弃的子树的数量
;被丢弃的子树被缩放为
。其中v为学习率
这个参数用来控制理想的优化目标和每一步结果的度量方法。
如果你之前用的是Scikit-learn,你可能不太熟悉这些参数。但是有个好消息,python的XGBoost模块有一个sklearn包。这个包中的参数是按sklearn风格命名的。会改变的函数名是:
你肯定在疑惑为啥咱们没有介绍和GBM中的’n_estimators’类似的参数。XGBoost中确实有一个类似的参数,是在标准XGBoost实现中调用拟合函数时,把它作为’num_boosting_rounds’参数传入。
参考链接:
对于external-memory 和 in-memory 计算,二者几乎没有区别。除了在文件名上有所不同。
xgboost 支持使用gpu 计算,前提是安装时开启了GPU 支持。要想使用GPU 训练,需要指定tree_method 参数为下列的值:
当tree_method 为’gpu_exact’,’gpu_hist’ 时,模型的predict 默认采用GPU 加速。
你可以通过设置predictor 参数来指定predict 时的计算设备:
多GPU 可以通过grow_gpu_hist 参数和 n_gpus 参数配合使用。如果n_gpus设置为 -1,则所有的GPU 都被使用。它默认为1。多GPU 不一定比单个GPU 更快,因为PCI总线的带宽限制,数据传输速度可能成为瓶颈。可以通过gpu_id 参数来选择设备,默认为 0 。如果非0,则GPU 的编号规则为 mod(gpu_id + i) % n_visible_devices for i in 0~n_gpus-1
GPU 计算支持的参数:
在模型中可能会有一些单调的约束:当
时:
如果想在xgboost 中添加单调约束,则可以设置monotone_constraints 参数。假设样本有 2 个特征,则:
右侧的 1 表示单调递增约束;0 表示无约束; -1 表示单调递减约束。 有多少个特征,就对应多少个数值。
xgboost 的数据存储在DMatrix 对象中,xgboost 支持直接从下列格式的文件中加载数据:
[label] [index1]:[value1] [index2]:[value2] ...
[label] [index1]:[value1] [index2]:[value2] ...
...
dtrain = xgb.DMatrix('train.svm.txt') #libsvm 格式
dtest = xgb.DMatrix('test.svm.buffer') # xgboost binary buffer 文件
data = np.random.rand(5, 10)
label = np.random.randint(2, size=5)
dtrain = xgb.DMatrix(data, label=label)#从 numpy array 中加载
csr = scipy.sparse.csr_matrix((dat, (row, col)))
dtrain = xgb.DMatrix(csr)
DMatrix: 由xgboost 内部使用的数据结构,它存储了数据集,并且针对了内存消耗和训练速度进行了优化。
xgboost.DMatrix(data, label=None, missing=None, weight=None, silent=False,
feature_names=None, feature_types=None, nthread=None)
参数:
属性:
方法:
示例:
data/train.svm.txt 的内容:
1 1:1 2:2
1 1:2 2:3
1 1:3 2:4
1 1:4 2:5
0 1:5 2:6
0 1:6 2:7
0 1:7 2:8
0 1:8 2:9
测试代码:
import xgboost as xgt
import numpy as np
class MatrixTest:
'''
测试 DMatrix
'''
def __init__(self):
self._matrix1 = xgt.DMatrix('data/train.svm.txt')
self._matrix2 = xgt.DMatrix(data=np.arange(0, 12).reshape((4, 3)),
label=[1, 2, 3, 4], weight=[0.5, 0.4, 0.3, 0.2],
silent=False, feature_names=['a', 'b', 'c'],
feature_types=['int', 'int', 'float'], nthread=2)
def print(self, matrix):
print('feature_names:%s' % matrix.feature_names)
print('feature_types:%s' % matrix.feature_types)
def run_get(self, matrix):
print('get_base_margin():', matrix.get_base_margin())
print('get_label():', matrix.get_label())
print('get_weight():', matrix.get_weight())
print('num_col():', matrix.num_col())
print('num_row():', matrix.num_row())
def test(self):
print('查看 matrix1 :')
self.print(self._matrix1)
# feature_names:['f0', 'f1', 'f2']
# feature_types:None
print('\n查看 matrix2 :')
self.print(self._matrix2)
# feature_names:['a', 'b', 'c']
# feature_types:['int', 'int', 'float']
print('\n查看 matrix1 get:')
self.run_get(self._matrix1)
# get_base_margin(): []
# get_label(): [1. 1. 1. 1. 0. 0. 0. 0.]
# get_weight(): []
# num_col(): 3
# num_row(): 8
print('\n查看 matrix2 get:')
self.run_get(self._matrix2)
# get_base_margin(): []
# get_label(): [1. 2. 3. 4.]
# get_weight(): [0.5 0.4 0.3 0.2]
# num_col(): 3
# num_row(): 4
print(self._matrix2.slice([0, 1]).get_label())
# [1. 2.]
Booster 是xgboost 的模型,它包含了训练、预测、评估等任务的底层实现。
xbgoost.Booster(params=None,cache=(),model_file=None)
参数:
属性:通过方法来存取、设置属性。
方法:
for i in range(0,100):
booster.update(train_matrix,iteration=i)
Booster 没有 train 方法。因此有两种策略来获得训练好的 Booster
示例:
import xgboost as xgt
import pandas as pd
from sklearn.model_selection import train_test_split
_label_map = {
# 'Iris-setosa':0, #经过裁剪的,去掉了 iris 中的 setosa 类
'Iris-versicolor': 0,
'Iris-virginica': 1
}
class BoosterTest:
'''
测试 Booster
'''
def __init__(self):
df = pd.read_csv('./data/iris.csv')
_feature_names = ['Sepal Length', 'Sepal Width', 'Petal Length', 'Petal Width']
x = df[_feature_names]
y = df['Class'].map(lambda x: _label_map[x])
train_X, test_X, train_Y, test_Y = train_test_split(x, y,
test_size=0.3, stratify=y, shuffle=True, random_state=1)
self._train_matrix = xgt.DMatrix(data=train_X, label=train_Y,
eature_names=_feature_names,
feature_types=['float', 'float', 'float', 'float'])
self._validate_matrix = xgt.DMatrix(data=test_X, label=test_Y,
feature_names=_feature_names,
feature_types=['float', 'float', 'float', 'float'])
self._booster = xgt.Booster(params={
'booster': 'gbtree',
'silent': 0, # 打印消息
'eta': 0.1, # 学习率
'max_depth': 5,
'tree_method': 'exact',
'objective': 'binary:logistic',
'eval_metric': 'auc',
'seed': 321},
cache=[self._train_matrix, self._validate_matrix])
def test_attribute(self):
'''
测试属性的设置和获取
:return:
'''
self._booster.set_attr(key1='1')
print('attr:key1 -> ', self._booster.attr('key1'))
print('attr:key2 -> ', self._booster.attr('key2'))
print('attributes -> ', self._booster.attributes())
def test_dump_model(self):
'''
测试 dump 模型
:return:
'''
_dump_str = self._booster.get_dump(fmap='model/booster.feature',
with_stats=True, dump_format='text')
print('dump:', _dump_str[0][:20] + '...' if _dump_str else [])
self._booster.dump_model('model/booster.model',
fmap='model/booster.feature', with_stats=True)
def test_train(self):
'''
训练
:return:
'''
for i in range(0, 100):
self._booster.update(self._train_matrix, iteration=i)
print(self._booster.eval(self._train_matrix, name='train', iteration=i))
print(self._booster.eval(self._validate_matrix, name='eval', iteration=i))
def test_importance(self):
'''
测试特征重要性
:return:
'''
print('fscore:', self._booster.get_fscore('model/booster.feature'))
print('score.weight:', self._booster.get_score(importance_type='weight'))
print('score.gain:', self._booster.get_score(importance_type='gain'))
def test(self):
self.test_attribute()
# attr:key1 -> 1
# attr:key2 -> None
# attributes -> {'key1': '1'}
self.test_dump_model()
# dump: []
self.test_train()
# [0] train-auc:0.980816
# [0] eval-auc:0.933333
# ...
# [99] train-auc:0.998367
# [99] eval-auc:0.995556
self.test_dump_model()
# dump: 0:[f2<4.85] yes=1,no...
self.test_importance()
# score: {'f2': 80, 'f3': 72, 'f0': 6, 'f1': 5}
# score.weight: {'Petal Length': 80, 'Petal Width': 72, 'Sepal Length': 6, 'Sepal Width': 5}
# score.gain: {'Petal Length': 3.6525380337500004, 'Petal Width': 2.2072901486111114, 'Sepal Length': 0.06247816666666667, 'Sepal Width': 0.09243024}
if __name__ == '__main__':
BoosterTest().test()
xgboost.train(): 使用给定的参数来训练一个booster
xgboost.train(params, dtrain, num_boost_round=10, evals=(), obj=None, feval=None,
maximize=False, early_stopping_rounds=None, evals_result=None, verbose_eval=True,
xgb_model=None, callbacks=None, learning_rates=None)
参数:
返回值:一个Booster 对象,表示训练好的模型
xgboost.cv(): 使用给定的参数执行交叉验证 。它常用作参数搜索
xgboost.cv(params, dtrain, num_boost_round=10, nfold=3, stratified=False, folds=None,
metrics=(), obj=None, feval=None, maximize=False, early_stopping_rounds=None,
fpreproc=None, as_pandas=True, verbose_eval=None, show_stdv=True, seed=0,
callbacks=None, shuffle=True)
参数:
返回值:一个字符串的列表,给出了evaluation history 。它给的是早停时刻的history(此时对应着最优模型),早停之后的结果被抛弃。
示例:
import xgboost as xgt
import pandas as pd
from sklearn.model_selection import train_test_split
_label_map = {
# 'Iris-setosa':0, #经过裁剪的,去掉了 iris 中的 setosa 类
'Iris-versicolor': 0,
'Iris-virginica': 1
}
class TrainTest:
def __init__(self):
df = pd.read_csv('./data/iris.csv')
_feature_names = ['Sepal Length', 'Sepal Width', 'Petal Length', 'Petal Width']
x = df[_feature_names]
y = df['Class'].map(lambda x: _label_map[x])
train_X, test_X, train_Y, test_Y = train_test_split(x, y, test_size=0.3,
stratify=y, shuffle=True, random_state=1)
self._train_matrix = xgt.DMatrix(data=train_X, label=train_Y,
feature_names=_feature_names,
feature_types=['float', 'float', 'float', 'float'])
self._validate_matrix = xgt.DMatrix(data=test_X, label=test_Y,
feature_names=_feature_names,
feature_types=['float', 'float', 'float', 'float'])
def train_test(self):
params = {
'booster': 'gbtree',
'eta': 0.01,
'max_depth': 5,
'tree_method': 'exact',
'objective': 'binary:logistic',
'eval_metric': ['logloss', 'error', 'auc']
}
eval_rst = {}
booster = xgt.train(params, self._train_matrix, num_boost_round=20,
evals=([(self._train_matrix, 'valid1'), (self._validate_matrix, 'valid2')]),
early_stopping_rounds=5, evals_result=eval_rst, verbose_eval=True)
## 训练输出
# Multiple eval metrics have been passed: 'valid2-auc' will be used for early stopping.
# Will train until valid2-auc hasn't improved in 5 rounds.
# [0] valid1-logloss:0.685684 valid1-error:0.042857 valid1-auc:0.980816 valid2-logloss:0.685749 valid2-error:0.066667 valid2-auc:0.933333
# ...
# Stopping. Best iteration:
# [1] valid1-logloss:0.678149 valid1-error:0.042857 valid1-auc:0.99551 valid2-logloss:0.677882 valid2-error:0.066667 valid2-auc:0.966667
print('booster attributes:', booster.attributes())
# booster attributes: {'best_iteration': '1', 'best_msg': '[1]\tvalid1-logloss:0.678149\tvalid1-error:0.042857\tvalid1-auc:0.99551\tvalid2-logloss:0.677882\tvalid2-error:0.066667\tvalid2-auc:0.966667', 'best_score': '0.966667'}
print('fscore:', booster.get_fscore())
# fscore: {'Petal Length': 8, 'Petal Width': 7}
print('eval_rst:', eval_rst)
# eval_rst: {'valid1': {'logloss': [0.685684, 0.678149, 0.671075, 0.663787, 0.656948, 0.649895], 'error': [0.042857, 0.042857, 0.042857, 0.042857, 0.042857, 0.042857], 'auc': [0.980816, 0.99551, 0.99551, 0.99551, 0.99551, 0.99551]}, 'valid2': {'logloss': [0.685749, 0.677882, 0.670747, 0.663147, 0.656263, 0.648916], 'error': [0.066667, 0.066667, 0.066667, 0.066667, 0.066667, 0.066667], 'auc': [0.933333, 0.966667, 0.966667, 0.966667, 0.966667, 0.966667]}}
def cv_test(self):
params = {
'booster': 'gbtree',
'eta': 0.01,
'max_depth': 5,
'tree_method': 'exact',
'objective': 'binary:logistic',
'eval_metric': ['logloss', 'error', 'auc']
}
eval_history = xgt.cv(params, self._train_matrix, num_boost_round=20,
nfold=3, stratified=True, metrics=['error', 'auc'],
early_stopping_rounds=5, verbose_eval=True, shuffle=True)
## 训练输出
# [0] train-auc:0.974306+0.00309697 train-error:0.0428743+0.0177703 test-auc:0.887626+0.0695933 test-error:0.112374+0.0695933
# ....
print('eval_history:', eval_history)
# eval_history: test-auc-mean test-auc-std test-error-mean test-error-std \
# 0 0.887626 0.069593 0.112374 0.069593
# 1 0.925821 0.020752 0.112374 0.069593
# 2 0.925821 0.020752 0.098485 0.050631
# train-auc-mean train-auc-std train-error-mean train-error-std
# 0 0.974306 0.003097 0.042874 0.01777
# 1 0.987893 0.012337 0.042874 0.01777
# 2 0.986735 0.011871 0.042874 0.01777
xgboost 给出了针对scikit-learn 接口的API。
xgboost.XGBRegressor: 它实现了scikit-learn 的回归模型API
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, **kwargs)
参数:
xgboost.XGBClassifier :它实现了scikit-learn 的分类模型API
class xgboost.XGBClassifier(max_depth=3, learning_rate=0.1, n_estimators=100,
silent=True, objective='binary:logistic', 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, **kwargs)
参数参考xgboost.XGBRegressor
xgboost.XGBClassifier 和 xgboost.XGBRegressor 的方法:
示例:
import xgboost as xgt
import pandas as pd
from sklearn.model_selection import train_test_split
_label_map = {
# 'Iris-setosa':0, #经过裁剪的,去掉了 iris 中的 setosa 类
'Iris-versicolor': 0,
'Iris-virginica': 1
}
class SKLTest:
def __init__(self):
df = pd.read_csv('./data/iris.csv')
_feature_names = ['Sepal Length', 'Sepal Width', 'Petal Length', 'Petal Width']
x = df[_feature_names]
y = df['Class'].map(lambda x: _label_map[x])
self.train_X, self.test_X, self.train_Y, self.test_Y = \
train_test_split(x, y, test_size=0.3, stratify=y, shuffle=True, random_state=1)
def train_test(self):
clf = xgt.XGBClassifier(max_depth=3, learning_rate=0.1, n_estimators=100)
clf.fit(self.train_X, self.train_Y, eval_metric='auc',
eval_set=[(self.test_X, self.test_Y), ],
early_stopping_rounds=3)
# 训练输出:
# Will train until validation_0-auc hasn't improved in 3 rounds.
# [0] validation_0-auc:0.933333
# ...
# Stopping. Best iteration:
# [2] validation_0-auc:0.997778
print('evals_result:', clf.evals_result())
# evals_result: {'validation_0': {'auc': [0.933333, 0.966667, 0.997778, 0.997778, 0.997778]}}
print('predict:', clf.predict(self.test_X))
# predict: [1 1 0 0 0 1 1 1 0 0 0 1 1 0 1 1 0 1 0 0 0 0 0 1 1 0 0 1 1 0]
xgboost.plot_importance():绘制特征重要性
xgboost.plot_importance(booster, ax=None, height=0.2, xlim=None, ylim=None,
title='Feature importance', xlabel='F score', ylabel='Features',
importance_type='weight', max_num_features=None, grid=True,
show_values=True, **kwargs)
参数:
xgboost.plot_tree(): 绘制指定的子树
xgboost.plot_tree(booster, fmap='', num_trees=0, rankdir='UT', ax=None, **kwargs)
参数:
xgboost.to_graphviz(): 转换指定的子树成一个graphviz 实例
在IPython中,可以自动绘制graphviz 实例;否则你需要手动调用graphviz 对象的.render() 方法来绘制。
xgboost.to_graphviz(booster, fmap='', num_trees=0, rankdir='UT', yes_color='#0000FF',
no_color='#FF0000', **kwargs)
参数:
示例:
import xgboost as xgt
import pandas as pd
from sklearn.model_selection import train_test_split
from matplotlib.pylab import plot as plt
_label_map = {
# 'Iris-setosa':0, #经过裁剪的,去掉了 iris 中的 setosa 类
'Iris-versicolor': 0,
'Iris-virginica': 1
}
class PlotTest:
def __init__(self):
df = pd.read_csv('./data/iris.csv')
_feature_names = ['Sepal Length', 'Sepal Width', 'Petal Length', 'Petal Width']
x = df[_feature_names]
y = df['Class'].map(lambda x: _label_map[x])
train_X, test_X, train_Y, test_Y = train_test_split(x, y,
test_size=0.3, stratify=y, shuffle=True, random_state=1)
self._train_matrix = xgt.DMatrix(data=train_X, label=train_Y,
feature_names=_feature_names,
feature_types=['float', 'float', 'float', 'float'])
self._validate_matrix = xgt.DMatrix(data=test_X, label=test_Y,
feature_names=_feature_names,
feature_types=['float', 'float', 'float', 'float'])
def plot_test(self):
params = {
'booster': 'gbtree',
'eta': 0.01,
'max_depth': 5,
'tree_method': 'exact',
'objective': 'binary:logistic',
'eval_metric': ['logloss', 'error', 'auc']
}
eval_rst = {}
booster = xgt.train(params, self._train_matrix,
num_boost_round=20, evals=([(self._train_matrix, 'valid1'),
(self._validate_matrix, 'valid2')]),
early_stopping_rounds=5, evals_result=eval_rst, verbose_eval=True)
xgt.plot_importance(booster)
plt.show()
在对XGBoost进行优化调参的时候,使用的是Scikit-learn中sklearn.model_selection.GridSearchCV
常用参数解读:
具体参考地址:http://scikit-learn.org/stable/modules/model_evaluation.html
演示时使用的r2这个得分函数,你也可以根据自己的实际需要来选择。调参刚开始的时候,一般要先初始化一些值:
调参的时候一般按照以下顺序来进行:
1、最佳迭代次数:n_estimators
if __name__ == '__main__':
...
cv_params = {'n_estimators': [400, 500, 600, 700, 800]}
other_params = {'learning_rate': 0.1, 'n_estimators': 500, 'max_depth': 5, 'min_child_weight': 1, 'seed': 0,
'subsample': 0.8, 'colsample_bytree': 0.8, 'gamma': 0, 'reg_alpha': 0, 'reg_lambda': 1}
model = xgb.XGBRegressor(**other_params)
optimized_GBM = GridSearchCV(estimator=model, param_grid=cv_params, scoring='r2', cv=5, verbose=1, n_jobs=4)
optimized_GBM.fit(X_train, y_train)
evalute_result = optimized_GBM.grid_scores_
print('每轮迭代运行结果:{0}'.format(evalute_result))
print('参数的最佳取值:{0}'.format(optimized_GBM.best_params_))
print('最佳模型得分:{0}'.format(optimized_GBM.best_score_))
运行后的结果为:
[Parallel(n_jobs=4)]: Done 25 out of 25 | elapsed: 1.5min finished
每轮迭代运行结果:[mean: 0.94051, std: 0.01244, params: {'n_estimators': 400}, mean: 0.94057, std: 0.01244, params: {'n_estimators': 500}, mean: 0.94061, std: 0.01230, params: {'n_estimators': 600}, mean: 0.94060, std: 0.01223, params: {'n_estimators': 700}, mean: 0.94058, std: 0.01231, params: {'n_estimators': 800}]
参数的最佳取值:{'n_estimators': 600}
最佳模型得分:0.9406056804545407
由输出结果可知最佳迭代次数为600次。但是,我们还不能认为这是最终的结果,由于设置的间隔太大,所以,我们又测试了一组参数,这次粒度小一些:
cv_params = {'n_estimators': [550, 575, 600, 650, 675]}
other_params = {'learning_rate': 0.1, 'n_estimators': 600, 'max_depth': 5, 'min_child_weight': 1, 'seed': 0,
'subsample': 0.8, 'colsample_bytree': 0.8, 'gamma': 0, 'reg_alpha': 0, 'reg_lambda': 1}
运行后最佳迭代次数变成了550。有人可能会问,那还要不要继续缩小粒度测试下去呢?这个可以看个人情况,如果你想要更高的精度,当然是粒度越小,结果越准确,大家可以自己慢慢去调试。
2、接下来要调试的参数是min_child_weight以及max_depth
注意:每次调完一个参数,要把 other_params对应的参数更新为最优值。
cv_params = {'max_depth': [3, 4, 5, 6, 7, 8, 9, 10], 'min_child_weight': [1, 2, 3, 4, 5, 6]}
other_params = {'learning_rate': 0.1, 'n_estimators': 550, 'max_depth': 5, 'min_child_weight': 1, 'seed': 0,
'subsample': 0.8, 'colsample_bytree': 0.8, 'gamma': 0, 'reg_alpha': 0, 'reg_lambda': 1}
运行后可知参数的最佳取值:{‘min_child_weight’: 5, ‘max_depth’: 4}。(代码输出结果被我省略了一部分,因为结果太长了,以下也是如此)
3、接着我们就开始调试参数:gamma
cv_params = {'gamma': [0.1, 0.2, 0.3, 0.4, 0.5, 0.6]}
other_params = {'learning_rate': 0.1, 'n_estimators': 550, 'max_depth': 4, 'min_child_weight': 5, 'seed': 0,
'subsample': 0.8, 'colsample_bytree': 0.8, 'gamma': 0, 'reg_alpha': 0, 'reg_lambda': 1}
由输出结果可知参数的最佳取值:{‘gamma’: 0.1}。
4、接着是subsample以及colsample_bytree
cv_params = {'subsample': [0.6, 0.7, 0.8, 0.9], 'colsample_bytree': [0.6, 0.7, 0.8, 0.9]}
other_params = {'learning_rate': 0.1, 'n_estimators': 550, 'max_depth': 4, 'min_child_weight': 5, 'seed': 0,
'subsample': 0.8, 'colsample_bytree': 0.8, 'gamma': 0.1, 'reg_alpha': 0, 'reg_lambda': 1}
运行后显示参数的最佳取值:{‘subsample’: 0.7,’colsample_bytree’: 0.7}
5、紧接着就是:reg_alpha以及reg_lambda
cv_params = {'reg_alpha': [0.05, 0.1, 1, 2, 3], 'reg_lambda': [0.05, 0.1, 1, 2, 3]}
other_params = {'learning_rate': 0.1, 'n_estimators': 550, 'max_depth': 4, 'min_child_weight': 5, 'seed': 0,
'subsample': 0.7, 'colsample_bytree': 0.7, 'gamma': 0.1, 'reg_alpha': 0, 'reg_lambda': 1}
由输出结果可知参数的最佳取值:{‘reg_alpha’: 1, ‘reg_lambda’: 1}。
6、最后就是learning_rate,一般这时候要调小学习率来测试
cv_params = {'learning_rate': [0.01, 0.05, 0.07, 0.1, 0.2]}
other_params = {'learning_rate': 0.1, 'n_estimators': 550, 'max_depth': 4, 'min_child_weight': 5, 'seed': 0,
'subsample': 0.7, 'colsample_bytree': 0.7, 'gamma': 0.1, 'reg_alpha': 1, 'reg_lambda': 1}
由输出结果可知参数的最佳取值:{‘learning_rate’: 0.1}。
我们可以很清楚地看到,随着参数的调优,最佳模型得分是不断提高的,这也从另一方面验证了调优确实是起到了一定的作用。不过,我们也可以注意到,其实最佳分数并没有提升太多。提醒一点,这个分数是根据前面设置的得分函数算出来的。
https://www.biaodianfu.com/xgboost.html#%E5%A6%82%E4%BD%95%E4%BD%BF%E7%94%A8XGBoost%EF%BC%9F