Jak dostroić hiperparametry drzew xgboost?

68

Mam dane niezrównoważone w klasie i chcę dostroić hiperparametry wzmocnionego warkocza za pomocą xgboost.

pytania

  1. Czy istnieje odpowiednik gridsearchcv lub randomsearchcv dla xgboost?
  2. Jeśli nie, jakie jest zalecane podejście do dostrojenia parametrów xgboost?
GeorgeOfTheRF
źródło
Dzięki, ale ten link omawia inny problem i nie odpowiada na moje pytanie.
GeorgeOfTheRF
Czy dokładne nazywanie parametru xgboost(max.depth)lub xgb.train(max_depth)? Czy xgboost niekonsekwentnie używa kropki vs podkreślenia dla parametru w różnych miejscach? A może są nawróceni?
smci
1
@smci, zaznacz „help (” xgboost-deprecated ”)”
Hemant Rupani

Odpowiedzi:

82

Ponieważ interfejs do xgboostw caretniedawno się zmienił, oto skrypt, który zapewnia w pełni skomentowane wprowadzenie caretdo dostrojenia xgboosthiperparametrów.

W tym celu wykorzystam dane treningowe z konkursu Kaggle „Daj mi trochę uznania .

1. Montaż xgboostmodelu

W tej sekcji:

  • dopasuj xgboostmodel z dowolnymi hiperparametrami
  • oszacuj stratę (AUC-ROC) za pomocą walidacji krzyżowej ( xgb.cv)
  • wykreślić metrykę oceny szkolenia i testowania

Oto kod, aby to zrobić.

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

Oto, jak wygląda AUC testowania w porównaniu do treningu:

wprowadź opis zdjęcia tutaj

2. Wyszukiwanie hiperparametrów za pomocą train

W celu wyszukiwania hiperparametrów wykonujemy następujące kroki:

  • stworzyć data.frameunikalną kombinację parametrów, dla których chcemy wyszkolonych modeli.
  • Określ parametry kontrolne, które mają zastosowanie do szkolenia każdego modelu, w tym parametry walidacji krzyżowej i określ, że prawdopodobieństwa mają być obliczone, aby można było obliczyć AUC
  • sprawdzaj krzyżowo i trenuj modele dla każdej kombinacji parametrów, oszczędzając AUC dla każdego modelu.

Oto kod, który pokazuje, jak to zrobić.

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

Na koniec możesz utworzyć wykres bąbelkowy dla AUC dla odmian etai max_depth:

wprowadź opis zdjęcia tutaj

tchakravarty
źródło
Czy Caret nadal obsługuje tylko eta, gamma i maksymalną głębokość dla wyszukiwania siatki, co z podpróbką i innymi parametrami xgboost?
GeorgeOfTheRF
2
@ML_Pro Wsparcie dla większości xgboostparametrów już istnieje, w szczególności wsparcie gammajest nowe. Oto pełna lista obsługiwanych parametrów.
tchakravarty
To jest wsparcie xgboost, prawda? Moje pytanie dotyczy tego, które wszystkie parametry obsługują wyszukiwanie sieci
GeorgeOfTheRF
1
Jakie byłyby zmiany wymagane do klasyfikacji wieloklasowej. Również dokumentacja mówi o zastosowaniu scale_pose_weightdo niezrównoważonej klasyfikacji. Czy możesz podać szczegółowe informacje? Dzięki!
discipulus
1
W przypadku problemu z niewyważeniem klasy scale_pos_weightjest teraz udokumentowany w dokumentacji parametrów . scale_pos_weightnie jest parametrem dostrajania daszka, ale można porównać ręcznie. W moim przypadku użycie wagi
okazało
24

Pakiet Caret zawiera 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
    )

Próbka wyjściowa

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

Jedną wadą jest to, że inne parametry xgboost, takie jak podpróbka itp., Nie są obecnie obsługiwane przez daszek.

Edytować

Gamma, colsample_bytree, min_child_weight i podpróbka itp. Można teraz dostroić bezpośrednio (czerwiec 2017) za pomocą Caret. Wystarczy dodać je w części powyższego kodu, aby działało. Dziękujemy usεr11852 za ​​wyróżnienie go w komentarzu.

GeorgeOfTheRF
źródło
4
Drobna aktualizacja dotycząca wspomnianej wady. caretteraz (Feb-2017) obsługuje dodatkowych parametrów gamma, colsample_bytree, min_child_weighti subsample. (Tak skutecznie można dostroić prawie wszystko - w określonym czasie)
usεr11852
10

Wiem, że to stare pytanie, ale używam innej metody niż powyższe. Korzystam z funkcji BayesianOptimization z pakietu Bayesian Optimization, aby znaleźć optymalne parametry. Aby to zrobić, najpierw tworzysz fałdy krzyżowej weryfikacji, a następnie tworzysz funkcję, xgb.cv.bayesktóra ma parametry zwiększające parametry hiperłącza, które chcesz zmienić. W tym przykładzie dostrajam max.depth, min_child_weight, subsample, colsample_bytree, gamma. Następnie wywołujesz xgb.cvtę funkcję z parametrami hiper ustawionymi na parametry wejściowe parametru xgb.cv.bayes. Następnie wywołujesz BayesianOptimizationz xgb.cv.bayesi pożądanymi zakresami hiper parametrów podwyższających. init_pointsoznacza liczbę modeli początkowych z hiperparametrami pobranymi losowo z określonych zakresów, orazn_iterto liczba rund modeli po punktach początkowych. Funkcja generuje wszystkie parametry podwyższające i AUC testowe.

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
źródło
1
Jest to dobre podejście, ale jest pewne zastrzeżenie : pakiet R rBayesianOptimization, od najnowszej wersji CRAN 1.1.0 (która nie była aktualizowana od ponad 2 lat), nie ma testów i bardziej restrykcyjnej licencji niż Python pakiet oryginalnych autorów metody, która ma testy. Zobacz github.com/fmfn/BayesianOptimization .
egnha
8

To jest starsze pytanie, ale pomyślałem, że podzielę się tym, jak dostroję parametry xgboost. Początkowo myślałem, że skorzystam z tej opcji, ale ostatnio znalazłem problem z obsługą wszystkich parametrów, a także brakujących wartości. Zastanawiałem się też nad napisaniem pętli iteracyjnej poprzez różne kombinacje parametrów, ale chciałem, aby działała równolegle i wymagałaby zbyt wiele czasu. Korzystanie z gridSearch z pakietu NMOF zapewniło to, co najlepsze z obu światów (wszystkie parametry, a także przetwarzanie równoległe). Oto przykładowy kod klasyfikacji binarnej (działa w systemie Windows i 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
źródło