Wie werden Hyperparameter von xgboost-Bäumen optimiert?

68

Ich habe klassenunausgeglichene Daten und möchte die Hyperparameter der verstärkten Locke mit xgboost optimieren.

Fragen

  1. Gibt es für xgboost ein Äquivalent zu gridsearchcv oder randomsearchcv?
  2. Wenn nicht, was ist der empfohlene Ansatz, um die Parameter von xgboost zu optimieren?
GeorgeOfTheRF
quelle
Danke, aber dieser Link behandelt ein anderes Problem und beantwortet meine Frage nicht.
GeorgeOfTheRF
Ist die genaue Bezeichnung des Parameters xgboost(max.depth)oder xgb.train(max_depth)? Verwendet xgboost uneinheitlich Punkt-gegen-Unterstrich für den Parameter an verschiedenen Stellen? Oder sind sie konvertiert?
smci
1
@smci, check "help (" xgboost-deprecated ")"
Hemant Rupani

Antworten:

82

Da sich die Benutzeroberfläche von xgboostin caretkürzlich geändert hat, finden Sie hier ein Skript, das eine vollständig kommentierte exemplarische Vorgehensweise caretzum Einstellen von xgboostHyperparametern enthält.

Dazu verwende ich die Trainingsdaten des Kaggle-Wettbewerbs "Give Me Some Credit" .

1. Ein xgboostModell montieren

In diesem Abschnitt werden wir:

  • Passen Sie ein xgboostModell mit beliebigen Hyperparametern an
  • Bewertung des Verlusts (AUC-ROC) mittels Kreuzvalidierung ( xgb.cv)
  • Zeichnen Sie das Training in Abhängigkeit von der Testbewertungsmetrik

Hier ist ein Code, um dies zu tun.

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

So sieht das Testen im Vergleich zur Trainings-AUC aus:

Bildbeschreibung hier eingeben

2. Hyperparametersuche mit train

Für die Hyperparametersuche führen wir folgende Schritte durch:

  • Erstellen Sie eine data.framemit einzigartigen Kombinationen von Parametern, für die wir trainierte Modelle benötigen.
  • Geben Sie die Steuerparameter an, die für das Training jedes Modells gelten, einschließlich der Kreuzvalidierungsparameter, und geben Sie an, dass die Wahrscheinlichkeiten berechnet werden, damit die AUC berechnet werden kann
  • Überprüfen und trainieren Sie die Modelle für jede Parameterkombination und speichern Sie die AUC für jedes Modell.

Hier ist ein Code, der zeigt, wie das geht.

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

Zuletzt können Sie einen Bubbleplot für die AUC über die Variationen von etaund erstellen max_depth:

Bildbeschreibung hier eingeben

tchakravarty
quelle
Unterstützt Caret immer noch nur Eta, Gamma und Max. Tiefe für die Rastersuche?
GeorgeOfTheRF
2
@ML_Pro Unterstützung für die meisten xgboostParameter ist jetzt vorhanden, insbesondere Unterstützung für gammaist neu. Hier ist eine vollständige Liste der unterstützten Parameter.
Tschakravarty
Das ist doch Unterstützung durch xgboost oder? Meine Frage ist, über welche Parameter Caret-Unterstützung für die
Rastersuche
1
Welche Änderungen wären für die Klassifizierung mehrerer Klassen erforderlich? In der Dokumentation wird auch die Verwendung scale_pose_weightfür eine unausgewogene Klassifizierung angegeben. Können Sie nähere Angaben dazu machen? Vielen Dank!
Discipulus
1
Für das Problem mit unausgeglichenen Klassen scale_pos_weightwird jetzt in der Parameterdokumentation dokumentiert . scale_pos_weightist kein Caret-Tuning-Parameter, kann aber manuell verglichen werden. In meinem Fall hatte die Verwendung des Gewichts nur geringe Auswirkungen (binäre Klassifizierung,> 20% Positiv)
geneorama
24

Caret-Paket haben xgboost integriert.

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
    )

Beispielausgabe

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

Ein Nachteil, den ich sehe, ist, dass andere Parameter von xgboost wie Subsample usw. derzeit von Caret nicht unterstützt werden.

Bearbeiten

Gamma, colsample_bytree, min_child_weight und subsample etc können jetzt (Juni 2017) direkt mit Caret eingestellt werden. Fügen Sie sie einfach in den Rasterabschnitt des obigen Codes ein, damit es funktioniert. Vielen Dank an usεr11852 für die Hervorhebung im Kommentar.

GeorgeOfTheRF
quelle
4
Ein kleines Update bezüglich des genannten Nachteils. caretJetzt (Feb-2017) unterstützt zusätzliche Parameter gamma, colsample_bytree, min_child_weightund subsample. (So ​​effektiv können Sie fast alles stimmen - gegebene Zeit)
usεr11852 sagt Reinstate Monic
10

Ich weiß, dass dies eine alte Frage ist, aber ich verwende eine andere Methode als die oben genannten. Ich benutze die BayesianOptimization-Funktion aus dem Bayesian Optimization-Paket, um optimale Parameter zu finden. Dazu erstellen Sie zunächst Kreuzvalidierungsfalten und anschließend eine Funktion xgb.cv.bayes, deren Parameter die zu ändernden verstärkenden Hyperparameter enthalten. In diesem Beispiel stimme ich max.depth, min_child_weight, subsample, colsample_bytree, gamma. Diese xgb.cvFunktion rufen Sie dann mit den in den Eingabeparametern von eingestellten Hyperparametern auf xgb.cv.bayes. Dann rufst du BayesianOptimizationmit xgb.cv.bayesund die gewünschten Bereiche der aufsteigenden Hyperparameter auf. init_pointsist die Anzahl der anfänglichen Modelle mit zufällig ausgewählten Hyperparametern aus den angegebenen Bereichenn_iterist die Anzahl der Runden von Modellen nach den Anfangspunkten. Die Funktion gibt alle Boosting-Parameter und die Test-AUC aus.

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
quelle
1
Dies ist ein guter Ansatz, aber es gibt eine Einschränkung : Das R-Paket rBayesianOptimization verfügt ab der neuesten CRAN-Version 1.1.0 (die seit über 2 Jahren nicht aktualisiert wurde) über keine Tests und eine restriktivere Lizenz als das Python Paket von den ursprünglichen Autoren der Methode, die Tests hat. Siehe github.com/fmfn/BayesianOptimization .
Egnha
8

Dies ist eine ältere Frage, aber ich dachte, ich würde teilen, wie ich xgboost-Parameter abstimme. Ursprünglich dachte ich, ich würde Caret dafür verwenden, fand aber kürzlich ein Problem bei der Behandlung aller Parameter sowie fehlender Werte. Ich habe auch darüber nachgedacht, eine Iterationsschleife durch verschiedene Parameterkombinationen zu schreiben, wollte aber, dass sie parallel abläuft und zu viel Zeit benötigt. Die Verwendung von gridSearch aus dem NMOF-Paket bot das Beste aus beiden Welten (alle Parameter sowie Parallelverarbeitung). Hier ist ein Beispielcode für die Binärklassifizierung (funktioniert unter Windows und 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
quelle