XGBoost学习笔记

来源:互联网 发布:圆周率网络 编辑:程序博客网 时间:2024/06/06 19:07

XGBoost是Kaggle上非常火的一种模型,很多项目用它拿到了第一。

python库安装

python的pip上还没有1,mac上略有麻烦,参见Installing XGBoost on Mac OSX

Mac上,CC, CXX的version应该是7

export CC = gcc-7export CXX = g++-7

参数的说明

对于xgboost,有很多参数可以设置,这些参数的详细说明在这里,有几个重要的如下:

  • 一般参数,设置选择哪个booster算法
    • booster: 可以选择gbtree,dart和gblinear。gbtree, dart使用基于树的模型进行提升计算,gblinear使用线性模型进行提升计算。缺省值为gbtree
    • silent: 取0时表示打印出运行时信息,取1时表示以缄默方式运行,不打印运行时信息。缺省值为0
    • nthread: XGBoost运行时的线程数。缺省值是当前系统可以获得的最大线程数
    • num_pbuffer: 预测缓冲区大小,通常设置为训练实例的数目。缓冲用于保存最后一步提升的预测结果,无需人为设置。
    • num_feature: Boosting过程中用到的特征维数,设置为特征个数。XGBoost会自动设置,无需人为设置。
  • 使用的booster算法的参数

    • gbtree参数设置

      • eta(学习率): 为了防止过拟合,更新过程中用到的收缩步长。在每次提升计算之后,算法会直接获得新特征的权重。 eta通过缩减特征的权重使提升计算过程更加保守。缺省值为0.3。取值范围为:[0,1] 在 Scikit-Learn中,这个参数名是learning_rate
      • gamma(最小扩展损失): 决定树的节点是否扩展为区域的最小损失。如多一个节点split的时候,对于loss function带来的降低量大于gamma时,则进行split。值越大,算法越保守。==需要调参==。缺省值是0,取值范围是[0,∞]
      • max_depth:树的深度,越大模型越复杂,也越可能过拟合。0表示没限制,默认值是6。==需要调参==,一般在3到10之间。
      • min_child_weight: 子节点中最小的样本权重和。如果一个叶子节点的样本权重和小于min_child_weight则拆分过程结束。在现行回归模型中,这个参数是指建立每个模型所需要的最小样本数。值越大,算法越保守conservative,但太大会导致模型欠拟合,==需要调参==。默认值是1,取值范围为:[0,∞]
      • max_delta_step: 我们允许每个树的权重被估计的最大值。如果它的值被设置为0,意味着没有约束;如果它被设置为一个正值,它能够使得更新的步骤更加保守。通常无需设置该参数,但是如果在逻辑回归中极其不平衡时它可能会有帮助。把它范围设置为1-10之间也许能控制更新。默认值是0,取值范围为:[0,∞]
      • subsample: 用于训练模型的子样本占整个样本集合的比例。如果设置为0.5则意味着XGBoost将随机的从整个样本集合中随机的抽取出50%的子样本建立树模型,这能够防止过拟合,但取值太小可能欠拟合。一般在[0.5, 1]之间比较合适,允许的取值范围为:(0,1]
      • colsample_bytree: 在建立树时对特征采样的比例。缺省值为1,取值范围为:(0,1]
      • colsample_bylevel: 在建立树时,split时,对于每一层的特征采样比例。缺省值为1,取值范围为:(0,1]
      • alpha: L1 正则的惩罚系数,值越大越不容易过拟合,缺省值为0,增加这个值会让算法更保守。在 Scikit-Learn中,这个参数名是reg_alpha
      • lambda: L2 正则的惩罚系数,值越大越不容易过拟合,缺省值为1,增加这个值会让算法更保守。在 Scikit-Learn中,这个参数名是reg_lambda
      • scale_pos_weight: 当分类很不平衡的时候,把它设置为正值,可以加快收敛。默认值是1。

      还有很多,感觉不是特别重要,就没写上来

  • 学习任务的参数

    • objective: 定义学习目标,可选的目标函数如下:

      • “reg:linear” —— 线性回归。
      • “reg:logistic”—— 逻辑回归。
      • “binary:logistic”—— 二分类的逻辑回归问题,输出为概率。
      • “binary:logitraw”—— 二分类的逻辑回归问题,输出的结果为逻辑变换前的分值。
      • “count:poisson”—— 计数问题的poisson泊松回归,输出结果为poisson分布。在poisson回归中,max_delta_step的缺省值为0.7。(used to safeguard optimization)
      • “multi:softmax” –让XGBoost采用softmax目标函数处理多分类问题,同时需要设置参数num_class(类别个数),返回的是预测的分类
      • “multi:softprob” –和softmax一样,但是输出的是ndata * nclass的向量,可以将该向量reshape成ndata行nclass列的矩阵。每行数据表示样本所属于每个类别的概率。
      • “rank:pairwise” –设置XGBoost使用最小化pairwise损失做排名。
      • “reg:gamma”
      • “reg:tweedie”
    • base_score: 所有实例的初始化预测分数,全局的偏差值; 只要经历足够多的迭代次数,这个值对最终结果将不会有太大的影响。初始化为0.5

    • eval_metric: 校验数据所需要的评价指标,不同的目标函数将会有缺省的评价指标(rmse for regression, and error for classification, mean average precision for ranking),用户可以添加多种评价指标,对于Python用户要以list传递参数对给程序,而不是dict,否则后面的参数会覆盖之前。参数选择有

      • rmse: root mean square error
      • mae: mean absolute error
      • logloss: negative log-likelihood
      • error: Binary classification error rate (超过 0.5 threshold,认为是positive),就是 wrong casesall cases
      • error@t
      • merror: Multiclass classification error rate
      • mlogloss: Multiclass logloss
      • auc: Area under the curve
      • ndcg: normalized discounted cumulative gain
      • map: mean average precision
      • ndcg@n, map@n
      • “ndcg-“,”map-“,”ndcg@n-“,”map@n-”
    • seed: 随机数的种子。缺省值为0

    • num_round: boosting的轮数
    • save_period: 保存模型中间模型,如果是0,则只保存最终模型
  • 命令行参数

参数的优化

调参

可以使用hyperopt来遍历查找合适的参数配置。参见Hyperopt的使用

传统的方式可以通过 sklearn.model_selection 下面的 GridSearchCV 和 RandomizedSearchCV

  • GridSearchCV: paramters 有对应的list,然后就是笛卡尔积的遍历。所有的组合都会遍历,所以这个特别慢!
cv = StratifiedKFold(y, n_folds=10, shuffle=True, random_state=seed)# 变量params_grid = {    'max_depth': [1, 2, 3],    'n_estimators': [5, 10, 25, 50],    'learning_rate': np.linspace(1e-16, 1, 3)}# 不变量params_fixed = {    'objective': 'binary:logistic',    'silent': 1}bst_grid = GridSearchCV(    estimator=XGBClassifier(**params_fixed, seed=seed),    param_grid=params_grid,    cv=cv,    scoring='accuracy')# 训练,漫长的等待bst_grid.fit(X, y)# 得到最佳参数print(bst_grid.best_params_.items())
  • RandomizedSearchCV: paramters 有对应的list,然后随机取数,最多试指定的次数(n_iter)就结束。
# 随机的范围params_dist_grid = {    'max_depth': [1, 2, 3, 4],    'gamma': [0, 0.5, 1],    'n_estimators': randint(1, 1001), # uniform discrete random distribution    'learning_rate': uniform(), # gaussian distribution    'subsample': uniform(), # gaussian distribution    'colsample_bytree': uniform() # gaussian distribution}# 与 GridSearchCV 类似rs_grid = RandomizedSearchCV(    estimator=XGBClassifier(**params_fixed, seed=seed),    param_distributions=params_dist_grid,    n_iter=10,    cv=cv,    scoring='accuracy',    random_state=seed)rs_grid.fit(X, y)# 得到最佳参数print(rs_grid.best_params_)

Feature的预处理

对于xgboost,不需要做 feature 的 normalization。
如果存在某些训练数据数值缺失,换言之,提供的是sparse feature matrix,xgboost也能处理好。不过,gblinear booster把missing values设置为0,安全起见,missing values 一开始都设置为 np.nan 吧。
模型训练后,可以通过实例的 get_fscore() 知道哪些feature比较重要,或者 xgb.plot_importance(bst) [bst为训练好的实例]

拟合度调优

使用 early_stopping_rounds 防止过拟合

为了防止过拟合,fit 函数有一个 early_stopping_rounds 的参数,表示当模型训练 early_stopping_rounds 轮之后,模型的 loss 并没有变优,则停止训练过程。

#  采用error作为loss functionparams['eval_metric'] = 'error'num_rounds = 1500bst = xgb.train(params, dtrain, num_rounds, watchlist, early_stopping_rounds=10)

需要注意到是,上面例子中的bst返回的是最后一天iteration,而不是最佳匹配的那个。 需要用 bst.best_ntree_limit 获取正确的值

调整合适的 n_estimators 数量

当 n_estimators 数量太大的时候,容易产生过拟合。这时,可以通过测试集的匹配程度来找到合适的值。
以下内容参考之 http://education.parrotprediction.teachable.com/courses/78878/lectures/1137866

  1. 先使用 cross_validation 来划分测试集合与训练集合

    cv = StratifiedKFold(y, n_folds=10, shuffle=True, random_state=seed)
  2. 定义 estimator 的数量列表,这里是1到200,10为步长的正整数。然后通过 validation_curve 得到所有的情况下的训练得分与测试得分。

    default_params = {    'objective': 'binary:logistic',    'max_depth': 1,    'learning_rate': 0.3,    'silent': 1.0}# 定义了列表 n_estimators_range = np.linspace(1, 200, 10).astype('int')train_scores, test_scores = validation_curve(    XGBClassifier(**default_params),    X, y,    param_name = 'n_estimators',    param_range = n_estimators_range,    cv=cv,    scoring='accuracy')
  3. 假设这些数值属于正态分布,那么可以得到测试集合结果与训练集合结果的平均值和标准偏差 σ ,通过绘图看它们的曲线情况。看elbow的拐弯点在什么地方。同时,测试集结果最好的情况是在什么地方。

    train_scores_mean = np.mean(train_scores, axis=1)train_scores_std = np.std(train_scores, axis=1)test_scores_mean = np.mean(test_scores, axis=1)test_scores_std = np.std(test_scores, axis=1)fig = plt.figure(figsize=(10, 6), dpi=100)plt.title("Validation Curve with XGBoost (eta = 0.3)")plt.xlabel("number of trees")plt.ylabel("Accuracy")plt.ylim(0.7, 1.1)plt.plot(n_estimators_range,             train_scores_mean,             label="Training score",             color="r")plt.plot(n_estimators_range,             test_scores_mean,              label="Cross-validation score",             color="g")plt.fill_between(n_estimators_range,                  train_scores_mean - train_scores_std,                 train_scores_mean + train_scores_std,                  alpha=0.2, color="r")plt.fill_between(n_estimators_range,                 test_scores_mean - test_scores_std,                 test_scores_mean + test_scores_std,                 alpha=0.2, color="g")plt.axhline(y=1, color='k', ls='dashed')plt.legend(loc="best")plt.show()i = np.argmax(test_scores_mean)print("Best cross-validation result ({0:.2f}) obtained for {1} trees".format(test_scores_mean[i], n_estimators_range[i]))

获取到如下图,可以看到,elbow的拐点在25个estimator,同时,log显示89个estimator的时候,测试的mean最大,为0.90。所以,可以取一个权衡的值,比如,50个左右。
这里写图片描述

High Variance(过拟合)的处理方式

  • 减少树的最大深度 max_depth
  • 增加 min_child_weight 的值
  • 增加 gamma 的值
  • subsample, colsample_bytree 采用随机值,即不用默认1
  • 增加 lambdaalpha

High Bias(欠拟合)的处理方式

这个与 High Variance 的方式有些取反

  • 增加树的最大深度 max_depth
  • 减少 min_child_weight 的值
  • 减少 gamma 的值
  • 减少 lambdaalpha

自定义 evaluation metric

自定义函数需要接收两个参数,预测的可能性与训练的数据。另,xgb.train 里面需要指定maximize的值,它如果是 False ,表示自定义函数返回的值越小越好,否则就是 True。

def misclassified(pred_probs, dtrain):    labels = dtrain.get_label() # obtain true labels    preds = pred_probs > 0.5 # obtain predicted values    return 'misclassified', np.sum(labels != preds)watchlist  = [(dtest,'test'), (dtrain,'train')]# 因为 eval_metric 的默认参数是 error ,pred_probs > 0.5 是error比较多,故这个sum希望越小越好,maximize 设置为 False    bst = xgb.train(params, dtrain, num_rounds, watchlist, feval=misclassified, maximize=False)

也可以通过定义一个空的dict,保存每次训练的loss返回值

evals_result = {}bst = xgb.train(params, dtrain, num_rounds, watchlist, feval=misclassified, maximize=False, evals_result=evals_result)print(evals_result)

处理失衡的数据集

对于classification类问题,假设有2种分类,90%的数据是分类1,10%的数据是分类2,这就是原始数据失衡。它会导致预测在测试集上看起来accuracy很高(但是recall会比较低),但实际上对于分类1可能过拟合,对于分类2可能欠拟合。对于这些问题,一般处理的策略有

  • 收集更多的数据
  • 使用更好的衡量函数,而不是默认的 error,比如 AUC,F1 Score, Kappa 等
  • 增加(oversampling) 数据量少的分类的数据,减少(undersampling) 数据量多的分类的数据
    • python 可以采用类库imbalanced-learn来实现

对于xgboost算法,同时可以有如下做法:

  • 将 min_child_weight 设置得小一点,这样分类2可以有多一些节点
  • 初始化 DMatrix 时,对分类2的数据设置更高的权重
  • 通过 scale_pos_weight 控制平衡
  • 使用 AUC 来衡量最后结果

DMatrix的权重设置

可以根据分类的值,假设分类2的值是1,分类1的值是0,如下方式可以提高分类2的权重

weights = np.zeros(len(y_train))weights[y_train == 0] = 1 # 分类1weights[y_train == 1] = 5 # 分类2# 分类2的权重是分类1的5倍dtrain = xgb.DMatrix(X_train, label=y_train, weight=weights)dtest = xgb.DMatrix(X_test)

这样做,可以增加分类2的预测准确性,但是整体的accuracy和precision会降低,需要对weight放到多少调整到一个合适的值。

使用 scale_pos_weight 参数

思路就是如果分类1和2比例失调,那scale的比例取相同的值,以”纠正”这种失调

dtrain = xgb.DMatrix(X_train, label=y_train)dtest = xgb.DMatrix(X_test)train_labels = dtrain.get_label()# 失调的比例  分类1数量 / 分类2数量ratio = float(np.sum(train_labels == 0)) / np.sum(train_labels == 1)params['scale_pos_weight'] = ratiobst = xgb.train(params, dtrain, num_rounds)y_test_preds = (bst.predict(dtest) > 0.5).astype('int')pd.crosstab(    pd.Series(y_test, name='Actual'),    pd.Series(y_test_preds, name='Predicted'),    margins=True)

scale_pos_weight的效果一般会比DMatrix权重效果好,注意的是,这个方法如果和DMatrix权重的方法一起用,需要小心配置参数,否则容易用力过猛,矫枉过正。

参考列表

  • Practical XGBoost in Python
  • 官方文档
  • 接口的api定义

  1. 现在pip应该能安装了,直接 pip install xgboost 即可 ↩
原创粉丝点击