¿XGBoost maneja la multicolinealidad por sí mismo?

23

Actualmente estoy usando XGBoost en un conjunto de datos con 21 características (seleccionadas de la lista de unas 150 características), luego las codifiqué para obtener ~ 98 características. Algunas de estas 98 características son algo redundantes, por ejemplo: una variable (característica) también aparece como BA yCBA .CA

Mis preguntas son:

  • ¿Cómo ( si? ) Manejan los árboles de decisión potenciados la multicolinealidad?
  • ¿Cómo afectaría la existencia de multicolinealidad a la predicción si no se maneja?

Por lo que entiendo, el modelo está aprendiendo más de un árbol y la predicción final se basa en algo así como una "suma ponderada" de las predicciones individuales. Entonces, si esto es correcto, los árboles de decisión potenciados deberían poder manejar la codependencia entre variables.

Además, en una nota relacionada: ¿cómo funciona el objeto de importancia variable en XGBoost?

usuario140323
fuente
Entiendo que los árboles pueden manejar la multicolinealidad. Pero, ¿qué pasa con XGBoost basado en regresión? ¿Puede manejar también la multicolinealidad? > Los árboles de decisión son por naturaleza inmunes a la multicolinealidad. Por ejemplo, si tiene 2 características que están correlacionadas en un 99%, cuando> decide una división, el árbol elegirá solo una de ellas. Otros> modelos como la regresión logística usarían ambas características. >> Dado que los árboles potenciados usan árboles de decisión individuales, tampoco se ven afectados por la multicolinealidad. Sin embargo, es una buena práctica eliminar todas las funciones redundantes de cualquier conjunto de datos utilizado para el tra
Jay Saxena

Respuestas:

27

Los árboles de decisión son por naturaleza inmunes a la multicolinealidad. Por ejemplo, si tiene 2 características que están 99% correlacionadas, al decidir sobre una división, el árbol elegirá solo una de ellas. Otros modelos, como la regresión logística, utilizarían ambas características.

Dado que los árboles potenciados utilizan árboles de decisión individuales, tampoco se ven afectados por la multicolinealidad. Sin embargo, es una buena práctica eliminar cualquier característica redundante de cualquier conjunto de datos utilizado para el entrenamiento, independientemente del algoritmo del modelo. En su caso, ya que está obteniendo nuevas características, puede usar este enfoque, evaluar la importancia de cada característica y conservar solo las mejores características para su modelo final.

La matriz de importancia de un modelo xgboost es en realidad un objeto data.table con la primera columna que enumera los nombres de todas las características realmente utilizadas en los árboles potenciados. La segunda columna es la métrica de ganancia que implica la contribución relativa de la característica correspondiente al modelo calculada tomando la contribución de cada característica para cada árbol en el modelo. Un valor más alto de esta métrica en comparación con otra característica implica que es más importante para generar una predicción.

Sandeep S. Sandhu
fuente
7

Tenía curiosidad sobre esto e hice algunas pruebas.

He entrenado un modelo en el conjunto de datos de diamantes, y he observado que la variable "x" es la más importante para predecir si el precio de un diamante es más alto que cierto umbral. Luego, agregué varias columnas altamente correlacionadas con x, ejecuté el mismo modelo y observé los mismos valores.

Parece que cuando la correlación entre dos columnas es 1, xgboost elimina la columna adicional antes de calcular el modelo, por lo que la importancia no se ve afectada. Sin embargo, cuando agrega una columna que está parcialmente correlacionada con otra, por lo tanto, con un coeficiente más bajo, la importancia de la variable original x disminuye.

Por ejemplo, si agrego una variable xy = x + y, la importancia de x e y disminuye. De manera similar, la importancia de x disminuye si agrego nuevas variables con r = 0.4, 0.5 o 0.6, aunque solo un poco.

Creo que la colinealidad no es un problema para aumentar cuando se calcula la precisión del modelo, porque al árbol de decisión no le importa cuál de las variables se utiliza. Sin embargo, podría afectar la importancia de las variables, porque eliminar una de las dos variables correlacionadas no tiene un gran impacto en la precisión del modelo, dado que la otra contiene información similar.

library(tidyverse)
library(xgboost)

evaluate_model = function(dataset) {
    print("Correlation matrix")
    dataset %>% select(-cut, -color, -clarity, -price) %>% cor %>% print

    print("running model")
    diamond.model = xgboost(
        data=dataset %>% select(-cut, -color, -clarity, -price) %>% as.matrix, 
        label=dataset$price > 400, 
        max.depth=15, nrounds=30, nthread=2, objective = "binary:logistic",
        verbose=F
        )

    print("Importance matrix")
    importance_matrix <- xgb.importance(model = diamond.model)
    importance_matrix %>% print
    xgb.plot.importance(importance_matrix)
    }

> diamonds %>% head
carat   cut color   clarity depth   table   price   x   y   z
0.23    Ideal   E   SI2 61.5    55  326 3.95    3.98    2.43
0.21    Premium E   SI1 59.8    61  326 3.89    3.84    2.31
0.23    Good    E   VS1 56.9    65  327 4.05    4.07    2.31
0.29    Premium I   VS2 62.4    58  334 4.20    4.23    2.63
0.31    Good    J   SI2 63.3    58  335 4.34    4.35    2.75
0.24    Very Good   J   VVS2    62.8    57  336 3.94    3.96    2.48

Evaluar un modelo en los datos de diamantes.

Predecimos si el precio es superior a 400, dadas todas las variables numéricas disponibles (quilate, profundidad, tabla, x, y, x)

Tenga en cuenta que x es la variable más importante, con una puntuación de ganancia de importancia de 0.375954.

evaluate_model(diamonds)
    [1] "Correlation matrix"
               carat       depth      table           x           y          z
    carat 1.00000000  0.02822431  0.1816175  0.97509423  0.95172220 0.95338738
    depth 0.02822431  1.00000000 -0.2957785 -0.02528925 -0.02934067 0.09492388
    table 0.18161755 -0.29577852  1.0000000  0.19534428  0.18376015 0.15092869
    x     0.97509423 -0.02528925  0.1953443  1.00000000  0.97470148 0.97077180
    y     0.95172220 -0.02934067  0.1837601  0.97470148  1.00000000 0.95200572
    z     0.95338738  0.09492388  0.1509287  0.97077180  0.95200572 1.00000000
    [1] "running model"
    [1] "Importance matrix"
       Feature       Gain      Cover  Frequency
    1:       x 0.37595419 0.54788335 0.19607102
    2:   carat 0.19699839 0.18015576 0.04873442
    3:   depth 0.15358261 0.08780079 0.27767284
    4:       y 0.11645929 0.06527969 0.18813751
    5:   table 0.09447853 0.05037063 0.17151492
    6:       z 0.06252699 0.06850978 0.11786929

Modelo entrenado en diamantes, agregando una variable con r = 1 a x

Aquí agregamos una nueva columna, que sin embargo no agrega ninguna información nueva, ya que está perfectamente correlacionada con x.

Tenga en cuenta que esta nueva variable no está presente en la salida. Parece que xgboost elimina automáticamente las variables perfectamente correlacionadas antes de comenzar el cálculo. La ganancia de importancia de x es la misma, 0.3759.

diamonds_xx = diamonds %>%
    mutate(xx = x + runif(1, -1, 1))
evaluate_model(diamonds_xx)
[1] "Correlation matrix"
           carat       depth      table           x           y          z
carat 1.00000000  0.02822431  0.1816175  0.97509423  0.95172220 0.95338738
depth 0.02822431  1.00000000 -0.2957785 -0.02528925 -0.02934067 0.09492388
table 0.18161755 -0.29577852  1.0000000  0.19534428  0.18376015 0.15092869
x     0.97509423 -0.02528925  0.1953443  1.00000000  0.97470148 0.97077180
y     0.95172220 -0.02934067  0.1837601  0.97470148  1.00000000 0.95200572
z     0.95338738  0.09492388  0.1509287  0.97077180  0.95200572 1.00000000
xx    0.97509423 -0.02528925  0.1953443  1.00000000  0.97470148 0.97077180
               xx
carat  0.97509423
depth -0.02528925
table  0.19534428
x      1.00000000
y      0.97470148
z      0.97077180
xx     1.00000000
[1] "running model"
[1] "Importance matrix"
   Feature       Gain      Cover  Frequency
1:       x 0.37595419 0.54788335 0.19607102
2:   carat 0.19699839 0.18015576 0.04873442
3:   depth 0.15358261 0.08780079 0.27767284
4:       y 0.11645929 0.06527969 0.18813751
5:   table 0.09447853 0.05037063 0.17151492
6:       z 0.06252699 0.06850978 0.11786929

Modelo entrenado en diamantes, agregando una columna para x + y

Agregamos una nueva columna xy = x + y. Esto está parcialmente correlacionado con x e y.

Tenga en cuenta que la importancia de x e y se reduce ligeramente, pasando de 0.3759 a 0.3592 para x, y de 0.116 a 0.079 para y.

diamonds_xy = diamonds %>%
    mutate(xy=x+y)
evaluate_model(diamonds_xy)

[1] "Correlation matrix"
           carat       depth      table           x           y          z
carat 1.00000000  0.02822431  0.1816175  0.97509423  0.95172220 0.95338738
depth 0.02822431  1.00000000 -0.2957785 -0.02528925 -0.02934067 0.09492388
table 0.18161755 -0.29577852  1.0000000  0.19534428  0.18376015 0.15092869
x     0.97509423 -0.02528925  0.1953443  1.00000000  0.97470148 0.97077180
y     0.95172220 -0.02934067  0.1837601  0.97470148  1.00000000 0.95200572
z     0.95338738  0.09492388  0.1509287  0.97077180  0.95200572 1.00000000
xy    0.96945349 -0.02750770  0.1907100  0.99354016  0.99376929 0.96744200
              xy
carat  0.9694535
depth -0.0275077
table  0.1907100
x      0.9935402
y      0.9937693
z      0.9674420
xy     1.0000000
[1] "running model"
[1] "Importance matrix"
   Feature       Gain      Cover  Frequency
1:       x 0.35927767 0.52924339 0.15952849
2:   carat 0.17881931 0.18472506 0.04793713
3:   depth 0.14353540 0.07482622 0.24990177
4:   table 0.09202059 0.04714548 0.16267191
5:      xy 0.08203819 0.04706267 0.13555992
6:       y 0.07956856 0.05284980 0.13595285
7:       z 0.06474029 0.06414738 0.10844794

Modelo entrenado en datos de Diamantes, modificado agregando columnas redundantes

Agregamos tres nuevas columnas que están correlacionadas con x (r = 0.4, 0.5 y 0.6) y vemos qué sucede.

Tenga en cuenta que la importancia de x se reduce, cayendo de 0.3759 a 0.279.

#' given a vector of values (e.g. diamonds$x), calculate three new vectors correlated to it
#' 
#' Source: https://stat.ethz.ch/pipermail/r-help/2007-April/128938.html
calculate_correlated_vars = function(x1) {

    # create the initial x variable
    #x1 <- diamonds$x

    # x2, x3, and x4 in a matrix, these will be modified to meet the criteria
    x234 <- scale(matrix( rnorm(nrow(diamonds) * 3), ncol=3 ))

    # put all into 1 matrix for simplicity
    x1234 <- cbind(scale(x1),x234)

    # find the current correlation matrix
    c1 <- var(x1234)

    # cholesky decomposition to get independence
    chol1 <- solve(chol(c1))

    newx <-  x1234 %*% chol1 

    # check that we have independence and x1 unchanged
    zapsmall(cor(newx))
    all.equal( x1234[,1], newx[,1] )

    # create new correlation structure (zeros can be replaced with other r vals)
    newc <- matrix( 
    c(1  , 0.4, 0.5, 0.6, 
      0.4, 1  , 0  , 0  ,
      0.5, 0  , 1  , 0  ,
      0.6, 0  , 0  , 1  ), ncol=4 )

    # check that it is positive definite
    eigen(newc)

    chol2 <- chol(newc)

    finalx <- newx %*% chol2 * sd(x1) + mean(x1)

    # verify success
    mean(x1)
    colMeans(finalx)

    sd(x1)
    apply(finalx, 2, sd)

    zapsmall(cor(finalx))
    #pairs(finalx)

    all.equal(x1, finalx[,1])
    finalx
}
finalx = calculate_correlated_vars(diamonds$x)
diamonds_cor = diamonds
diamonds_cor$x5 = finalx[,2]
diamonds_cor$x6 = finalx[,3]
diamonds_cor$x7 = finalx[,4]
evaluate_model(diamonds_cor)
[1] "Correlation matrix"
           carat        depth       table           x           y          z
carat 1.00000000  0.028224314  0.18161755  0.97509423  0.95172220 0.95338738
depth 0.02822431  1.000000000 -0.29577852 -0.02528925 -0.02934067 0.09492388
table 0.18161755 -0.295778522  1.00000000  0.19534428  0.18376015 0.15092869
x     0.97509423 -0.025289247  0.19534428  1.00000000  0.97470148 0.97077180
y     0.95172220 -0.029340671  0.18376015  0.97470148  1.00000000 0.95200572
z     0.95338738  0.094923882  0.15092869  0.97077180  0.95200572 1.00000000
x5    0.39031255 -0.007507604  0.07338484  0.40000000  0.38959178 0.38734145
x6    0.48879000 -0.016481580  0.09931705  0.50000000  0.48835896 0.48487442
x7    0.58412252 -0.013772440  0.11822089  0.60000000  0.58408881 0.58297414
                 x5            x6            x7
carat  3.903125e-01  4.887900e-01  5.841225e-01
depth -7.507604e-03 -1.648158e-02 -1.377244e-02
table  7.338484e-02  9.931705e-02  1.182209e-01
x      4.000000e-01  5.000000e-01  6.000000e-01
y      3.895918e-01  4.883590e-01  5.840888e-01
z      3.873415e-01  4.848744e-01  5.829741e-01
x5     1.000000e+00  5.925447e-17  8.529781e-17
x6     5.925447e-17  1.000000e+00  6.683397e-17
x7     8.529781e-17  6.683397e-17  1.000000e+00
[1] "running model"
[1] "Importance matrix"
   Feature       Gain      Cover  Frequency
1:       x 0.27947762 0.51343709 0.09748172
2:   carat 0.13556427 0.17401365 0.02680747
3:      x5 0.13369515 0.05267688 0.18155971
4:      x6 0.12968400 0.04804315 0.19821284
5:      x7 0.10600238 0.05148826 0.16450041
6:   depth 0.07087679 0.04485760 0.11251015
7:       y 0.06050565 0.03896716 0.08245329
8:   table 0.04577057 0.03135677 0.07554833
9:       z 0.03842355 0.04515944 0.06092608
dalloliogm
fuente
6

Hay una respuesta de Tianqi Chen (2018).

Esta diferencia tiene un impacto en un caso de esquina en el análisis de importancia de características: las características correlacionadas. Imagine dos características perfectamente correlacionadas, la característica A y la característica B. Para un árbol específico, si el algoritmo necesita una de ellas, elegirá al azar (verdadero tanto en Boosting como en Random Forests ™).

Sin embargo, en Random Forests ™ esta elección aleatoria se hará para cada árbol, porque cada árbol es independiente de los demás. Por lo tanto, de manera aproximada, dependiendo de sus parámetros, el 50% de los árboles elegirán la característica A y el otro 50% elegirá la característica B. Entonces, la importancia de la información contenida en A y B (que es la misma, porque están perfectamente correlacionadas ) se diluye en A y B. Por lo tanto, no sabrá fácilmente que esta información es importante para predecir lo que desea predecir. Es aún peor cuando tienes 10 características correlacionadas ...

Al impulsar, cuando el algoritmo ha aprendido un vínculo específico entre la característica y el resultado, intentará no volver a centrarse en él (en teoría es lo que sucede, la realidad no siempre es así de simple). Por lo tanto, toda la importancia estará en la función A o en la función B (pero no en ambas). Sabrá que una característica tiene un papel importante en el vínculo entre las observaciones y la etiqueta. Todavía depende de usted buscar las funciones correlacionadas con la que se detectó como importante si necesita conocerlas todas.

Para resumir, Xgboost no utiliza aleatoriamente las características correlacionadas en cada árbol, que modelo de bosque aleatorio sufre de tal situación.

Referencia :

Tianqi Chen, Michaël Benesty, Tong He. 2018. "Comprenda su conjunto de datos con Xgboost" . Https://cran.r-project.org/web/packages/xgboost/vignettes/discoverYourData.html#numeric-vs-categorical-variables .

Jiaxiang
fuente
2

Una observación sobre la respuesta de Sandeep: suponiendo que 2 de sus funciones sean altamente colineales (digamos igual al 99% del tiempo) De hecho, solo se selecciona 1 función en cada división, pero para la siguiente división, el xgb puede seleccionar la otra función. Por lo tanto, la clasificación de características xgb probablemente clasificará las 2 características colineales por igual. Sin algún conocimiento previo u otro procesamiento de características, casi no tiene medios de esta clasificación proporcionada para detectar que las 2 características son colineales.

Ahora, en cuanto a la importancia relativa que genera el xgboost, debería ser muy similar (o tal vez exactamente similar) a la clasificación del árbol impulsado por el gradiente de sklearn. Ver aquí para explicaciones.

PSAfrance
fuente