Como ajustar os hiperparâmetros das árvores xgboost?

68

Eu tenho dados de desequilíbrio de classe e quero ajustar os hiperparâmetros da trança impulsionada usando xgboost.

Questões

  1. Existe um equivalente de gridsearchcv ou randomsearchcv para xgboost?
  2. Caso contrário, qual é a abordagem recomendada para ajustar os parâmetros do xgboost?
GeorgeOfTheRF
fonte
Obrigado, mas esse link discute uma questão diferente e não responde à minha pergunta.
GeorgeOfTheRF 12/09
A nomeação exata do parâmetro xgboost(max.depth)ou xgb.train(max_depth)? O xgboost usa inconsistentemente ponto vs sublinhado para o parâmetro em lugares diferentes? Ou eles são convertidos?
SMCI
11
@smci, marque "help (" xgboost-obsoleto ")"
Hemant

Respostas:

82

Como a interface para xgboostin caretfoi alterada recentemente, eis um script que fornece uma explicação totalmente comentada do uso caretpara ajustar xgboosthiperparâmetros.

Para isso, usarei os dados de treinamento da competição Kaggle "Give Me Some Credit" .

1. Ajustando um xgboostmodelo

Nesta seção, nós:

  • ajustar um xgboostmodelo com hiperparâmetros arbitrários
  • avaliar a perda (AUC-ROC) usando validação cruzada ( xgb.cv)
  • traçar a métrica de avaliação de treinamento versus teste

Aqui está um código para fazer isso.

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()

Aqui está a aparência da AUC de teste versus treinamento:

insira a descrição da imagem aqui

2. Pesquisa por hiperparâmetro usando train

Para a pesquisa de hiperparâmetros, executamos as seguintes etapas:

  • crie uma data.framecombinação única de parâmetros para a qual queremos modelos treinados.
  • Especifique os parâmetros de controle que se aplicam ao treinamento de cada modelo, incluindo os parâmetros de validação cruzada, e especifique que as probabilidades sejam computadas para que a AUC possa ser calculada
  • validar e treinar os modelos para cada combinação de parâmetros, salvando a AUC para cada modelo.

Aqui está um código que mostra como fazer isso.

# 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 fim, você pode criar um gráfico de bolhas para a AUC sobre as variações etae max_depth:

insira a descrição da imagem aqui

tchakravarty
fonte
O cursor ainda suporta apenas eta, gama e profundidade máxima para pesquisa em grade, e a subamostra e outros parâmetros do xgboost?
GeorgeOfTheRF
2
O @ML_Pro xgboostjá existe suporte para a maioria dos parâmetros, em particular o suporte para gammaé novo. Aqui está uma lista completa dos parâmetros suportados.
Tchakravarty
Esse é o suporte do xgboost, certo? A minha pergunta é sobre o qual todos os parâmetros são compatíveis com acento circunflexo para a busca de grade
GeorgeOfTheRF
11
Quais seriam as alterações necessárias para a classificação multiclasse. Também a documentação diz uso scale_pose_weightpara classificação desequilibrada. Você pode fornecer detalhes sobre como? Obrigado!
discipulus
11
Para o problema de classe desequilibrada, scale_pos_weightagora está documentado na documentação dos parâmetros . scale_pos_weightnão é um parâmetro de ajuste de cursor, mas você pode comparar manualmente. No meu caso, usando o peso passou a ter pouco efeito (classificação binária,> 20% de positivos)
geneorama
24

O pacote Caret incorporou o 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
    )

Saída de amostra

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

Uma desvantagem que vejo é que outros parâmetros do xgboost, como a subamostra, etc, não são suportados pelo sinal de intercalação atualmente.

Editar

Agora, gama, colsample_bytree, min_child_weight e subamostra etc (junho de 2017) podem ser ajustados diretamente usando Caret. Basta adicioná-los na parte da grade do código acima para fazê-lo funcionar. Obrigado usεr11852 por destacá-lo no comentário.

GeorgeOfTheRF
fonte
4
Uma pequena atualização sobre a desvantagem mencionada. caretagora (Fev-2017) suporta parâmetros adicionais para gamma, colsample_bytree, min_child_weighte subsample. (De maneira eficaz, você pode ajustar quase tudo - dado tempo)
usεr11852 diz Reinstate Monic
10

Sei que essa é uma pergunta antiga, mas uso um método diferente dos acima. Eu uso a função BayesianOptimization do pacote Bayesian Optimization para encontrar parâmetros ideais. Para fazer isso, primeiro crie dobras de validação cruzada e, em seguida, crie uma função xgb.cv.bayesque tenha como parâmetros os hiper parâmetros de aumento que você deseja alterar. Neste exemplo, estou afinando max.depth, min_child_weight, subsample, colsample_bytree, gamma. Você então chama xgb.cvessa função com os hiper parâmetros configurados nos parâmetros de entrada de xgb.cv.bayes. Então você chama BayesianOptimizationcom os xgb.cv.bayesintervalos desejados e os hiper parâmetros de aumento. init_pointsé o número de modelos iniciais com hiper parâmetros obtidos aleatoriamente nos intervalos especificados en_iteré o número de rodadas de modelos após os pontos iniciais. A função gera todos os parâmetros de reforço e a AUC de teste.

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
fonte
11
Essa é uma boa abordagem, mas há uma ressalva : o pacote R rBayesianOptimization, a partir da versão mais recente do CRAN 1.1.0 (que não foi atualizada em mais de 2 anos), não possui testes e uma licença mais restritiva que o Python pacote pelos autores originais do método, que possui testes. Consulte github.com/fmfn/BayesianOptimization .
egnha
8

Esta é uma pergunta mais antiga, mas pensei em compartilhar como ajustar os parâmetros do xgboost. Originalmente, pensei em usar o sinal de intercalação para isso, mas recentemente encontrei um problema ao lidar com todos os parâmetros e valores ausentes. Eu também estava pensando em escrever um loop iterativo através de diferentes combinações de parâmetros, mas queria que ele fosse executado em paralelo e exigiria muito tempo. O uso do gridSearch do pacote NMOF forneceu o melhor dos dois mundos (todos os parâmetros e também o processamento paralelo). Aqui está um código de exemplo para classificação binária (funciona no Windows e 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
fonte