¿Cómo ajustar los hiperparámetros de los árboles xgboost?

69

Tengo una clase de datos desequilibrados y quiero ajustar los hiperparámetros del trenzado reforzado usando xgboost.

Preguntas

  1. ¿Hay un equivalente de gridsearchcv o randomsearchcv para xgboost?
  2. Si no, ¿cuál es el enfoque recomendado para ajustar los parámetros de xgboost?
GeorgeOfTheRF
fuente
Gracias pero ese enlace discute un problema diferente y no responde mi pregunta.
GeorgeOfTheRF
¿Es el nombre exacto del parámetro xgboost(max.depth)o xgb.train(max_depth)? ¿Xgboost usa inconsistentemente punto vs guión bajo para el parámetro en diferentes lugares? ¿O están convertidos?
smci
1
@smci, marque "ayuda (" xgboost-obsoleto ")"
Hemant Rupani

Respuestas:

82

Dado que la interfaz de xgboostin caretha cambiado recientemente, aquí hay un script que proporciona un tutorial completamente comentado sobre el uso caretpara ajustar xgboosthiperparámetros.

Para esto, utilizaré los datos de entrenamiento de la competencia de Kaggle "Give Me Some Credit" .

1. Ajustar un xgboostmodelo

En esta sección, nosotros:

  • ajustar un xgboostmodelo con hiperparámetros arbitrarios
  • evaluar la pérdida (AUC-ROC) utilizando validación cruzada ( xgb.cv)
  • trazar la métrica de evaluación de entrenamiento versus evaluación

Aquí hay un código para hacer esto.

library(caret)
library(xgboost)
library(readr)
library(dplyr)
library(tidyr)

# load in the training data
df_train = read_csv("04-GiveMeSomeCredit/Data/cs-training.csv") %>%
  na.omit() %>%                                                                # listwise deletion 
  select(-`[EMPTY]`) %>%
  mutate(SeriousDlqin2yrs = factor(SeriousDlqin2yrs,                           # factor variable for classification
                                   labels = c("Failure", "Success")))

# xgboost fitting with arbitrary parameters
xgb_params_1 = list(
  objective = "binary:logistic",                                               # binary classification
  eta = 0.01,                                                                  # learning rate
  max.depth = 3,                                                               # max tree depth
  eval_metric = "auc"                                                          # evaluation/loss metric
)

# fit the model with the arbitrary parameters specified above
xgb_1 = xgboost(data = as.matrix(df_train %>%
                                   select(-SeriousDlqin2yrs)),
                label = df_train$SeriousDlqin2yrs,
                params = xgb_params_1,
                nrounds = 100,                                                 # max number of trees to build
                verbose = TRUE,                                         
                print.every.n = 1,
                early.stop.round = 10                                          # stop if no improvement within 10 trees
)

# cross-validate xgboost to get the accurate measure of error
xgb_cv_1 = xgb.cv(params = xgb_params_1,
                  data = as.matrix(df_train %>%
                                     select(-SeriousDlqin2yrs)),
                  label = df_train$SeriousDlqin2yrs,
                  nrounds = 100, 
                  nfold = 5,                                                   # number of folds in K-fold
                  prediction = TRUE,                                           # return the prediction using the final model 
                  showsd = TRUE,                                               # standard deviation of loss across folds
                  stratified = TRUE,                                           # sample is unbalanced; use stratified sampling
                  verbose = TRUE,
                  print.every.n = 1, 
                  early.stop.round = 10
)

# plot the AUC for the training and testing samples
xgb_cv_1$dt %>%
  select(-contains("std")) %>%
  mutate(IterationNum = 1:n()) %>%
  gather(TestOrTrain, AUC, -IterationNum) %>%
  ggplot(aes(x = IterationNum, y = AUC, group = TestOrTrain, color = TestOrTrain)) + 
  geom_line() + 
  theme_bw()

Así es como se ve el AUC de prueba versus entrenamiento:

ingrese la descripción de la imagen aquí

2. Búsqueda de hiperparámetros usando train

Para la búsqueda de hiperparámetros, realizamos los siguientes pasos:

  • crear un data.framecon combinaciones únicas de parámetros para los que queremos modelos entrenados.
  • Especifique los parámetros de control que se aplican a la capacitación de cada modelo, incluidos los parámetros de validación cruzada, y especifique que se calculen las probabilidades para que se pueda calcular el AUC
  • validar y entrenar los modelos para cada combinación de parámetros, guardando el AUC para cada modelo.

Aquí hay un código que muestra cómo hacer esto.

# set up the cross-validated hyper-parameter search
xgb_grid_1 = expand.grid(
  nrounds = 1000,
  eta = c(0.01, 0.001, 0.0001),
  max_depth = c(2, 4, 6, 8, 10),
  gamma = 1
)

# pack the training control parameters
xgb_trcontrol_1 = trainControl(
  method = "cv",
  number = 5,
  verboseIter = TRUE,
  returnData = FALSE,
  returnResamp = "all",                                                        # save losses across all models
  classProbs = TRUE,                                                           # set to TRUE for AUC to be computed
  summaryFunction = twoClassSummary,
  allowParallel = TRUE
)

# train the model for each parameter combination in the grid, 
#   using CV to evaluate
xgb_train_1 = train(
  x = as.matrix(df_train %>%
                  select(-SeriousDlqin2yrs)),
  y = as.factor(df_train$SeriousDlqin2yrs),
  trControl = xgb_trcontrol_1,
  tuneGrid = xgb_grid_1,
  method = "xgbTree"
)

# scatter plot of the AUC against max_depth and eta
ggplot(xgb_train_1$results, aes(x = as.factor(eta), y = max_depth, size = ROC, color = ROC)) + 
  geom_point() + 
  theme_bw() + 
  scale_size_continuous(guide = "none")

Por último, puede crear un diagrama de burbujas para el AUC sobre las variaciones de etay max_depth:

ingrese la descripción de la imagen aquí

tchakravarty
fuente
¿Caret todavía solo admite eta, gamma y profundidad máxima para la búsqueda de cuadrícula, qué pasa con la submuestra y otros parámetros de xgboost?
GeorgeOfTheRF
2
@ML_Pro El soporte para la mayoría de los xgboostparámetros ahora existe, en particular el soporte para gammaes nuevo. Aquí hay una lista completa de los parámetros admitidos.
tchakravarty
Ese es el soporte de xgboost ¿verdad? Mi pregunta es sobre qué parámetros son compatibles con la búsqueda en la cuadrícula
GeorgeOfTheRF
1
¿Cuáles serían los cambios necesarios para la clasificación multiclase? También la documentación dice uso scale_pose_weightpara clasificación desequilibrada. ¿Puede proporcionar detalles sobre cómo hacerlo? ¡Gracias!
discipulus
1
Para el problema de la clase no balanceada, scale_pos_weightahora está documentado en la documentación del parámetro . scale_pos_weightno es un parámetro de ajuste de intercalación, pero puede compararlo manualmente. En mi caso, usar el peso tuvo poco efecto (clasificación binaria,> 20% de resultados positivos)
geneorama
24

El paquete Caret ha incorporado xgboost.

cv.ctrl <- trainControl(method = "repeatedcv", repeats = 1,number = 3, 
                        #summaryFunction = twoClassSummary,
                        classProbs = TRUE,
                        allowParallel=T)

    xgb.grid <- expand.grid(nrounds = 1000,
                            eta = c(0.01,0.05,0.1),
                            max_depth = c(2,4,6,8,10,14)
    )
    set.seed(45)
    xgb_tune <-train(formula,
                     data=train,
                     method="xgbTree",
                     trControl=cv.ctrl,
                     tuneGrid=xgb.grid,
                     verbose=T,
                     metric="Kappa",
                     nthread =3
    )

Salida de muestra

eXtreme Gradient Boosting 

32218 samples
   41 predictor
    2 classes: 'N', 'Y' 

No pre-processing
Resampling: Cross-Validated (3 fold, repeated 1 times) 
Summary of sample sizes: 21479, 21479, 21478 
Resampling results

  Accuracy   Kappa      Accuracy SD   Kappa SD   
  0.9324911  0.1094426  0.0009742774  0.008972911

Un inconveniente que veo es que otros parámetros de xgboost como la submuestra, etc., no son compatibles con caret actualmente.

Editar

Gamma, colsample_bytree, min_child_weight y subsample, etc. ahora se pueden ajustar directamente (junio de 2017) utilizando Caret. Simplemente agréguelos en la parte de la cuadrícula del código anterior para que funcione. Gracias usεr11852 por resaltarlo en el comentario.

GeorgeOfTheRF
fuente
44
Una actualización menor con respecto al inconveniente mencionado. caretahora (-2017 febrero) soporta parámetros adicionales para gamma, colsample_bytree, min_child_weighty subsample. (Así que efectivamente puede sintonizar casi todo - tiempo dado)
ussr11852 dice Reinstate Monic
10

Sé que esta es una vieja pregunta, pero uso un método diferente de los anteriores. Utilizo la función BayesianOptimization del paquete Bayesian Optimization para encontrar parámetros óptimos. Para hacer esto, primero cree pliegues de validación cruzada, luego cree una función xgb.cv.bayesque tenga como parámetros los hiperparámetros de impulso que desea cambiar. En este ejemplo estoy sintonizando max.depth, min_child_weight, subsample, colsample_bytree, gamma. Luego llama xgb.cva esa función con los hiperparámetros establecidos en los parámetros de entrada de xgb.cv.bayes. Luego llama BayesianOptimizationcon los xgb.cv.bayesrangos deseados de los hiperparámetros de refuerzo. init_pointses el número de modelos iniciales con hiperparámetros tomados al azar de los rangos especificados, yn_iteres el número de rondas de modelos después de los puntos iniciales. La función genera todos los parámetros de refuerzo y el AUC de prueba.

cv_folds <- KFold(as.matrix(df.train[,target.var]), nfolds = 5, 
                  stratified = TRUE, seed = 50)
xgb.cv.bayes <- function(max.depth, min_child_weight, subsample, colsample_bytree, gamma){
  cv <- xgv.cv(params = list(booster = 'gbtree', eta = 0.05,
                             max_depth = max.depth,
                             min_child_weight = min_child_weight,
                             subsample = subsample,
                             colsample_bytree = colsample_bytree,
                             gamma = gamma,
                             lambda = 1, alpha = 0,
                             objective = 'binary:logistic',
                             eval_metric = 'auc'),
                 data = data.matrix(df.train[,-target.var]),
                 label = as.matrix(df.train[, target.var]),
                 nround = 500, folds = cv_folds, prediction = TRUE,
                 showsd = TRUE, early.stop.round = 5, maximize = TRUE,
                 verbose = 0
  )
  list(Score = cv$dt[, max(test.auc.mean)],
       Pred = cv$pred)
}

xgb.bayes.model <- BayesianOptimization(
  xgb.cv.bayes,
  bounds = list(max.depth = c(2L, 12L),
                min_child_weight = c(1L, 10L),
                subsample = c(0.5, 1),
                colsample_bytree = c(0.1, 0.4),
                gamma = c(0, 10)
  ),
  init_grid_dt = NULL,
  init_points = 10,  # number of random points to start search
  n_iter = 20, # number of iterations after initial random points are set
  acq = 'ucb', kappa = 2.576, eps = 0.0, verbose = TRUE
)
Bryan Schwimmer
fuente
1
Este es un buen enfoque, pero hay una advertencia : el paquete R rBayesianOptimization, a partir de la última versión CRAN 1.1.0 (que no se ha actualizado en más de 2 años), no tiene pruebas y una licencia más restrictiva que Python paquete por los autores originales del método, que tiene pruebas. Consulte github.com/fmfn/BayesianOptimization .
Egnha
8

Esta es una pregunta anterior, pero pensé que compartiría cómo ajusto los parámetros de xgboost. Originalmente pensé que usaría caret para esto, pero recientemente encontré un problema para manejar todos los parámetros, así como los valores faltantes. También estaba considerando escribir un ciclo iterativo a través de diferentes combinaciones de parámetros, pero quería que se ejecutara en paralelo y requeriría demasiado tiempo. El uso de gridSearch del paquete NMOF proporcionó lo mejor de ambos mundos (todos los parámetros, así como el procesamiento paralelo). Aquí hay un código de ejemplo para la clasificación binaria (funciona en Windows y Linux):

# xgboost task parameters
nrounds <- 1000
folds <- 10
obj <- 'binary:logistic'
eval <- 'logloss'

# Parameter grid to search
params <- list(
  eval_metric = eval,
  objective = obj,
  eta = c(0.1,0.01),
  max_depth = c(4,6,8,10),
  max_delta_step = c(0,1),
  subsample = 1,
  scale_pos_weight = 1
)

# Table to track performance from each worker node
res <- data.frame()

# Simple cross validated xgboost training function (returning minimum error for grid search)
xgbCV <- function (params) {
  fit <- xgb.cv(
    data = data.matrix(train), 
    label = trainLabel, 
    param =params, 
    missing = NA, 
    nfold = folds, 
    prediction = FALSE,
    early.stop.round = 50,
    maximize = FALSE,
    nrounds = nrounds
  )
  rounds <- nrow(fit)
  metric = paste('test.',eval,'.mean',sep='')
  idx <- which.min(fit[,fit[[metric]]]) 
  val <- fit[idx,][[metric]]
  res <<- rbind(res,c(idx,val,rounds))
  colnames(res) <<- c('idx','val','rounds')
  return(val)
}

# Find minimal testing error in parallel
cl <- makeCluster(round(detectCores()/2)) 
clusterExport(cl, c("xgb.cv",'train','trainLabel','nrounds','res','eval','folds'))
sol <- gridSearch(
  fun = xgbCV,
  levels = params,
  method = 'snow',
  cl = cl,
  keepNames = TRUE,
  asList = TRUE
)

# Combine all model results
comb=clusterEvalQ(cl,res)
results <- ldply(comb,data.frame)
stopCluster(cl)

# Train model given solution above
params <- c(sol$minlevels,objective = obj, eval_metric = eval)
xgbModel <- xgboost(
  data = xgb.DMatrix(data.matrix(train),missing=NaN, label = trainLabel),
  param = params,
  nrounds = results[which.min(results[,2]),1]
)

print(params)
print(results)
John Richardson
fuente