xgboost w R: jak xgb.cv przekaż optymalne parametry do xgb.pociąg

Przeglądałem pakiet xgboost W R i przejrzałem kilka dem i samouczków, ale to wciąż mnie myli: po użyciu {[2] } do walidacji krzyżowej, w jaki sposób optymalne parametry zostają przekazane xgb.train? Czy powinienem obliczyć idealne parametry (takie jak nround, max.depth) na podstawie wyniku xgb.cv?

param <- list("objective" = "multi:softprob",
              "eval_metric" = "mlogloss",
              "num_class" = 12)
cv.nround <- 11
cv.nfold <- 5
mdcv <-xgb.cv(data=dtrain,params = param,nthread=6,nfold = cv.nfold,nrounds = cv.nround,verbose = T)

md <-xgb.train(data=dtrain,params = param,nround = 80,watchlist = list(train=dtrain,test=dtest),nthread=6)
Author: snowneji, 2016-01-28

3 answers

Wygląda na to, że źle zrozumiałeś xgb.cv, nie jest to funkcja wyszukiwania parametrów. To nie K-folds krzyż walidacji, nic więcej.

W Twoim kodzie, nie zmienia on wartości param.

Aby znaleźć najlepsze parametry w XGBoost R, istnieje kilka metod. Są to 2 metody,

(1) użyj mlr pakiet, http://mlr-org.github.io/mlr-tutorial/release/html/

Jest przykładowy kod XGBoost + mlr wyzwanie,

Ale ten kod służy regresji, Nie klasyfikacji. Z tego co wiem, nie ma jeszcze mlogloss metryki w mlr pakiecie, więc musisz sam zakodować pomiar mlogloss od zera. CMIIW.

(2) Druga metoda, ręcznie ustawiając parametry następnie powtórz, przykład,

param <- list(objective = "multi:softprob",
      eval_metric = "mlogloss",
      num_class = 12,
      max_depth = 8,
      eta = 0.05,
      gamma = 0.01, 
      subsample = 0.9,
      colsample_bytree = 0.8, 
      min_child_weight = 4,
      max_delta_step = 1
      )
cv.nround = 1000
cv.nfold = 5
mdcv <- xgb.cv(data=dtrain, params = param, nthread=6, 
                nfold=cv.nfold, nrounds=cv.nround,
                verbose = T)

Następnie znajdziesz najlepszy (minimalny) mlogloss,

min_logloss = min(mdcv[, test.mlogloss.mean])
min_logloss_index = which.min(mdcv[, test.mlogloss.mean])

min_logloss jest minimalną wartością mloglossa, podczas gdy {[12] } jest indeksem (okrągłym).

Musisz powtórz powyższy proces kilka razy, za każdym razem zmieniaj parametry ręcznie (mlr powtarza za Ciebie). Aż w końcu otrzymasz najlepsze globalne minimum min_logloss.

Notatka: możesz to zrobić w pętli 100 lub 200 iteracji, w której dla każdej iteracji ustawiasz wartość parametrów losowo. W ten sposób należy zapisać najlepszą [parameters_list, min_logloss, min_logloss_index] W zmiennych lub w pliku.

Uwaga: lepiej ustawić losowe ziarno przez set.seed() dla powtarzalnego wyniku. Różne losowe nasiona dają inny wynik. Musisz więc zapisać [parameters_list, min_logloss, min_logloss_index, seednumber] w zmiennych lub pliku.

Powiedz, że w końcu otrzymasz 3 Wyniki w 3 iteracjach/powtórzeniach:

min_logloss = 2.1457, min_logloss_index = 840
min_logloss = 2.2293, min_logloss_index = 920
min_logloss = 1.9745, min_logloss_index = 780

Następnie należy użyć trzeciego parametru (ma globalne minimum min_logloss z 1.9745). Twój najlepszy indeks (Nr) to 780.

Gdy uzyskasz najlepsze parametry, użyj go w treningu,

# best_param is global best param with minimum min_logloss
# best_min_logloss_index is the global minimum logloss index
nround = 780
md <- xgb.train(data=dtrain, params=best_param, nrounds=nround, nthread=6)
Nie wydaje mi się, żebyś potrzebował tego szkolenia, bo zrobiłeś walidację krzyżową. Ale jeśli nadal chcesz użyć watchlist, jest po prostu w porządku.

Jeszcze lepiej możesz użyć early stoping in xgb.cv.

mdcv <- xgb.cv(data=dtrain, params=param, nthread=6, 
                nfold=cv.nfold, nrounds=cv.nround,
                verbose = T, early.stop.round=8, maximize=FALSE)

Z tym kodem, gdy mlogloss wartość nie maleje w 8 krokach, xgb.cv zatrzyma się. Możesz zaoszczędzić czas. Musisz ustawić maximize na FALSE, ponieważ oczekujesz minimum mlogloss.

Oto przykładowy kod, z pętlą 100 iteracji i losowo wybranymi parametrami.

best_param = list()
best_seednumber = 1234
best_logloss = Inf
best_logloss_index = 0

for (iter in 1:100) {
    param <- list(objective = "multi:softprob",
          eval_metric = "mlogloss",
          num_class = 12,
          max_depth = sample(6:10, 1),
          eta = runif(1, .01, .3),
          gamma = runif(1, 0.0, 0.2), 
          subsample = runif(1, .6, .9),
          colsample_bytree = runif(1, .5, .8), 
          min_child_weight = sample(1:40, 1),
          max_delta_step = sample(1:10, 1)
          )
    cv.nround = 1000
    cv.nfold = 5
    seed.number = sample.int(10000, 1)[[1]]
    set.seed(seed.number)
    mdcv <- xgb.cv(data=dtrain, params = param, nthread=6, 
                    nfold=cv.nfold, nrounds=cv.nround,
                    verbose = T, early.stop.round=8, maximize=FALSE)

    min_logloss = min(mdcv[, test.mlogloss.mean])
    min_logloss_index = which.min(mdcv[, test.mlogloss.mean])

    if (min_logloss < best_logloss) {
        best_logloss = min_logloss
        best_logloss_index = min_logloss_index
        best_seednumber = seed.number
        best_param = param
    }
}

nround = best_logloss_index
set.seed(best_seednumber)
md <- xgb.train(data=dtrain, params=best_param, nrounds=nround, nthread=6)

Z tym kodem, uruchamiasz walidację krzyżową 100 razy, za każdym razem z przypadkowymi parametrami. Wtedy otrzymujesz najlepszy zestaw parametrów, czyli w iteracji z minimum min_logloss.

Zwiększ wartość early.stop.round W przypadku, gdy okaże się, że jest za mała (zbyt wczesne zatrzymanie). Musisz również zmienić limit losowych wartości parametrów na podstawie charakterystyki danych.

I, dla 100 lub 200 iteracji, myślę, że chcesz zmienić verbose NA FALSE.

Uwaga: jest to przykład metody losowej, można ją dostosować np. poprzez optymalizację Bayesowską dla lepszego metoda. Jeśli masz wersję Pythona XGBoost, istnieje dobry skrypt hyperparameter dla XGBoost, https://github.com/mpearmain/BayesBoost aby wyszukać najlepsze parametry za pomocą optymalizacji bayesowskiej.

W tym samym roku, w 2010 roku, na forum Kaggle pojawiła się nowa wersja Kaggle.

Edit: jeśli znasz Pythona i sklearn, możesz również użyć GridSearchCV wraz z xgboost.XGBClassifier lub xgboost.XGBRegressor

 80
Author: silo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-04-13 01:09:07

To dobre pytanie i świetna odpowiedź od silo z mnóstwem szczegółów! Uważam, że to bardzo pomocne dla kogoś nowego xgboost Jak ja. Dziękuję. Metoda randomizacji i porównania do granicy jest bardzo inspirująca. Dobry w użyciu i dobrze wiedzieć. Teraz w 2018 r. potrzebne są niewielkie zmiany, na przykład early.stop.round powinno być early_stopping_rounds. Wyjście mdcv jest zorganizowane nieco inaczej:

  min_rmse_index  <-  mdcv$best_iteration
  min_rmse <-  mdcv$evaluation_log[min_rmse_index]$test_rmse_mean

I zależy od zastosowania (liniowe, logistyczne itp...),objective, eval_metric i parametry są odpowiednio dostosowywane.

Dla wygody każdego, kto uruchamia regresję, oto lekko dostosowana wersja kodu (większość jest taka sama jak powyżej).

library(xgboost)
# Matrix for xgb: dtrain and dtest, "label" is the dependent variable
dtrain <- xgb.DMatrix(X_train, label = Y_train)
dtest <- xgb.DMatrix(X_test, label = Y_test)

best_param <- list()
best_seednumber <- 1234
best_rmse <- Inf
best_rmse_index <- 0

set.seed(123)
for (iter in 1:100) {
  param <- list(objective = "reg:linear",
                eval_metric = "rmse",
                max_depth = sample(6:10, 1),
                eta = runif(1, .01, .3), # Learning rate, default: 0.3
                subsample = runif(1, .6, .9),
                colsample_bytree = runif(1, .5, .8), 
                min_child_weight = sample(1:40, 1),
                max_delta_step = sample(1:10, 1)
  )
  cv.nround <-  1000
  cv.nfold <-  5 # 5-fold cross-validation
  seed.number  <-  sample.int(10000, 1) # set seed for the cv
  set.seed(seed.number)
  mdcv <- xgb.cv(data = dtrain, params = param,  
                 nfold = cv.nfold, nrounds = cv.nround,
                 verbose = F, early_stopping_rounds = 8, maximize = FALSE)

  min_rmse_index  <-  mdcv$best_iteration
  min_rmse <-  mdcv$evaluation_log[min_rmse_index]$test_rmse_mean

  if (min_rmse < best_rmse) {
    best_rmse <- min_rmse
    best_rmse_index <- min_rmse_index
    best_seednumber <- seed.number
    best_param <- param
  }
}

# The best index (min_rmse_index) is the best "nround" in the model
nround = best_rmse_index
set.seed(best_seednumber)
xg_mod <- xgboost(data = dtest, params = best_param, nround = nround, verbose = F)

# Check error in testing data
yhat_xg <- predict(xg_mod, dtest)
(MSE_xgb <- mean((yhat_xg - Y_test)^2))
 6
Author: Yang Liu,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-07-08 10:10:13

Okazało się, że odpowiedź silo jest bardzo pomocna. Oprócz jego podejścia do badań losowych, możesz użyć optymalizacji bayesowskiej, aby ułatwić proces wyszukiwania hiperparametrów, np. rbayesianoptimization library . Poniżej znajduje się mój kod z biblioteką rbayesianoptimization.

cv_folds <- KFold(dataFTR$isPreIctalTrain, nfolds = 5, stratified = FALSE, seed = seedNum)
xgb_cv_bayes <- function(nround,max.depth, min_child_weight, subsample,eta,gamma,colsample_bytree,max_delta_step) {
param<-list(booster = "gbtree",
            max_depth = max.depth,
            min_child_weight = min_child_weight,
            eta=eta,gamma=gamma,
            subsample = subsample, colsample_bytree = colsample_bytree,
            max_delta_step=max_delta_step,
            lambda = 1, alpha = 0,
            objective = "binary:logistic",
            eval_metric = "auc")
cv <- xgb.cv(params = param, data = dtrain, folds = cv_folds,nrounds = 1000,early_stopping_rounds = 10, maximize = TRUE, verbose = verbose)

list(Score = cv$evaluation_log$test_auc_mean[cv$best_iteration],
     Pred=cv$best_iteration)
# we don't need cross-validation prediction and we need the number of rounds.
# a workaround is to pass the number of rounds(best_iteration) to the Pred, which is a default parameter in the rbayesianoptimization library.
}
OPT_Res <- BayesianOptimization(xgb_cv_bayes,
                              bounds = list(max.depth =c(3L, 10L),min_child_weight = c(1L, 40L),
                                            subsample = c(0.6, 0.9),
                                            eta=c(0.01,0.3),gamma = c(0.0, 0.2),
                                            colsample_bytree=c(0.5,0.8),max_delta_step=c(1L,10L)),
                              init_grid_dt = NULL, init_points = 10, n_iter = 10,
                              acq = "ucb", kappa = 2.576, eps = 0.0,
                              verbose = verbose)
best_param <- list(
booster = "gbtree",
eval.metric = "auc",
objective = "binary:logistic",
max_depth = OPT_Res$Best_Par["max.depth"],
eta = OPT_Res$Best_Par["eta"],
gamma = OPT_Res$Best_Par["gamma"],
subsample = OPT_Res$Best_Par["subsample"],
colsample_bytree = OPT_Res$Best_Par["colsample_bytree"],
min_child_weight = OPT_Res$Best_Par["min_child_weight"],
max_delta_step = OPT_Res$Best_Par["max_delta_step"])
# number of rounds should be tuned using CV
#https://www.hackerearth.com/practice/machine-learning/machine-learning-algorithms/beginners-tutorial-on-xgboost-parameter-tuning-r/tutorial/
# However, nrounds can not be directly derivied from the bayesianoptimization function
# Here, OPT_Res$Pred, which was supposed to be used for cross-validation, is used to record the number of rounds
nrounds=OPT_Res$Pred[[which.max(OPT_Res$History$Value)]]
xgb_model <- xgb.train (params = best_param, data = dtrain, nrounds = nrounds)
 3
Author: Penning Yu,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-02-16 18:54:27