Come ottimizzare gli iperparametri degli alberi xgboost?


69

Ho una classe di dati sbilanciati e voglio sintonizzare gli iperparametri della treccia potenziata usando xgboost.

Domande

  1. Esiste un equivalente di gridsearchcv o randomsearchcv per xgboost?
  2. In caso contrario, qual è l'approccio raccomandato per ottimizzare i parametri di xgboost?


Grazie ma quel link discute un problema diverso e non risponde alla mia domanda.
GeorgeOfTheRF,

La denominazione esatta del parametro xgboost(max.depth)o xgb.train(max_depth)? Xgboost utilizza in modo incoerente punto vs trattino basso per il parametro in luoghi diversi? O sono convertiti?
smci,

1
@smci, controlla "help (" xgboost-deprecated ")"
Hemant Rupani,

Risposte:


82

Da quando l'interfaccia a xgboostin caretè stata recentemente modificata, ecco uno script che fornisce una descrizione completa dell'uso caretdi come ottimizzare xgboosti parametri.

Per questo, userò i dati di allenamento del concorso Kaggle "Give Me Some Credit" .

1. Montaggio di un xgboostmodello

In questa sezione, noi:

  • misura un xgboostmodello con iperparametri arbitrari
  • valutare la perdita (AUC-ROC) usando la validazione incrociata ( xgb.cv)
  • tracciare la formazione rispetto alla metrica di valutazione dei test

Ecco un po 'di codice per farlo.

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

Ecco come si presentano i test rispetto alla formazione AUC:

inserisci qui la descrizione dell'immagine

2. Ricerca dell'iperparametro mediante train

Per la ricerca dell'iperparametro, eseguiamo i seguenti passaggi:

  • creare una data.framecombinazione unica di parametri per i quali vogliamo modelli addestrati.
  • Specificare i parametri di controllo che si applicano all'addestramento di ciascun modello, inclusi i parametri di convalida incrociata, e specificare che le probabilità devono essere calcolate in modo che l'AUC possa essere calcolata
  • convalidare in modo incrociato e addestrare i modelli per ciascuna combinazione di parametri, salvando l'AUC per ciascun modello.

Ecco un po 'di codice che mostra come farlo.

# 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")

Infine, è possibile creare un grafico a bolle per l'AUC sulle varianti di etae max_depth:

inserisci qui la descrizione dell'immagine


Caret supporta ancora solo eta, gamma e profondità massima per la ricerca in griglia e per quanto riguarda il sottocampione e altri parametri di xgboost?
GeorgeOfTheRF,

2
@ML_Pro Il supporto per la maggior parte dei xgboostparametri ora esiste, in particolare il supporto per gammaè nuovo. Ecco un elenco completo dei parametri supportati.
Tchakravarty,

Questo è il supporto di xgboost giusto? La mia domanda riguarda quali sono tutti i parametri che supportano il caret per la ricerca della griglia
GeorgeOfTheRF

1
Quali sarebbero le modifiche necessarie per la classificazione multiclasse. Anche la documentazione dice l'uso scale_pose_weightper la classificazione sbilanciata. Potete fornire dettagli su come? Grazie!
discipulus,

1
Per il problema della classe sbilanciata, scale_pos_weightè ora documentato nella documentazione dei parametri . scale_pos_weightnon è un parametro di regolazione del punto di inserimento, ma puoi confrontare manualmente. Nel mio caso, l'uso del peso ha avuto scarso effetto (classificazione binaria,> 20% di positivi)
geneorama

24

Il pacchetto Caret ha incorporato 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
    )

Uscita campione

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

Uno svantaggio che vedo è che altri parametri di xgboost come il sottocampione ecc. Non sono attualmente supportati dal cursore.

modificare

Gamma, colsample_bytree, min_child_weight e subsample ecc. Ora possono essere sintonizzati direttamente (giugno 2017) usando Caret. Basta aggiungerli nella parte griglia del codice sopra per farlo funzionare. Grazie usεr11852 per averlo evidenziato nel commento.


4
Un aggiornamento minore per quanto riguarda lo svantaggio menzionato. caretora (Feb-2017) supporta i parametri aggiuntivi per gamma, colsample_bytree, min_child_weighte subsample. (Così efficacemente puoi sintonizzare quasi tutto - dato il tempo)
usεr11852 dice Reinstate Monic il

10

So che questa è una vecchia domanda, ma uso un metodo diverso da quelli sopra. Uso la funzione BayesianOptimization dal pacchetto Bayesian Optimization per trovare parametri ottimali. Per fare ciò, devi prima creare pieghe incrociate di convalida, quindi creare una funzione xgb.cv.bayesche abbia come parametri i parametri di potenziamento dell'ipermetro che desideri modificare. In questo esempio sto sintonizzando max.depth, min_child_weight, subsample, colsample_bytree, gamma. Quindi si chiama xgb.cvquella funzione con i parametri iper impostati su nei parametri di input di xgb.cv.bayes. Quindi si chiama BayesianOptimizationcon xgb.cv.bayese gli intervalli desiderati dei parametri iper boost. init_pointsè il numero di modelli iniziali con iper parametri presi casualmente dagli intervalli specificati en_iterè il numero di round di modelli dopo i punti iniziali. La funzione emette tutti i parametri di potenziamento e l'AUC di prova.

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
)

1
Questo è un buon approccio, ma c'è un avvertimento : il pacchetto R rBayesianOptimization, a partire dall'ultima versione CRAN 1.1.0 (che non è stata aggiornata da oltre 2 anni), non ha test e una licenza più restrittiva rispetto a Python pacchetto dagli autori originali del metodo, che ha test. Vedi github.com/fmfn/BayesianOptimization .
egnha,

8

Questa è una domanda più vecchia, ma ho pensato di condividere il modo in cui ottimizzo i parametri di xgboost. Inizialmente pensavo che avrei usato il cursore per questo, ma recentemente ho riscontrato un problema nella gestione di tutti i parametri e dei valori mancanti. Stavo anche pensando di scrivere un ciclo iterativo attraverso diverse combinazioni di parametri, ma volevo che funzionasse in parallelo e richiederebbe troppo tempo. L'uso di gridSearch dal pacchetto NMOF ha offerto il meglio da entrambi i mondi (tutti i parametri e l'elaborazione parallela). Ecco un esempio di codice per la classificazione binaria (funziona su 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)
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.