XGBoost gère-t-il la multicolinéarité par lui-même?

23

J'utilise actuellement XGBoost sur un ensemble de données avec 21 fonctionnalités (sélectionnées dans la liste de quelque 150 fonctionnalités), puis je les ai codées à chaud pour obtenir ~ 98 fonctionnalités. Certaines de ces 98 fonctionnalités sont quelque peu redondantes, par exemple: une variable (fonctionnalité) apparaît également comme BA etCBA .CA

Mes questions sont:

  • Comment ( si? ) Les arbres de décision boostés gèrent-ils la multicolinéarité?
  • Comment l'existence de la multicolinéarité affecterait-elle la prédiction si elle n'était pas gérée?

D'après ce que je comprends, le modèle apprend plus d'un arbre et la prédiction finale est basée sur quelque chose comme une «somme pondérée» des prédictions individuelles. Donc, si cela est correct, les arbres de décision boostés devraient être capables de gérer la co-dépendance entre les variables.

En outre, sur une note connexe - comment fonctionne l'objet d'importance variable dans XGBoost?

user140323
la source
Je comprends que les arbres peuvent gérer la multicolinéarité. Mais qu'en est-il du XGBoost basé sur la régression? Peut-il également gérer la multi-colinéarité? > Les arbres de décision sont par nature immunisés contre la multi-colinéarité. Par exemple, si vous avez 2 fonctionnalités qui sont corrélées à 99%, lorsque vous décidez d'une division, l'arborescence n'en choisira qu'une. D'autres modèles tels que la régression logistique utiliseraient les deux fonctionnalités. >> Puisque les arbres boostés utilisent des arbres de décision individuels, ils ne sont pas non plus affectés par la multi-colinéarité. Cependant, c'est une bonne pratique pour> supprimer toutes les fonctionnalités redondantes de tout ensemble de données utilisé pour tra
Jay Saxena

Réponses:

27

Les arbres de décision sont par nature immunisés contre la multi-colinéarité. Par exemple, si vous avez 2 fonctionnalités qui sont corrélées à 99%, lorsque vous décidez d'une division, l'arborescence n'en choisit qu'une. D'autres modèles tels que la régression logistique utiliseraient les deux fonctionnalités.

Étant donné que les arbres boostés utilisent des arbres de décision individuels, ils ne sont pas non plus affectés par la multi-colinéarité. Cependant, c'est une bonne pratique pour supprimer toutes les fonctionnalités redondantes de tout ensemble de données utilisé pour la formation, quel que soit l'algorithme du modèle. Dans votre cas, puisque vous dérivez de nouvelles fonctionnalités, vous pouvez utiliser cette approche, évaluer l'importance de chaque fonctionnalité et ne conserver que les meilleures fonctionnalités pour votre modèle final.

La matrice d'importance d'un modèle xgboost est en fait un objet data.table avec la première colonne listant les noms de toutes les fonctionnalités réellement utilisées dans les arbres boostés. La deuxième colonne est la métrique Gain qui implique la contribution relative de l'entité correspondante au modèle calculée en prenant la contribution de chaque entité pour chaque arbre du modèle. Une valeur plus élevée de cette métrique par rapport à une autre fonctionnalité implique qu'elle est plus importante pour générer une prédiction.

Sandeep S. Sandhu
la source
7

J'étais curieux à ce sujet et j'ai fait quelques tests.

J'ai formé un modèle sur l'ensemble de données sur les diamants et j'ai observé que la variable «x» est la plus importante pour prédire si le prix d'un diamant est supérieur à un certain seuil. Ensuite, j'ai ajouté plusieurs colonnes hautement corrélées à x, exécuté le même modèle et observé les mêmes valeurs.

Il semble que lorsque la corrélation entre deux colonnes est 1, xgboost supprime la colonne supplémentaire avant de calculer le modèle, de sorte que l'importance n'est pas affectée. Cependant, lorsque vous ajoutez une colonne partiellement corrélée à une autre, donc avec un coefficient inférieur, l'importance de la variable d'origine x est réduite.

Par exemple, si j'ajoute une variable xy = x + y, l'importance de x et y diminue. De même, l'importance de x diminue si j'ajoute de nouvelles variables avec r = 0,4, 0,5 ou 0,6, bien que juste un peu.

Je pense que la colinéarité n'est pas un problème pour booster lorsque vous calculez la précision du modèle, car l'arbre de décision ne se soucie pas de laquelle des variables est utilisée. Cependant, cela pourrait affecter l'importance des variables, car la suppression de l'une des deux variables corrélées n'a pas un grand impact sur la précision du modèle, étant donné que l'autre contient des informations similaires.

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

Évaluer un modèle sur les données diamants

Nous prédisons si le prix est supérieur à 400, compte tenu de toutes les variables numériques disponibles (carat, profondeur, tableau, x, y, x)

Notez que x est la variable la plus importante, avec un score de gain d'importance 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

Modèle formé sur les diamants, ajoutant une variable avec r = 1 à x

Ici, nous ajoutons une nouvelle colonne, qui n'ajoute cependant aucune nouvelle information, car elle est parfaitement corrélée à x.

Notez que cette nouvelle variable n'est pas présente dans la sortie. Il semble que xgboost supprime automatiquement les variables parfaitement corrélées avant de commencer le calcul. Le gain d'importance de x est le même, 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

Modèle formé sur les diamants, ajoutant une colonne pour x + y

Nous ajoutons une nouvelle colonne xy = x + y. Ceci est partiellement corrélé à la fois à x et à y.

Notez que l'importance de x et y est légèrement réduite, passant de 0,3759 à 0,3592 pour x, et de 0,116 à 0,079 pour 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

Modèle formé sur les données Diamonds, modifié en ajoutant des colonnes redondantes

Nous ajoutons trois nouvelles colonnes qui sont corrélées à x (r = 0,4, 0,5 et 0,6) et voyons ce qui se passe.

Notez que l'importance de x diminue, passant de 0,3759 à 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
la source
6

Il y a une réponse de Tianqi Chen (2018).

Cette différence a un impact sur un cas d'angle dans l'analyse d'importance des entités: les entités corrélées. Imaginez deux fonctionnalités parfaitement corrélées, la fonctionnalité A et la fonctionnalité B. Pour un arbre spécifique, si l'algorithme en a besoin, il choisira de manière aléatoire (vrai à la fois pour le boosting et pour Random Forests ™).

Cependant, dans Random Forests ™, ce choix aléatoire sera fait pour chaque arbre, car chaque arbre est indépendant des autres. Par conséquent, approximativement, en fonction de vos paramètres, 50% des arbres choisiront la caractéristique A et les 50% restants choisiront la caractéristique B. Donc, l'importance des informations contenues dans A et B (qui est la même, car elles sont parfaitement corrélées) ) est dilué en A et B. Vous ne saurez donc pas facilement que cette information est importante pour prédire ce que vous voulez prédire! C'est encore pire quand vous avez 10 fonctionnalités corrélées…

En boostant, lorsqu'un lien spécifique entre fonctionnalité et résultat a été appris par l'algorithme, il va essayer de ne pas se recentrer sur lui (en théorie c'est ce qui se passe, la réalité n'est pas toujours aussi simple). Par conséquent, toute l'importance sera accordée à la fonctionnalité A ou à la fonctionnalité B (mais pas les deux). Vous saurez qu'une fonction joue un rôle important dans le lien entre les observations et l'étiquette. C'est toujours à vous de rechercher les fonctionnalités corrélées à celle détectée comme importante si vous avez besoin de toutes les connaître.

Pour résumer, Xgboost n'utilise pas au hasard les caractéristiques corrélées de chaque arbre, quel modèle de forêt aléatoire souffre d'une telle situation.

Référence :

Tianqi Chen, Michaël Benesty, Tong He. 2018. «Comprendre votre ensemble de données avec Xgboost» . Https://cran.r-project.org/web/packages/xgboost/vignettes/discoverYourData.html#numeric-vs-categorical-variables .

Jiaxiang
la source
2

Une remarque sur la réponse de Sandeep: en supposant que 2 de vos fonctionnalités sont hautement colinéaires (disons égales à 99% du temps). Par conséquent, le classement des entités xgb classera probablement les 2 entités colinéaires de manière égale. Sans connaissances préalables ou traitement des autres fonctionnalités, vous n'avez pratiquement aucun moyen à partir de ce classement fourni pour détecter que les 2 fonctionnalités sont colinéaires.

Maintenant, en ce qui concerne l'importance relative qui produit xgboost, elle devrait être très similaire (ou peut-être exactement similaire) au classement de l'arbre boosté par le gradient sklearn. Voir ici pour les explications.

PSAfrance
la source