跳到内容

根据 XGBoost 模型预测数据上的值。

用法

# S3 method for class 'xgb.Booster'
predict(
  object,
  newdata,
  missing = NA,
  outputmargin = FALSE,
  predleaf = FALSE,
  predcontrib = FALSE,
  approxcontrib = FALSE,
  predinteraction = FALSE,
  training = FALSE,
  iterationrange = NULL,
  strict_shape = FALSE,
  avoid_transpose = FALSE,
  validate_features = FALSE,
  base_margin = NULL,
  ...
)

参数

object

xgb.Booster 类的对象。

newdata

接受 data.frame, matrix, dgCMatrix, dgRMatrix, dsparseVector, 本地数据文件, 或 xgb.DMatrix

对于稀疏数据的单行预测,建议使用 CSR 格式。如果传入一个稀疏向量,它将被视为一个行向量。

请注意,对于对相同数据进行重复预测,您可能希望在这里创建并传入一个 DMatrix,而不是传入像矩阵或数据框这样的 R 类型,因为在 DMatrix 上预测会更快。

如果 newdata 是一个 data.frame,请注意:

  • 如果列不是数值类型,它们将被转换为数值类型,这可能会使操作比在等效的 matrix 对象中更慢。

  • 列的顺序必须与拟合模型所用数据的顺序一致(即,列不会通过名称引用,仅通过它们在数据中的顺序引用),除非传入 validate_features = TRUE(这不是默认设置)。

  • 如果模型是用包含分类列的数据拟合的,那么这里的这些列必须是 factor 类型,并且必须使用相同的编码(即,具有相同的水平)。

  • 如果 newdata 包含任何 factor 列,它们将被转换为 base-0 编码(与创建 DMatrix 期间相同) - 因此,不应在训练期间具有不同类型的列下传入 factor

  • 任何类型不是 factor 的列都将被解释为数值类型。

missing

表示数据中缺失值的浮点值(例如,0 或其他极端值)。

newdataxgb.DMatrix 时,此参数不使用 - 在这种情况下,应将其作为参数传递给 DMatrix 构造函数。

outputmargin

预测结果是否应以 Boosting 迭代结果的原始未转换预测总和的形式返回。例如,对于逻辑回归,将 outputmargin 设置为 TRUE 将返回 log-odds 而不是概率。

predleaf

是否预测每棵树的叶子索引。

predcontrib

是否返回特征对个体预测的贡献(参见详细信息)。

approxcontrib

是否使用快速近似方法计算特征贡献(参见详细信息)。

predinteraction

是否返回特征交互对个体预测的贡献(参见详细信息)。

training

预测结果是否用于训练。对于 dart booster,训练预测将执行 dropout。

iterationrange

用于预测的模型中的轮次/迭代序列,通过传入一个二维向量来指定序列中的开始和结束数字(与 R 的 seq 格式相同 - 即 base-1 索引,并且包含两端)。

例如,传入 c(1,20) 将使用前二十次迭代进行预测,而传入 c(1,1) 将仅使用第一次迭代进行预测。

如果传入 NULL,如果模型使用了早停,则将在最佳迭代处停止;否则,将使用所有迭代(轮次)。

如果传入 "all",将使用所有轮次,无论模型是否使用了早停。

不适用于 gblinear booster。

strict_shape

对于给定的预测模式,是否总是返回具有相同维度的数组,而不管模型类型如何 - 例如,多分类模型和二分类模型都将生成具有相同维数的输出数组,其中对于二分类模型,'class' 维的大小等于 '1'。

如果传入 FALSE(默认值),维度将根据模型类型进行简化,例如,二分类模型将没有多余的 'class' 维度。

有关每种预测模式下输出数组的精确形状,请参见返回类型的文档。

avoid_transpose

是否以核心 XGBoost 库生成结果预测的相同内存布局输出,而无需转置以匹配预期的输出形状。

在内部,XGBoost 使用行优先顺序生成预测,而 R 数组使用列优先顺序,因此需要对结果进行转置,以便在表示为 R 数组或矩阵时具有预期的形状,这可能是一个缓慢的操作。

如果传入 TRUE,则结果的维度将按相反的顺序排列 - 例如,行将是最后一个维度而不是第一个维度。

validate_features

TRUE 时,验证 Booster 的 feature_names 与 newdata 的 feature_names 是否匹配(仅当 objectnewdata 都有 feature_names 时适用)。

如果列名不同且 newdata 不是 xgb.DMatrix,将尝试重新排序 newdata 中的列以匹配 booster 的列。

如果 booster 具有特征类型并且 newdataxgb.DMatrixdata.frame,则将额外验证 newdata 中的分类列类型是否正确,如果不匹配则抛出错误。

如果传入 FALSE,则假定特征名称和类型相同,并且顺序与训练数据中的顺序相同。

请注意,此检查可能会给预测增加相当大的延迟,因此建议在性能敏感的应用中禁用它。

base_margin

用于从现有模型进行 Boosting 的基础边距(添加到所有观测值的原始分数,与模型中的树无关)。

如果提供,它应该是一个长度等于 newdata 行数的向量(对于每个观测值产生单个分数的 Objectives),或者是一个行数与 newdata 行数匹配、列数与模型估计分数数量匹配的矩阵(例如,多分类的类别数量)。

请注意,如果 newdataxgb.DMatrix 对象,此参数将被忽略,因为它需要添加到 DMatrix 中(例如,在构造函数中作为参数传入,或调用 setinfo.xgb.DMatrix())。

...

未使用。

返回值

一个数值向量或数组,其相应维度取决于预测模式和参数 strict_shape,具体如下:

如果传入 strict_shape=FALSE

  • 对于回归或二分类:一个长度为 nrows 的向量。

  • 对于多分类和多目标 Objectives:一个维度为 [nrows, ngroups] 的矩阵。

    请注意,Objective 变体 multi:softmax 默认倾向于预测最可能的类别(一个长度为 nrows 的向量),而不是每个类别的概率。

  • 对于 predleaf:一个每棵树有一列的矩阵。

    对于多分类/多目标,它们的排列方式是输出中的列将先是来自一个组的叶子,然后是来自另一个组的叶子(例如,顺序将是 group1:feat1group1:feat2、...、group2:feat1group2:feat2、...)。

    如果有多于一棵并行树(例如随机森林),并行树将是结果顺序中的最后一个分组,结果仍然是二维的。

  • 对于 predcontrib:当不是多分类/多目标时,一个维度为 [nrows, nfeats+1] 的矩阵。最后的 "+ 1" 列对应于基线值。

    对于多分类和多目标 Objectives,将是一个维度为 [nrows, ngroups, nfeats+1] 的数组。

    贡献值处于未转换边距的尺度(例如,对于二分类,这些值是相对于基线的 log-odds 偏差)。

  • 对于 predinteraction:当不是多分类/多目标时,输出是一个维度为 [nrows, nfeats+1, nfeats+1] 的三维数组。非对角线(在最后两个维度中)元素表示不同的特征交互贡献。该数组相对于最后两个维度是对称的。"+ 1" 列对应于基线。沿最后一个维度对该数组求和,应产生与 predcontrib = TRUE 几乎相同的结果。

    对于多分类和多目标,将是一个维度为 [nrows, ngroups, nfeats+1, nfeats+1] 的四维数组

如果传入 strict_shape=TRUE,结果始终是一个矩阵(如果是二维)或数组(如果是三维或更高)

  • 对于正常预测,维度是 [nrows, ngroups]

  • 对于 predcontrib=TRUE,维度是 [nrows, ngroups, nfeats+1]

  • 对于 predinteraction=TRUE,维度是 [nrows, ngroups, nfeats+1, nfeats+1]

  • 对于 predleaf=TRUE,维度是 [nrows, niter, ngroups, num_parallel_tree]

如果传入 avoid_transpose=TRUE,则所有情况下的维度都将按相反顺序排列 - 例如,对于 predinteraction,它们将是 [nfeats+1, nfeats+1, ngroups, nrows],而不是 [nrows, ngroups, nfeats+1, nfeats+1]

详细信息

请注意,iterationrange 目前对来自 "gblinear" 的预测不起作用,因为 "gblinear" 不保留其 boosting 历史记录。

predleaf 选项的一个可能的实际应用是将模型用作捕获非线性和交互的新特征的生成器,例如,如 xgb.create.features() 中实现的。

predcontrib = TRUE 设置为 TRUE 允许计算每个特征对个体预测的贡献。对于 "gblinear" booster,特征贡献只是线性项 (feature_beta * feature_value)。对于 "gbtree" booster,特征贡献是 SHAP 值 (Lundberg 2017),它们的总和等于模型预期输出与当前预测之间的差值(其中使用 Hessian 权重计算预期值)。设置 approxcontrib = TRUE 根据 http://blog.datadive.net/interpreting-random-forests/ 中解释的思想来近似这些值。

使用 predinteraction = TRUE 计算每对特征交互贡献的 SHAP 值。请注意,此操作在计算和内存方面可能相当昂贵。由于它与特征数量呈二次方关系,建议先执行最重要特征的选择。请参阅下面关于返回结果格式的信息。

predict() 方法使用在 xgb.Booster 对象中定义的线程数(默认为全部)。如果您想更改线程数,请使用 xgb.model.parameters<-() 将新数字分配给 nthread。请注意,将矩阵转换为 xgb.DMatrix() 也使用多个线程。

参考文献

  1. Scott M. Lundberg, Su-In Lee, "A Unified Approach to Interpreting Model Predictions", NIPS Proceedings 2017, https://arxiv.org/abs/1705.07874

  2. Scott M. Lundberg, Su-In Lee, "Consistent feature attribution for tree ensembles", https://arxiv.org/abs/1706.06060

另请参阅

示例

## binary classification:

data(agaricus.train, package = "xgboost")
data(agaricus.test, package = "xgboost")

## Keep the number of threads to 2 for examples
nthread <- 2
data.table::setDTthreads(nthread)

train <- agaricus.train
test <- agaricus.test

bst <- xgb.train(
  data = xgb.DMatrix(train$data, label = train$label, nthread = 1),
  nrounds = 5,
  params = xgb.params(
    max_depth = 2,
    nthread = nthread,
    objective = "binary:logistic"
  )
)

# use all trees by default
pred <- predict(bst, test$data)
# use only the 1st tree
pred1 <- predict(bst, test$data, iterationrange = c(1, 1))

# Predicting tree leafs:
# the result is an nsamples X ntrees matrix
pred_leaf <- predict(bst, test$data, predleaf = TRUE)
str(pred_leaf)

# Predicting feature contributions to predictions:
# the result is an nsamples X (nfeatures + 1) matrix
pred_contr <- predict(bst, test$data, predcontrib = TRUE)
str(pred_contr)
# verify that contributions' sums are equal to log-odds of predictions (up to float precision):
summary(rowSums(pred_contr) - qlogis(pred))
# for the 1st record, let's inspect its features that had non-zero contribution to prediction:
contr1 <- pred_contr[1,]
contr1 <- contr1[-length(contr1)]    # drop intercept
contr1 <- contr1[contr1 != 0]        # drop non-contributing features
contr1 <- contr1[order(abs(contr1))] # order by contribution magnitude
old_mar <- par("mar")
par(mar = old_mar + c(0,7,0,0))
barplot(contr1, horiz = TRUE, las = 2, xlab = "contribution to prediction in log-odds")
par(mar = old_mar)


## multiclass classification in iris dataset:

lb <- as.numeric(iris$Species) - 1
num_class <- 3

set.seed(11)

bst <- xgb.train(
  data = xgb.DMatrix(as.matrix(iris[, -5], nthread = 1), label = lb),
  nrounds = 10,
  params = xgb.params(
    max_depth = 4,
    nthread = 2,
    subsample = 0.5,
    objective = "multi:softprob",
    num_class = num_class
  )
)

# predict for softmax returns num_class probability numbers per case:
pred <- predict(bst, as.matrix(iris[, -5]))
str(pred)
# convert the probabilities to softmax labels
pred_labels <- max.col(pred) - 1
# the following should result in the same error as seen in the last iteration
sum(pred_labels != lb) / length(lb)

# compare with predictions from softmax:
set.seed(11)

bst <- xgb.train(
  data = xgb.DMatrix(as.matrix(iris[, -5], nthread = 1), label = lb),
  nrounds = 10,
  params = xgb.params(
    max_depth = 4,
    nthread = 2,
    subsample = 0.5,
    objective = "multi:softmax",
    num_class = num_class
  )
)

pred <- predict(bst, as.matrix(iris[, -5]))
str(pred)
all.equal(pred, pred_labels)
# prediction from using only 5 iterations should result
# in the same error as seen in iteration 5:
pred5 <- predict(bst, as.matrix(iris[, -5]), iterationrange = c(1, 5))
sum(pred5 != lb) / length(lb)