在XGBoost算法原理小结中,咱们讨论了XGBoost的算法原理,这一片咱们讨论如何使用XGBoost的Python类库,以及一些重要参数的意义和调参思路。html
本文主要参考了XGBoost的Python文档 和 XGBoost的参数文档。node
XGBoost除了支持Python外,也支持R,Java等语言。本文关注于Python的XGBoost类库,安装使用"pip install xgboost"便可,目前使用的是XGBoost的0.90版本。XGBoost类库除了支持决策树做为弱学习器外,还支持线性分类器,以及带DropOut的决策树DART,不过一般状况下,咱们使用默认的决策树弱学习器便可,本文也只会讨论使用默认决策树弱学习器的XGBoost。python
XGBoost有2种Python接口风格。一种是XGBoost自带的原生Python API接口,另外一种是sklearn风格的API接口,二者的实现是基本同样的,仅仅有细微的API使用的不一样,主要体如今参数命名上,以及数据集的初始化上面。git
完整示例参见个人Github代码。github
XGBoost的类库的2种接口风格,咱们先来看看原生Python API接口如何使用。算法
原生XGBoost须要先把数据集按输入特征部分,输出部分分开,而后放到一个DMatrix数据结构里面,这个DMatrix咱们不须要关内心面的细节,使用咱们的训练集X和y初始化便可。api
import pandas as pd import numpy as np import xgboost as xgb import matplotlib.pylab as plt %matplotlib inline from sklearn.model_selection import GridSearchCV from sklearn.model_selection import train_test_split
from sklearn.datasets.samples_generator import make_classification # X为样本特征,y为样本类别输出, 共10000个样本,每一个样本20个特征,输出有2个类别,没有冗余特征,每一个类别一个簇 X, y = make_classification(n_samples=10000, n_features=20, n_redundant=0, n_clusters_per_class=1, n_classes=2, flip_y=0.1)
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=1)
dtrain = xgb.DMatrix(X_train,y_train)
dtest = xgb.DMatrix(X_test,y_test)
上面的代码中,咱们随机初始化了一个二分类的数据集,而后分红了训练集和验证集。使用训练集和验证集分别初始化了一个DMatrix,有了DMatrix,就能够作训练和预测了。简单的示例代码以下:数据结构
param = {'max_depth':5, 'eta':0.5, 'verbosity':1, 'objective':'binary:logistic'} raw_model = xgb.train(param, dtrain, num_boost_round=20)
from sklearn.metrics import accuracy_score pred_train_raw = raw_model.predict(dtrain) for i in range(len(pred_train_raw)): if pred_train_raw[i] > 0.5: pred_train_raw[i]=1 else: pred_train_raw[i]=0 print (accuracy_score(dtrain.get_label(), pred_train_raw))
训练集的准确率我这里输出是0.9664。再看看验证集的表现:并发
pred_test_raw = raw_model.predict(dtest) for i in range(len(pred_test_raw)): if pred_test_raw[i] > 0.5: pred_test_raw[i]=1 else: pred_test_raw[i]=0 print (accuracy_score(dtest.get_label(), pred_test_raw))
验证集的准确率我这里的输出是0.9408,已经很高了。app
不过对于我这样用惯sklearn风格API的,仍是不太喜欢原生Python API接口,既然有sklearn的wrapper,那么就尽可能使用sklearn风格的接口吧。
对于sklearn风格的接口,主要有2个类可使用,一个是分类用的XGBClassifier,另外一个是回归用的XGBRegressor。在使用这2个类的使用,对于算法的参数输入也有2种方式,第一种就是仍然使用和原始API同样的参数命名集合,另外一种是使用sklearn风格的参数命名。咱们这里先看看如何使用和原始API同样的参数命名集合。
其实就是使用XGBClassifier/XGBRegressor的**kwargs参数,把上面原生参数的params集合放进去,代码以下:
sklearn_model_raw = xgb.XGBClassifier(**param) sklearn_model_raw.fit(X_train, y_train, early_stopping_rounds=10, eval_metric="error", eval_set=[(X_test, y_test)])
里面的param其实就是2.1节里面定义的:
param = {'max_depth':5, 'eta':0.5, 'verbosity':1, 'objective':'binary:logistic'}
使用sklearn风格的接口,却使用原始的参数名定义,感受仍是有点怪,因此我通常仍是习惯使用另外一种风格接口,sklearn风格的参数命名。
使用sklearn风格的接口,并使用sklearn风格的参数,是我推荐的方式,主要是这样作和GBDT之类的sklearn库使用起来没有什么两样了,也可使用sklearn的网格搜索。
不过这样作的话,参数定义命名和2.1与2.2节就有些不一样了。具体的参数意义咱们后面讲,咱们看看分类的算法初始化,训练与调用的简单过程:
sklearn_model_new = xgb.XGBClassifier(max_depth=5,learning_rate= 0.5, verbosity=1, objective='binary:logistic',random_state=1)
能够看到,参数定义直接放在了XGBClassifier的类参数里,和sklearn相似。你们能够看到以前两节咱们定义的步长eta,这里变成了另外一个名字learning_rate。
在初始化后,训练和预测的方法就和2.2节没有区别了。
sklearn_model_new.fit(X_train, y_train, early_stopping_rounds=10, eval_metric="error", eval_set=[(X_test, y_test)])
在第二节咱们已经尝试使用XGBoost类库了,可是对于XGBoost的类库参数并无过多讨论。这里咱们就详细讨论下,主要以2.3节的sklearn风格参数为主来进行讨论。这些参数我会和以前讲的scikit-learn 梯度提高树(GBDT)调参小结中的参数定义对应,这样若是你们对GBDT的调参很熟悉了,那么XGBoost的调参也就掌握90%了。
XGBoost的类库参数主要包括boosting框架参数,弱学习器参数以及其余参数。
对于XGBoost的框架参数,最重要的是3个参数: booster,n_estimators和objectve。
1) booster决定了XGBoost使用的弱学习器类型,能够是默认的gbtree, 也就是CART决策树,还能够是线性弱学习器gblinear以及DART。通常来讲,咱们使用gbtree就能够了,不须要调参。
2) n_estimators则是很是重要的要调的参数,它关系到咱们XGBoost模型的复杂度,由于它表明了咱们决策树弱学习器的个数。这个参数对应sklearn GBDT的n_estimators。n_estimators过小,容易欠拟合,n_estimators太大,模型会过于复杂,通常须要调参选择一个适中的数值。
3) objective表明了咱们要解决的问题是分类仍是回归,或其余问题,以及对应的损失函数。具体能够取的值不少,通常咱们只关心在分类和回归的时候使用的参数。
在回归问题objective通常使用reg:squarederror ,即MSE均方偏差。二分类问题通常使用binary:logistic, 多分类问题通常使用multi:softmax。
这里咱们只讨论使用gbtree默认弱学习器的参数。 要调参的参数主要是决策树的相关参数以下:
1) max_depth: 控制树结构的深度,数据少或者特征少的时候能够无论这个值。若是模型样本量多,特征也多的状况下,须要限制这个最大深度,具体的取值通常要网格搜索调参。这个参数对应sklearn GBDT的max_depth。
2) min_child_weight: 最小的子节点权重阈值,若是某个树节点的权重小于这个阈值,则不会再分裂子树,即这个树节点就是叶子节点。这里树节点的权重使用的是该节点全部样本的二阶导数的和,即XGBoost原理篇里面的$H_{tj}$:$$H_{tj} = \sum\limits_{x_i \in R_{tj}}h_{ti}$$
这个值须要网格搜索寻找最优值,在sklearn GBDT里面,没有彻底对应的参数,不过min_samples_split从另外一个角度起到了阈值限制。
3) gamma: XGBoost的决策树分裂所带来的损失减少阈值。也就是咱们在尝试树结构分裂时,会尝试最大数下式:$$ \max \frac{1}{2}\frac{G_L^2}{H_L + \lambda} + \frac{1}{2}\frac{G_R^2}{H_R+\lambda} - \frac{1}{2}\frac{(G_L+G_R)^2}{H_L+H_R+ \lambda} - \gamma$$
这个最大化后的值须要大于咱们的gamma,才能继续分裂子树。这个值也须要网格搜索寻找最优值。
4) subsample: 子采样参数,这个也是不放回抽样,和sklearn GBDT的subsample做用同样。选择小于1的比例能够减小方差,即防止过拟合,可是会增长样本拟合的误差,所以取值不能过低。初期能够取值1,若是发现过拟合后能够网格搜索调参找一个相对小一些的值。
5) colsample_bytree/colsample_bylevel/colsample_bynode: 这三个参数都是用于特征采样的,默认都是不作采样,即便用全部的特征创建决策树。colsample_bytree控制整棵树的特征采样比例,colsample_bylevel控制某一层的特征采样比例,而colsample_bynode控制某一个树节点的特征采样比例。好比咱们一共64个特征,则假设colsample_bytree,colsample_bylevel和colsample_bynode都是0.5,则某一个树节点分裂时会随机采样8个特征来尝试分裂子树。
6) reg_alpha/reg_lambda: 这2个是XGBoost的正则化参数。reg_alpha是L1正则化系数,reg_lambda是L1正则化系数,在原理篇里咱们讨论了XGBoost的正则化损失项部分:$$\Omega(h_t) = \gamma J + \frac{\lambda}{2}\sum\limits_{j=1}^Jw_{tj}^2$$
上面这些参数都是须要调参的,不过通常先调max_depth,min_child_weight和gamma。若是发现有过拟合的状况下,再尝试调后面几个参数。
XGBoost还有一些其余的参数须要注意,主要是learning_rate。
learning_rate控制每一个弱学习器的权重缩减系数,和sklearn GBDT的learning_rate相似,较小的learning_rate意味着咱们须要更多的弱学习器的迭代次数。一般咱们用步长和迭代最大次数一块儿来决定算法的拟合效果。因此这两个参数n_estimators和learning_rate要一块儿调参才有效果。固然也能够先固定一个learning_rate ,而后调完n_estimators,再调完其余全部参数后,最后再来调learning_rate和n_estimators。
此外,n_jobs控制算法的并发线程数, scale_pos_weight用于类别不平衡的时候,负例和正例的比例。相似于sklearn中的class_weight。importance_type则能够查询各个特征的重要性程度。能够选择“gain”, “weight”, “cover”, “total_gain” 或者 “total_cover”。最后能够经过调用booster的get_score方法获取对应的特征权重。“weight”经过特征被选中做为分裂特征的计数来计算重要性,“gain”和“total_gain”则经过分别计算特征被选中作分裂特征时带来的平均增益和总增益来计算重要性。“cover”和 “total_cover”经过计算特征被选中作分裂时的平均样本覆盖度和整体样本覆盖度来来计算重要性。
XGBoost能够和sklearn的网格搜索类GridSeachCV结合使用来调参,使用时和普通sklearn分类回归算法没有区别。具体的流程的一个示例以下:
gsCv = GridSearchCV(sklearn_model_new, {'max_depth': [4,5,6], 'n_estimators': [5,10,20]}) gsCv.fit(X_train,y_train)
print(gsCv.best_score_) print(gsCv.best_params_)
我这里的输出是:
0.9533333333333334
{'max_depth': 4, 'n_estimators': 10}
接着尝试在上面搜索的基础上调learning_rate :
sklearn_model_new2 = xgb.XGBClassifier(max_depth=4,n_estimators=10,verbosity=1, objective='binary:logistic',random_state=1) gsCv2 = GridSearchCV(sklearn_model_new2, {'learning_rate ': [0.3,0.5,0.7]}) gsCv2.fit(X_train,y_train)
print(gsCv2.best_score_) print(gsCv2.best_params_)
我这里的输出是:
0.9516
{'learning_rate ': 0.3}
固然实际状况这里须要继续调参,这里假设咱们已经调参完毕,咱们尝试用验证集看看效果:
sklearn_model_new2 = xgb.XGBClassifier(max_depth=4,learning_rate= 0.3, verbosity=1, objective='binary:logistic',n_estimators=10) sklearn_model_new2.fit(X_train, y_train, early_stopping_rounds=10, eval_metric="error", eval_set=[(X_test, y_test)])
最后的输出是:
[9] validation_0-error:0.0588
也就是验证集的准确率是94.12%。
咱们能够经过验证集的准确率来判断咱们前面网格搜索调参是否起到了效果。实际处理的时候须要反复搜索参数并验证。
以上就是XGBoost的类库使用总结了,但愿能够帮到要用XGBoost解决实际问题的朋友们。
(欢迎转载,转载请注明出处。欢迎沟通交流: liujianping-ok@163.com)