3.5 Boosting en R

Estos métodos son también de los más populares en AE y están implementados en numerosos paquetes de R: ada, adabag, mboost, gbm, xgboost

3.5.1 Ejemplo: clasificación con el paquete ada

La función ada() del paquete ada (Culp et al., 2006) implementa diversos métodos boosting (incluyendo el algoritmo original AdaBoost). Emplea rpart para la construcción de los árboles, aunque solo admite respuestas dicotómicas y dos funciones de pérdida (exponencial y logística). Además, un posible problema al emplear esta función es que ordena alfabéticamente los niveles del factor, lo que puede llevar a una mala interpretación de los resultados.

Los principales parámetros son los siguientes:

ada(formula, data, loss = c("exponential", "logistic"),
    type = c("discrete", "real", "gentle"), iter = 50, 
    nu = 0.1, bag.frac = 0.5, ...)
  • formula y data (opcional): permiten especificar la respuesta y las variables predictoras de la forma habitual (típicamente respuesta ~ .; también admite matrices x e y en lugar de fórmulas).

  • loss: función de pérdida; por defecto "exponential" (algoritmo AdaBoost).

  • type: algoritmo boosting; por defecto "discrete" que implementa el algoritmo AdaBoost original que predice la variable respuesta. Otras alternativas son "real", que implementa el algoritmo Real AdaBoost (J. Friedman et al., 2000) que permite estimar las probabilidades, y "gentle" , versión modificada del anterior que emplea un método Newton de optimización por pasos (en lugar de optimización exacta).

  • iter: número de iteraciones boosting; por defecto 50.

  • nu: parámetro de regularización \(\lambda\); por defecto 0.1 (disminuyendo este parámetro es de esperar que se obtenga una mejora en la precisión de las predicciones pero requería aumentar iter aumentando notablemente el tiempo de computación y los requerimientos de memoria).

  • bag.frac: proporción de observaciones seleccionadas al azar para crecer cada árbol; por defecto 0.5.

  • ...: argumentos adicionales para rpart.control; por defecto rpart.control(maxdepth = 1, cp = -1, minsplit = 0, xval = 0).

Como ejemplo consideraremos el conjunto de datos de calidad de vino empleado en las secciones 2.3.2 y 3.3, pero para evitar problemas reordenamos alfabéticamente los niveles de la respuesta.

load("data/winetaste.RData")
# Reordenar alfabéticamente los niveles de winetaste$taste
# winetaste$taste <- factor(winetaste$taste, sort(levels(winetaste$taste)))
winetaste$taste <- factor(as.character(winetaste$taste))
# Partición de los datos
set.seed(1)
df <- winetaste
nobs <- nrow(df)
itrain <- sample(nobs, 0.8 * nobs)
train <- df[itrain, ]
test <- df[-itrain, ]

Por ejemplo, el siguiente código llama a la función ada() con la opción para estimar probabilidades (type = "real", Real AdaBoost), considerando interacciones (de orden 2) entre los predictores (maxdepth = 2), disminuyendo ligeramente el valor del parámetro de aprendizaje y aumentando el número de iteraciones:

library(ada)
ada.boost <- ada(taste ~ ., data = train, type = "real",
             control = rpart.control(maxdepth = 2, cp = 0, minsplit = 10, xval = 0),
             iter = 100, nu = 0.05)
ada.boost
## Call:
## ada(taste ~ ., data = train, type = "real", control = rpart.control(maxdepth = 2, 
##     cp = 0, minsplit = 10, xval = 0), iter = 100, nu = 0.05)
## 
## Loss: exponential Method: real   Iteration: 100 
## 
## Final Confusion Matrix for Data:
##           Final Prediction
## True value bad good
##       bad  162  176
##       good  46  616
## 
## Train Error: 0.222 
## 
## Out-Of-Bag Error:  0.233  iteration= 99 
## 
## Additional Estimates of number of iterations:
## 
## train.err1 train.kap1 
##         93         93

Con el método plot() podemos representar la evolución del error de clasificación al aumentar el número de iteraciones (ver Figura 3.11):

plot(ada.boost)
Evolución de la tasa de error utilizando ada().

Figura 3.11: Evolución de la tasa de error utilizando ada().

Podemos evaluar la precisión en la muestra de test empleando el procedimiento habitual:

pred <- predict(ada.boost, newdata = test)
caret::confusionMatrix(pred, test$taste, positive = "good")
## Confusion Matrix and Statistics
## 
##           Reference
## Prediction bad good
##       bad   34   16
##       good  50  150
##                                           
##                Accuracy : 0.736           
##                  95% CI : (0.6768, 0.7895)
##     No Information Rate : 0.664           
##     P-Value [Acc > NIR] : 0.008615        
##                                           
##                   Kappa : 0.3426          
##                                           
##  Mcnemar's Test P-Value : 4.865e-05       
##                                           
##             Sensitivity : 0.9036          
##             Specificity : 0.4048          
##          Pos Pred Value : 0.7500          
##          Neg Pred Value : 0.6800          
##              Prevalence : 0.6640          
##          Detection Rate : 0.6000          
##    Detection Prevalence : 0.8000          
##       Balanced Accuracy : 0.6542          
##                                           
##        'Positive' Class : good            
## 

Para obtener las estimaciones de las probabilidades, habría que establecer type = "probs" al predecir (devolverá una matriz con columnas correspondientes a los niveles):

p.est <- predict(ada.boost, newdata = test, type = "probs")
head(p.est)
##          [,1]      [,2]
## 1  0.49877103 0.5012290
## 4  0.30922187 0.6907781
## 9  0.02774336 0.9722566
## 10 0.04596187 0.9540381
## 12 0.44274407 0.5572559
## 16 0.37375910 0.6262409

Este procedimiento también está implementado en el paquete caret seleccionando el método "ada", que considera como hiperparámetros:

library(caret)
modelLookup("ada")
##   model parameter          label forReg forClass probModel
## 1   ada      iter         #Trees  FALSE     TRUE      TRUE
## 2   ada  maxdepth Max Tree Depth  FALSE     TRUE      TRUE
## 3   ada        nu  Learning Rate  FALSE     TRUE      TRUE

Aunque por defecto la función train() solo considera nueve combinaciones de hiperparámetros:

set.seed(1)
caret.ada0 <- train(taste ~ ., method = "ada", data = train,
                   trControl = trainControl(method = "cv", number = 5))
caret.ada0
## Boosted Classification Trees 
## 
## 1000 samples
##   11 predictor
##    2 classes: 'bad', 'good' 
## 
## No pre-processing
## Resampling: Cross-Validated (5 fold) 
## Summary of sample sizes: 800, 801, 800, 800, 799 
## Resampling results across tuning parameters:
## 
##   maxdepth  iter  Accuracy   Kappa    
##   1          50   0.7100121  0.2403486
##   1         100   0.7220322  0.2824931
##   1         150   0.7360322  0.3346624
##   2          50   0.7529774  0.3872880
##   2         100   0.7539673  0.4019619
##   2         150   0.7559673  0.4142035
##   3          50   0.7570024  0.4112842
##   3         100   0.7550323  0.4150030
##   3         150   0.7650024  0.4408835
## 
## Tuning parameter 'nu' was held constant at a value of 0.1
## Accuracy was used to select the optimal model using the largest value.
## The final values used for the model were iter = 150, maxdepth = 3 and nu = 0.1.
confusionMatrix(predict(caret.ada0, newdata = test), test$taste, positive = "good")
## Confusion Matrix and Statistics
## 
##           Reference
## Prediction bad good
##       bad   37   22
##       good  47  144
##                                           
##                Accuracy : 0.724           
##                  95% CI : (0.6641, 0.7785)
##     No Information Rate : 0.664           
##     P-Value [Acc > NIR] : 0.024724        
##                                           
##                   Kappa : 0.3324          
##                                           
##  Mcnemar's Test P-Value : 0.003861        
##                                           
##             Sensitivity : 0.8675          
##             Specificity : 0.4405          
##          Pos Pred Value : 0.7539          
##          Neg Pred Value : 0.6271          
##              Prevalence : 0.6640          
##          Detection Rate : 0.5760          
##    Detection Prevalence : 0.7640          
##       Balanced Accuracy : 0.6540          
##                                           
##        'Positive' Class : good            
## 

Se puede aumentar el número de combinaciones empleando tuneLength o tuneGrid pero la búsqueda en una rejilla completa puede incrementar considerablemente el tiempo de computación. Por este motivo se suelen seguir distintos procedimientos de búsqueda. Por ejemplo, fijar la tasa de aprendizaje (inicialmente a un valor alto) para seleccionar primero un número de interaciones y la complejidad del árbol, y posteriormente fijar estos valores para seleccionar una nueva tasa de aprendizaje (repitiendo el proceso, si es necesario, hasta convergencia).

set.seed(1)
caret.ada1 <- train(taste ~ ., method = "ada", data = train,
                    tuneGrid = data.frame(iter =  150, maxdepth = 3,
                                 nu = c(0.3, 0.1, 0.05, 0.01, 0.005)),
                   trControl = trainControl(method = "cv", number = 5))
caret.ada1
## Boosted Classification Trees 
## 
## 1000 samples
##   11 predictor
##    2 classes: 'bad', 'good' 
## 
## No pre-processing
## Resampling: Cross-Validated (5 fold) 
## Summary of sample sizes: 800, 801, 800, 800, 799 
## Resampling results across tuning parameters:
## 
##   nu     Accuracy   Kappa    
##   0.005  0.7439722  0.3723405
##   0.010  0.7439822  0.3725968
##   0.050  0.7559773  0.4116753
##   0.100  0.7619774  0.4365242
##   0.300  0.7580124  0.4405127
## 
## Tuning parameter 'iter' was held constant at a value of 150
## Tuning
##  parameter 'maxdepth' was held constant at a value of 3
## Accuracy was used to select the optimal model using the largest value.
## The final values used for the model were iter = 150, maxdepth = 3 and nu = 0.1.
confusionMatrix(predict(caret.ada1, newdata = test), test$taste, positive = "good")
## Confusion Matrix and Statistics
## 
##           Reference
## Prediction bad good
##       bad   40   21
##       good  44  145
##                                          
##                Accuracy : 0.74           
##                  95% CI : (0.681, 0.7932)
##     No Information Rate : 0.664          
##     P-Value [Acc > NIR] : 0.005841       
##                                          
##                   Kappa : 0.375          
##                                          
##  Mcnemar's Test P-Value : 0.006357       
##                                          
##             Sensitivity : 0.8735         
##             Specificity : 0.4762         
##          Pos Pred Value : 0.7672         
##          Neg Pred Value : 0.6557         
##              Prevalence : 0.6640         
##          Detection Rate : 0.5800         
##    Detection Prevalence : 0.7560         
##       Balanced Accuracy : 0.6748         
##                                          
##        'Positive' Class : good           
## 

3.5.2 Ejemplo: regresión con el paquete gbm

El paquete gbm implementa el algoritmo SGB de Friedman (2002) y admite varios tipos de respuesta considerando distintas funciones de pérdida (aunque en el caso de variables dicotómicas éstas deben tomar valores en \(\{0, 1\}\)26). La función principal es gbm() y se suelen considerar los siguientes argumentos:

gbm( formula, distribution = "bernoulli", data, n.trees = 100, 
     interaction.depth = 1, n.minobsinnode = 10,
     shrinkage = 0.1, bag.fraction = 0.5, 
     cv.folds = 0, n.cores = NULL)
  • formula y data (opcional): permiten especificar la respuesta y las variables predictoras de la forma habitual (típicamente respuesta ~ .; también está disponible una interfaz con matrices gbm.fit()).

  • distribution (opcional): texto con el nombre de la distribución (o lista con el nombre en name y parámetros adicionales en los demás componentes) que determina la función de pérdida. Si se omite se establecerá a partir del tipo de la respuesta: "bernouilli" (regresión logística) si es una variable dicotómica 0/1, "multinomial" (regresión multinomial) si es un factor (no se recomienda) y "gaussian" (error cuadrático) en caso contrario. Otras opciones que pueden ser de interés son: "laplace" (error absoluto), "adaboost" (pérdida exponencial para respuestas dicotómicas 0/1), "huberized" (pérdida de Huber para respuestas dicotómicas 0/1), "poisson" (regresión de Poisson) y "quantile" (regresión cuantil).

  • ntrees: iteraciones/número de árboles que se crecerán; por defecto 100 (se puede emplear la función gbm.perf() para seleccionar un valor “óptimo”).

  • interaction.depth: profundidad de los árboles; por defecto 1 (modelo aditivo).

  • n.minobsinnode: número mínimo de observaciones en un nodo terminal; por defecto 10.

  • shrinkage: parámetro de regularización \(\lambda\); por defecto 0.1.

  • bag.fraction: proporción de observaciones seleccionadas al azar para crecer cada árbol; por defecto 0.5.

  • cv.folds: número grupos para validación cruzada; por defecto 0 (no se hace validación cruzada). Si se asigna un valor mayor que 1 se realizará validación cruzada y se devolverá el error en la componente $cv.error (se puede emplear para seleccionar hiperparámetros).

  • n.cores: número de núcleos para el procesamiento en paralelo.

Como ejemplo consideraremos el conjunto de datos winequality.RData:

load("data/winequality.RData")
set.seed(1)
df <- winequality
nobs <- nrow(df)
itrain <- sample(nobs, 0.8 * nobs)
train <- df[itrain, ]
test <- df[-itrain, ]

library(gbm)
gbm.fit <- gbm(quality ~ ., data = train)
## Distribution not specified, assuming gaussian ...
gbm.fit
## gbm(formula = quality ~ ., data = train)
## A gradient boosted model with gaussian loss function.
## 100 iterations were performed.
## There were 11 predictors of which 11 had non-zero influence.

El método summary() calcula las medidas de influencia de los predictores y las representa gráficamente (ver Figura 3.12):

summary(gbm.fit)
Importancia de las variables predictoras (con los valores por defecto de gbm()).

Figura 3.12: Importancia de las variables predictoras (con los valores por defecto de gbm()).

##                                       var   rel.inf
## alcohol                           alcohol 40.907998
## volatile.acidity         volatile.acidity 13.839083
## free.sulfur.dioxide   free.sulfur.dioxide 11.488262
## fixed.acidity               fixed.acidity  7.914742
## citric.acid                   citric.acid  6.765875
## total.sulfur.dioxide total.sulfur.dioxide  4.808308
## residual.sugar             residual.sugar  4.758566
## chlorides                       chlorides  3.424537
## sulphates                       sulphates  3.086036
## density                           density  1.918442
## pH                                     pH  1.088152

Para estudiar el efecto de un predictor se pueden generar gráficos de los efectos parciales mediante el método plot() (ver Figura 3.13):

p1 <- plot(gbm.fit, i = "alcohol")
p2 <- plot(gbm.fit, i = "density")
# plot(gbm.fit, i = c("alcohol", "density")) # interacción
gridExtra::grid.arrange(p1, p2, ncol = 2)
Efecto parcial del alcohol (panel izquierdo) y la densidad (panel derecho) sobre la respuesta (con gbm()).

Figura 3.13: Efecto parcial del alcohol (panel izquierdo) y la densidad (panel derecho) sobre la respuesta (con gbm()).

Finalmente podemos evaluar la precisión en la muestra de test empleando el código habitual:

pred <- predict(gbm.fit, newdata = test)
obs <- test$quality

# Con el paquete caret
caret::postResample(pred, obs)
##      RMSE  Rsquared       MAE 
## 0.7586208 0.3001401 0.6110442
# Con la función accuracy()
accuracy <- function(pred, obs, na.rm = FALSE,
                     tol = sqrt(.Machine$double.eps)) {
  err <- obs - pred     # Errores
  if(na.rm) {
    is.a <- !is.na(err)
    err <- err[is.a]
    obs <- obs[is.a]
  }
  perr <- 100*err/pmax(obs, tol)  # Errores porcentuales
  return(c(
    me = mean(err),           # Error medio
    rmse = sqrt(mean(err^2)), # Raíz del error cuadrático medio
    mae = mean(abs(err)),     # Error absoluto medio
    mpe = mean(perr),         # Error porcentual medio
    mape = mean(abs(perr)),   # Error porcentual absoluto medio
    r.squared = 1 - sum(err^2)/sum((obs - mean(obs))^2)
  ))
}
accuracy(pred, obs)
##          me        rmse         mae         mpe        mape   r.squared 
## -0.01463661  0.75862081  0.61104421 -2.00702056 10.69753668  0.29917590

Este procedimiento también está implementado en el paquete caret seleccionando el método "gbm", que considera como hiperparámetros:

library(caret)
modelLookup("gbm")
##   model         parameter                   label forReg forClass probModel
## 1   gbm           n.trees   # Boosting Iterations   TRUE     TRUE      TRUE
## 2   gbm interaction.depth          Max Tree Depth   TRUE     TRUE      TRUE
## 3   gbm         shrinkage               Shrinkage   TRUE     TRUE      TRUE
## 4   gbm    n.minobsinnode Min. Terminal Node Size   TRUE     TRUE      TRUE

Aunque por defecto la función train() solo considera nueve combinaciones de hiperparámetros. Para hacer una búsqueda más completa se podría seguir un procedimiento análogo al empleado con el método anterior:

set.seed(1)
caret.gbm0 <- train(quality ~ ., method = "gbm", data = train,
                   trControl = trainControl(method = "cv", number = 5))
caret.gbm0
## Stochastic Gradient Boosting 
## 
## 1000 samples
##   11 predictor
## 
## No pre-processing
## Resampling: Cross-Validated (5 fold) 
## Summary of sample sizes: 800, 801, 800, 800, 799 
## Resampling results across tuning parameters:
## 
##   interaction.depth  n.trees  RMSE       Rsquared   MAE      
##   1                   50      0.7464098  0.2917796  0.5949686
##   1                  100      0.7258319  0.3171046  0.5751816
##   1                  150      0.7247246  0.3197241  0.5719404
##   2                   50      0.7198195  0.3307665  0.5712468
##   2                  100      0.7175006  0.3332903  0.5647409
##   2                  150      0.7258174  0.3222006  0.5713116
##   3                   50      0.7241661  0.3196365  0.5722590
##   3                  100      0.7272094  0.3191252  0.5754363
##   3                  150      0.7311429  0.3152905  0.5784988
## 
## Tuning parameter 'shrinkage' was held constant at a value of 0.1
## 
## Tuning parameter 'n.minobsinnode' was held constant at a value of 10
## RMSE was used to select the optimal model using the smallest value.
## The final values used for the model were n.trees = 100, interaction.depth =
##  2, shrinkage = 0.1 and n.minobsinnode = 10.
caret.gbm1 <- train(quality ~ ., method = "gbm", data = train,
   tuneGrid = data.frame(n.trees =  100, interaction.depth = 2, 
                        shrinkage = c(0.3, 0.1, 0.05, 0.01, 0.005),
                        n.minobsinnode = 10),
   trControl = trainControl(method = "cv", number = 5))
caret.gbm1
## Stochastic Gradient Boosting 
## 
## 1000 samples
##   11 predictor
## 
## No pre-processing
## Resampling: Cross-Validated (5 fold) 
## Summary of sample sizes: 800, 800, 801, 799, 800 
## Resampling results across tuning parameters:
## 
##   shrinkage  RMSE       Rsquared   MAE      
##   0.005      0.8154916  0.2419131  0.6245818
##   0.010      0.7844257  0.2602989  0.6128582
##   0.050      0.7206972  0.3275463  0.5707273
##   0.100      0.7124838  0.3407642  0.5631748
##   0.300      0.7720844  0.2613835  0.6091765
## 
## Tuning parameter 'n.trees' was held constant at a value of 100
## Tuning
##  parameter 'interaction.depth' was held constant at a value of 2
## 
## Tuning parameter 'n.minobsinnode' was held constant at a value of 10
## RMSE was used to select the optimal model using the smallest value.
## The final values used for the model were n.trees = 100, interaction.depth =
##  2, shrinkage = 0.1 and n.minobsinnode = 10.
varImp(caret.gbm1)
## gbm variable importance
## 
##                       Overall
## alcohol              100.0000
## volatile.acidity      28.4909
## free.sulfur.dioxide   24.5158
## residual.sugar        16.8406
## fixed.acidity         12.5623
## density               10.1917
## citric.acid            9.1542
## total.sulfur.dioxide   7.2659
## chlorides              4.5106
## pH                     0.1096
## sulphates              0.0000
postResample(predict(caret.gbm1, newdata = test), test$quality)
##      RMSE  Rsquared       MAE 
## 0.7403768 0.3329751 0.6017281

3.5.3 Ejemplo: XGBoost con el paquete caret

El método boosting implementado en el paquete xgboost es uno de los más populares hoy en día. Esta implementación proporciona parámetros adicionales de regularización para controlar la complejidad del modelo y tratar de evitar el sobreajuste. También incluye criterios de parada, para detener la evaluación del modelo cuando los árboles adicionales no ofrecen ninguna mejora. Dispone de una interfaz simple xgboost() y otra más avanzada xgb.train(), que admite funciones de pérdida y evaluación personalizadas. Normalmente es necesario un preprocesado de los datos antes de llamar a estas funciones, ya que requieren de una matriz para los predictores y de un vector para la respuesta (además en el caso de que sea dicotómica debe tomar valores en \(\{0, 1\}\)). Por tanto es necesario recodificar las variables categóricas como numéricas. Por este motivo puede ser preferible emplear la interfaz de caret.

El algoritmo estándar XGBoost, que emplea árboles como modelo base, está implementado en el método "xgbTree" de caret27:

library(caret)
# names(getModelInfo("xgb"))
modelLookup("xgbTree")
##     model        parameter                          label forReg forClass
## 1 xgbTree          nrounds          # Boosting Iterations   TRUE     TRUE
## 2 xgbTree        max_depth                 Max Tree Depth   TRUE     TRUE
## 3 xgbTree              eta                      Shrinkage   TRUE     TRUE
## 4 xgbTree            gamma         Minimum Loss Reduction   TRUE     TRUE
## 5 xgbTree colsample_bytree     Subsample Ratio of Columns   TRUE     TRUE
## 6 xgbTree min_child_weight Minimum Sum of Instance Weight   TRUE     TRUE
## 7 xgbTree        subsample           Subsample Percentage   TRUE     TRUE
##   probModel
## 1      TRUE
## 2      TRUE
## 3      TRUE
## 4      TRUE
## 5      TRUE
## 6      TRUE
## 7      TRUE

Este método considera los siguientes hiperparámetros:

  • "nrounds": número de iteraciones boosting.

  • "max_depth": profundidad máxima del árbol; por defecto 6.

  • "eta": parámetro de regularización \(\lambda\); por defecto 0.3.

  • "gamma": mínima reducción de la pérdida para hacer una partición adicional en un nodo del árbol; por defecto 0.

  • "colsample_bytree": proporción de predictores seleccionados al azar para crecer cada árbol; por defecto 1.

  • "min_child_weight": suma mínima de peso (hessiana) para hacer una partición adicional en un nodo del árbol; por defecto 1.

  • "subsample": proporción de observaciones seleccionadas al azar en cada iteración boosting; por defecto 1.

Para más información sobre parámetros adicionales se puede consultar la ayuda de xgboost::xgboost() o la lista detallada disponible en la Sección XGBoost Parameters del Manual de XGBoost.

Como ejemplo consideraremos el problema de clasificación empleando el conjunto de datos de calidad de vino:

load("data/winetaste.RData")
set.seed(1)
df <- winetaste
nobs <- nrow(df)
itrain <- sample(nobs, 0.8 * nobs)
train <- df[itrain, ]
test <- df[-itrain, ]

En este caso la función train() considera por defecto 108 combinaciones de hiperparámetros y el tiempo de computación puede ser excesivo28:

caret.xgb <- train(taste ~ ., method = "xgbTree", data = train,
                   trControl = trainControl(method = "cv", number = 5), 
                   verbosity = 0)
caret.xgb
## eXtreme Gradient Boosting 
## 
## 1000 samples
##   11 predictor
##    2 classes: 'good', 'bad' 
## 
## No pre-processing
## Resampling: Cross-Validated (5 fold) 
## Summary of sample sizes: 799, 801, 801, 799, 800 
## Resampling results across tuning parameters:
## 
##   eta  max_depth  colsample_bytree  subsample  nrounds  Accuracy   Kappa    
##   0.3  1          0.6               0.50        50      0.7479499  0.3997718
##   0.3  1          0.6               0.50       100      0.7509649  0.4226367
##   0.3  1          0.6               0.50       150      0.7480199  0.4142399
##   0.3  1          0.6               0.75        50      0.7389498  0.3775707
##   0.3  1          0.6               0.75       100      0.7499600  0.4178857
##   0.3  1          0.6               0.75       150      0.7519900  0.4194354
##   0.3  1          0.6               1.00        50      0.7479450  0.3933223
##   0.3  1          0.6               1.00       100      0.7439499  0.3946755
##  [ reached getOption("max.print") -- omitted 100 rows ]
## 
## Tuning parameter 'gamma' was held constant at a value of 0
## Tuning
##  parameter 'min_child_weight' was held constant at a value of 1
## Accuracy was used to select the optimal model using the largest value.
## The final values used for the model were nrounds = 100, max_depth = 2, eta
##  = 0.4, gamma = 0, colsample_bytree = 0.8, min_child_weight = 1 and subsample
##  = 1.
caret.xgb$bestTune
##    nrounds max_depth eta gamma colsample_bytree min_child_weight subsample
## 89     100         2 0.4     0              0.8                1         1
varImp(caret.xgb)
## xgbTree variable importance
## 
##                      Overall
## alcohol              100.000
## volatile.acidity      27.693
## citric.acid           23.788
## free.sulfur.dioxide   23.673
## fixed.acidity         20.393
## residual.sugar        15.734
## density               10.956
## chlorides              8.085
## sulphates              3.598
## pH                     2.925
## total.sulfur.dioxide   0.000
confusionMatrix(predict(caret.xgb, newdata = test), test$taste)
## Confusion Matrix and Statistics
## 
##           Reference
## Prediction good bad
##       good  147  46
##       bad    19  38
##                                          
##                Accuracy : 0.74           
##                  95% CI : (0.681, 0.7932)
##     No Information Rate : 0.664          
##     P-Value [Acc > NIR] : 0.005841       
##                                          
##                   Kappa : 0.3671         
##                                          
##  Mcnemar's Test P-Value : 0.001260       
##                                          
##             Sensitivity : 0.8855         
##             Specificity : 0.4524         
##          Pos Pred Value : 0.7617         
##          Neg Pred Value : 0.6667         
##              Prevalence : 0.6640         
##          Detection Rate : 0.5880         
##    Detection Prevalence : 0.7720         
##       Balanced Accuracy : 0.6690         
##                                          
##        'Positive' Class : good           
## 

Se podría seguir una estrategia de búsqueda similar a la empleada en los métodos anteriores.

References

Culp, M., Johnson, K., y Michailidis, G. (2006). ada: An R Package for Stochastic Boosting. Journal of Statistical Software, 17(2), 1-27. https://doi.org/10.18637/jss.v017.i02
Friedman, J. H. (2002). Stochastic gradient boosting. Computational Statistics & data analysis, 38(4), 367-378. https://doi.org/10.1016/S0167-9473(01)00065-2
Friedman, J., Hastie, T., y Tibshirani, R. (2000). Additive logistic regression: a statistical view of boosting (with discussion and a rejoinder by the authors). The Annals of Statistics, 28(2), 337-407. https://doi.org/10.1214/aos/1016218223
Vinayak, R. K., y Gilad-Bachrach, R. (2015). Dart: Dropouts meet multiple additive regression trees. Artificial Intelligence and Statistics, 489-497.

  1. Se puede evitar este inconveniente empleando la interfaz de caret.↩︎

  2. Otras alternativas son: "xgbDART" que también emplean árboles como modelo base, pero incluye el método DART (Vinayak y Gilad-Bachrach, 2015) para evitar sobreajuste (básicamente descarta árboles al azar en la secuencia), y "xgbLinear" que emplea modelos lineales.↩︎

  3. Además, se establece verbosity = 0 para evitar (cientos de) warnings: WARNING: src/c_api/c_api.cc:935: "ntree_limit" is deprecated, use "iteration_range" instead.↩︎