R 语言版 XGBoost 简介
简介
XGBoost 是一个优化的分布式梯度提升库,旨在实现高效率、灵活性和可移植性。它在梯度提升框架下实现了机器学习算法。XGBoost 提供了并行树提升(也称为 GBDT,GBM),能够快速准确地解决许多数据科学问题。相同的代码可以在主要的分布式环境(Hadoop、SGE、MPI)中运行,并可以解决超过数十亿样本的问题。
有关梯度提升概念的介绍,请参阅 XGBoost 在线文档中的教程《增强树简介》。
有关 XGBoost 功能和用法的更多详细信息,请参阅在线文档,其中包含更多教程、示例和详细信息。
这份简短的指南概述了 XGBoost R 接口的基本用法,假设读者对梯度提升决策树统计建模背后的基本概念有所了解。
构建预测模型
XGBoost 的核心是一个 C++ 库,它提供了不同编程语言的绑定,包括 R。XGBoost 的 R 包提供了一个惯用的接口,类似于其他使用 x/y 设计的统计建模包,以及一个更直接与底层核心库交互的低级接口,类似于 Python 等其他语言绑定,此外还有各种辅助函数,用于与其模型对象交互,例如绘制其特征重要性或将其转换为其他格式。
主要感兴趣的函数是 xgboost(x, y, ...),它对协变量/特征/预测变量“x”和响应变量“y”的观测数据调用 XGBoost 模型构建过程——对于 glmnet 或 ncvreg 等包的用户来说应该很熟悉
library(xgboost)
data(ToothGrowth)
y <- ToothGrowth$supp # the response which we want to model/predict
x <- ToothGrowth[, c("len", "dose")] # the features from which we want to predct it
model <- xgboost(x, y, nthreads = 1, nrounds = 2)
model## XGBoost model object
## Call:
##   xgboost(x = x, y = y, nrounds = 2, nthreads = 1)
## Objective: binary:logistic
## Number of iterations: 2
## Number of features: 2
## Classes: OJ, VC在此示例中,提供的“y”响应变量是具有两个类别(“OJ”和“VC”)的“因子”类型——因此,XGBoost 基于特征“x”为其构建了一个二元分类模型,通过从两个决策树(来自 nrounds=2)的总和中获得的规则桶,找到最大似然估计(类似于 R 的 glm 函数中的 family="binomial" 模型),然后我们可以从中预测概率、对数几率、最高似然类别等
predict(model, x[1:6, ], type = "response") # probabilities for y's last level ("VC")##         1         2         3         4         5         6 
## 0.6596265 0.5402158 0.6596265 0.6596265 0.6596265 0.4953500predict(model, x[1:6, ], type = "raw")      # log-odds##           1           2           3           4           5           6 
##  0.66163027  0.16121151  0.66163027  0.66163027  0.66163027 -0.01860031predict(model, x[1:6, ], type = "class")    # class with highest probability## [1] VC VC VC VC VC OJ
## Levels: OJ VC与 R 的 glm 函数(遵循 GLM 理论中的“族”和“链接”概念来拟合不同类型响应分布的模型)相比,XGBoost 遵循更简单的“目标”概念,将它们两者混合在一起,并且与 glm 一样,允许通过通用框架对非常不同类型的响应分布(例如离散选择、实值数字、计数、审查测量等)进行建模。
XGBoost 将根据响应对象的类自动确定一个合适的目标(分类可以传递因子,回归可以传递数值向量,生存分析可以传递 survival 包中的 Surv 对象等——详见 ?xgboost),但也可以通过 objective 参数根据所需的模型类型手动控制
data(mtcars)
y <- mtcars$mpg
x <- mtcars[, -1]
model_gaussian <- xgboost(x, y, nthreads = 1, nrounds = 2) # default is squared loss (Gaussian)
model_poisson <- xgboost(x, y, objective = "count:poisson", nthreads = 1, nrounds = 2)
model_abserr <- xgboost(x, y, objective = "reg:absoluteerror", nthreads = 1, nrounds = 2)注意:目标必须与“y”响应变量的类型匹配——例如,离散选择的分类目标需要“因子”类型,而实值数据的回归模型需要“数值”类型。
模型参数
XGBoost 模型允许对它们的构建方式进行高度控制。就其性质而言,梯度提升决策树集成能够捕捉数据中特征与响应变量之间非常复杂的模式,这也意味着如果控制不当,它们可能会出现过拟合。
为了获得最佳结果,需要为建模数据找到合适的参数。请注意,XGBoost 不会根据数据调整其默认超参数,并且不同的数据集将需要截然不同的超参数才能获得最佳预测性能。
例如,对于像“TootGrowth”这样只有两个特征和 60 个观测值的小数据集,XGBoost 的默认设置是过度拟合的,导致严重的过拟合——对于此类数据,人们可能希望使用更小的树(即更保守的决策规则,捕获更简单的模式)和更少的树,例如。
可以通过向 xgboost() 传递额外参数来控制参数。有关可用控制参数的详细信息,请参阅 ?xgb.params。
y <- ToothGrowth$supp
x <- ToothGrowth[, c("len", "dose")]
model_conservative <- xgboost(
    x, y, nthreads = 1,
    nrounds = 5,
    max_depth = 2,
    reg_lambda = 0.5,
    learning_rate = 0.15
)
pred_conservative <- predict(
    model_conservative,
    x
)
pred_conservative[1:6] # probabilities are all closer to 0.5 now##         1         2         3         4         5         6 
## 0.6509258 0.4822042 0.6509258 0.6509258 0.6509258 0.4477925XGBoost 还允许在提升轮次中计算模型质量的评估指标,并提供各种内置指标。可以将一部分数据自动留作评估集,然后可以从中可视化监控进度和过拟合情况
xgboost(
    x, y, nthreads = 1,
    eval_set = 0.2,
    monitor_training = TRUE,
    verbosity = 1,
    eval_metric = c("auc", "logloss"),
    nrounds = 5,
    max_depth = 2,
    reg_lambda = 0.5,
    learning_rate = 0.15
)## [1]  train-auc:0.757391  train-logloss:0.663578  eval-auc:0.757143   eval-logloss:0.676700 
## [2]  train-auc:0.757391  train-logloss:0.641348  eval-auc:0.757143   eval-logloss:0.657340 
## [3]  train-auc:0.757391  train-logloss:0.623876  eval-auc:0.757143   eval-logloss:0.641617 
## [4]  train-auc:0.757391  train-logloss:0.609999  eval-auc:0.757143   eval-logloss:0.628671 
## [5]  train-auc:0.757391  train-logloss:0.598893  eval-auc:0.757143   eval-logloss:0.617898## XGBoost model object
## Call:
##   xgboost(x = x, y = y, nrounds = 5, max_depth = 2, learning_rate = 0.15, 
##     reg_lambda = 0.5, verbosity = 1, monitor_training = TRUE, 
##     eval_set = 0.2, eval_metric = c("auc", "logloss"), nthreads = 1)
## Objective: binary:logistic
## Number of iterations: 5
## Number of features: 2
## Classes: OJ, VC检查模型对象
XGBoost 模型对象在很大程度上由指向 C++ 对象的指针组成,其中包含大部分信息,并通过包中的实用函数和方法进行接口,但它也包含一些可以通过 attributes() 检索(并添加新属性)的 R 属性
attributes(model)## $call
## xgboost(x = x, y = y, nrounds = 2, nthreads = 1)
## 
## $params
## $params$objective
## [1] "binary:logistic"
## 
## $params$nthread
## [1] 1
## 
## $params$verbosity
## [1] 0
## 
## $params$seed
## [1] 0
## 
## $params$validate_parameters
## [1] TRUE
## 
## 
## $names
## [1] "ptr"
## 
## $class
## [1] "xgboost"     "xgb.Booster"
## 
## $metadata
## $metadata$y_levels
## [1] "OJ" "VC"
## 
## $metadata$n_targets
## [1] 1除了 R 属性(可以是任意 R 对象)之外,它还可能保留一些可以访问和修改的标准化 C 级属性(但只能是 JSON 格式)
xgb.attributes(model)## list()(此模型中它们为空)
……但通常,当需要从模型对象中获取某些内容时,通常会通过内置的实用函数来完成。一些示例
xgb.importance(model)##    Feature      Gain     Cover Frequency
##     <char>     <num>     <num>     <num>
## 1:     len 0.7444265 0.6830449 0.7333333
## 2:    dose 0.2555735 0.3169551 0.2666667xgb.model.dt.tree(model)##      Tree  Node     ID Feature Split    Yes     No Missing        Gain
##     <int> <int> <char>  <char> <num> <char> <char>  <char>       <num>
##  1:     0     0    0-0     len  19.7    0-1    0-2     0-2  5.88235283
##  2:     0     1    0-1    dose   1.0    0-3    0-4     0-4  2.50230217
##  3:     0     2    0-2    dose   2.0    0-5    0-6     0-6  2.50230217
##  4:     0     3    0-3     len   8.2    0-7    0-8     0-8  5.02710962
##  5:     0     4    0-4    Leaf    NA   <NA>   <NA>    <NA>  0.36000001
##  6:     0     5    0-5    Leaf    NA   <NA>   <NA>    <NA> -0.36000001
##  7:     0     6    0-6     len  29.5    0-9   0-10    0-10  0.93020594
##  8:     0     7    0-7    Leaf    NA   <NA>   <NA>    <NA>  0.36000001
##  9:     0     8    0-8     len  10.0   0-11   0-12    0-12  0.60633492
## 10:     0     9    0-9     len  24.5   0-13   0-14    0-14  0.78028417
## 11:     0    10   0-10    Leaf    NA   <NA>   <NA>    <NA>  0.15000001
## 12:     0    11   0-11    Leaf    NA   <NA>   <NA>    <NA> -0.30000001
## 13:     0    12   0-12     len  13.6   0-15   0-16    0-16  2.92307687
## 14:     0    13   0-13    Leaf    NA   <NA>   <NA>    <NA>  0.06666667
## 15:     0    14   0-14    Leaf    NA   <NA>   <NA>    <NA> -0.17142859
## 16:     0    15   0-15    Leaf    NA   <NA>   <NA>    <NA>  0.20000002
## 17:     0    16   0-16    Leaf    NA   <NA>   <NA>    <NA> -0.30000001
## 18:     1     0    1-0     len  19.7    1-1    1-2     1-2  3.51329851
## 19:     1     1    1-1    dose   1.0    1-3    1-4     1-4  1.63309026
## 20:     1     2    1-2    dose   2.0    1-5    1-6     1-6  1.65485406
## 21:     1     3    1-3     len   8.2    1-7    1-8     1-8  3.56799269
## 22:     1     4    1-4    Leaf    NA   <NA>   <NA>    <NA>  0.28835031
## 23:     1     5    1-5    Leaf    NA   <NA>   <NA>    <NA> -0.28835031
## 24:     1     6    1-6     len  26.7    1-9   1-10    1-10  0.22153124
## 25:     1     7    1-7    Leaf    NA   <NA>   <NA>    <NA>  0.30163023
## 26:     1     8    1-8     len  11.2   1-11   1-12    1-12  0.25236940
## 27:     1     9    1-9     len  24.5   1-13   1-14    1-14  0.44972166
## 28:     1    10   1-10    Leaf    NA   <NA>   <NA>    <NA>  0.05241550
## 29:     1    11   1-11    Leaf    NA   <NA>   <NA>    <NA> -0.21860033
## 30:     1    12   1-12    Leaf    NA   <NA>   <NA>    <NA> -0.03878851
## 31:     1    13   1-13    Leaf    NA   <NA>   <NA>    <NA>  0.05559399
## 32:     1    14   1-14    Leaf    NA   <NA>   <NA>    <NA> -0.13160129
##      Tree  Node     ID Feature Split    Yes     No Missing        Gain
##         Cover
##         <num>
##  1: 15.000000
##  2:  7.500000
##  3:  7.500000
##  4:  4.750000
##  5:  2.750000
##  6:  2.750000
##  7:  4.750000
##  8:  1.500000
##  9:  3.250000
## 10:  3.750000
## 11:  1.000000
## 12:  1.000000
## 13:  2.250000
## 14:  1.250000
## 15:  2.500000
## 16:  1.250000
## 17:  1.000000
## 18: 14.695991
## 19:  7.308470
## 20:  7.387520
## 21:  4.645680
## 22:  2.662790
## 23:  2.662790
## 24:  4.724730
## 25:  1.452431
## 26:  3.193249
## 27:  2.985818
## 28:  1.738913
## 29:  1.472866
## 30:  1.720383
## 31:  1.248612
## 32:  1.737206
##         Cover其他功能
XGBoost 在其传统的梯度提升框架之上支持许多附加功能,其中包括:
- 构建具有每特征单调性约束或交互约束等特征的决策树模型。
- 计算个体预测中的特征贡献。
- 使用自定义目标和自定义评估指标。
- 拟合线性模型。
- 在 GPU 和/或不适合 RAM 的数据(“外部内存”)上拟合模型。
低级接口
除了 xgboost(x, y, ...) 函数之外,XGBoost 还通过函数 xgb.train() 提供了一个创建模型对象的低级接口,该接口类似于 XGBoost 其他语言绑定中的 xgb.train 函数。
与 xgboost() 函数接口相比,xgb.train() 接口暴露了更多功能(例如用户提供的回调或外部内存数据支持),并且执行的数据验证和类型转换更少。
两个接口之间的一些主要区别
- 与 xgboost()将 R 对象(如matrix或data.frame)作为输入不同,函数xgb.train()使用 XGBoost 自己的数据容器“DMatrix”,该容器可以通过函数xgb.DMatrix()从 R 对象创建。请注意,还有其他“DMatrix”构造函数,例如“xgb.QuantileDMatrix()”,它们可能对某些用例更有利。
- “DMatrix”对象可能包含特征/协变量、响应变量、观测权重、基本边距等混合;与 xgboost()不同,它要求其输入已经编码为 XGBoost 在幕后使用的表示形式——例如,虽然xgboost()可以将factor对象作为“y”,但xgb.DMatrix()需要将二元响应变量作为零和一的向量传递。
- 超参数在 xgboost()中作为函数参数传递,而在xgb.train()中作为命名列表传递。
- xgb.train()接口保留的输入元数据较少——例如,在调用- predict时,它不会将因子的级别作为列名添加到估计概率中。
xgb.train() 的示例用法
data("agaricus.train")
dmatrix <- xgb.DMatrix(
    data = agaricus.train$data,  # a sparse CSC matrix ('dgCMatrix')
    label = agaricus.train$label, # zeros and ones
    nthread = 1
)
booster <- xgb.train(
    data = dmatrix,
    nrounds = 10,
    params = xgb.params(
        objective = "binary:logistic",
        nthread = 1,
        max_depth = 3
    )
)
data("agaricus.test")
dmatrix_test <- xgb.DMatrix(agaricus.test$data, nthread = 1)
pred_prob <- predict(booster, dmatrix_test)
pred_raw <- predict(booster, dmatrix_test, outputmargin = TRUE)xgb.train() 产生的模型对象具有 xgb.Booster 类,而 xgboost() 产生的模型对象具有 xgboost 类,它是 xgb.Booster 的子类。它们的 predict 方法也接受不同的参数——例如,predict.xgboost 有一个 type 参数,而 predict.xgb.Booster 通过二元参数控制此功能——但由于 xgboost 是 xgb.Booster 的子类,如果需要,可以在 xgboost 对象上调用 xgb.Booster 的方法。
XGBoost R 包中的实用函数适用于两种模型类——例如
xgb.importance(model)##    Feature      Gain     Cover Frequency
##     <char>     <num>     <num>     <num>
## 1:     len 0.7444265 0.6830449 0.7333333
## 2:    dose 0.2555735 0.3169551 0.2666667xgb.importance(booster)##                            Feature         Gain        Cover  Frequency
##                             <char>        <num>        <num>      <num>
##  1:                      odor=none 0.6083687503 0.3459792871 0.16949153
##  2:                stalk-root=club 0.0959684807 0.0695742744 0.03389831
##  3:                     odor=anise 0.0645662853 0.0777761744 0.10169492
##  4:                    odor=almond 0.0542574659 0.0865120182 0.10169492
##  5:               bruises?=bruises 0.0532525762 0.0535293301 0.06779661
##  6:              stalk-root=rooted 0.0471992509 0.0610565707 0.03389831
##  7:        spore-print-color=green 0.0326096192 0.1418126308 0.16949153
##  8:                      odor=foul 0.0153302980 0.0103517575 0.01694915
##  9: stalk-surface-below-ring=scaly 0.0126892940 0.0914230316 0.08474576
## 10:                gill-size=broad 0.0066973198 0.0345993858 0.10169492
## 11:                   odor=pungent 0.0027091458 0.0032193586 0.01694915
## 12:           population=clustered 0.0025750464 0.0015616374 0.03389831
## 13:  stalk-color-below-ring=yellow 0.0016913567 0.0173903519 0.01694915
## 14:        spore-print-color=white 0.0012798160 0.0008031107 0.01694915
## 15:             gill-spacing=close 0.0008052948 0.0044110809 0.03389831虽然 xgboost() 旨在提供用户友好的接口,但在许多情况下,仍应优先选择 xgb.train() 接口——例如
- 对于对延迟敏感的应用程序(例如实时模型服务),xgb.train()将具有速度优势,因为它执行的验证、转换和元数据后处理较少。
- 如果您正在开发一个依赖 XGBoost 的 R 包,xgb.train()将提供更稳定的接口(不易发生更改),并且具有更低的时间/内存开销。
- 如果您需要 xgboost()接口未公开的功能——例如,如果您的数据集不适合计算机的 RAM,仍然可以通过xgb.ExtMemDMatrix()分批加载数据来构建 DMatrix。