XGBoost gestisce la multicollinearità da sola?


23

Attualmente sto usando XGBoost su un set di dati con 21 funzionalità (selezionate dall'elenco di circa 150 funzionalità), quindi le ho codificate a caldo per ottenere ~ 98 funzionalità. Alcune di queste 98 funzionalità sono in qualche modo ridondanti, ad esempio: una variabile (funzione) appare anche come e .UNBUNCUN

Le mie domande sono:

  • Come ( se? ) Gli alberi decisionali potenziati gestiscono la multicollinearità?
  • In che modo l'esistenza della multicollinearità influirebbe sulla previsione se non fosse gestita?

Da quello che ho capito, il modello sta imparando più di un albero e la previsione finale si basa su qualcosa come una "somma ponderata" delle singole previsioni. Quindi, se questo è corretto, allora gli alberi decisionali potenziati dovrebbero essere in grado di gestire la co-dipendenza tra le variabili.

Inoltre, in una nota correlata: come funziona l'oggetto a importanza variabile in XGBoost?


Capisco che gli alberi sono in grado di gestire la multicollinearità. Ma che dire dell'XGBoost basato sulla regressione? Può gestire anche la multi-collinearità? > Gli alberi decisionali sono per natura immuni alla multi-collinearità. Ad esempio, se hai 2 caratteristiche correlate al 99%, quando> decidendo su una divisione l'albero sceglierà solo una di esse. Altri modelli> come la regressione logistica utilizzerebbero entrambe le funzionalità. >> Dato che gli alberi potenziati usano singoli alberi decisionali, sono anche> non influenzati dalla multi-collinearità. Tuttavia, è buona norma> rimuovere eventuali funzionalità ridondanti da qualsiasi set di dati utilizzato per tra
Jay Saxena,

Risposte:


27

Gli alberi decisionali sono per natura immuni alla multi-collinearità. Ad esempio, se hai 2 caratteristiche che sono correlate al 99%, quando scegli una divisione l'albero sceglierà solo una di esse. Altri modelli come la regressione logistica utilizzerebbero entrambe le funzionalità.

Poiché gli alberi potenziati utilizzano alberi decisionali individuali, non sono interessati dalla multi-collinearità. Tuttavia, è buona norma rimuovere tutte le funzionalità ridondanti da qualsiasi set di dati utilizzato per la formazione, indipendentemente dall'algoritmo del modello. Nel tuo caso, poiché stai derivando nuove funzionalità, puoi utilizzare questo approccio, valutare l'importanza di ciascuna funzionalità e conservare solo le migliori funzionalità per il tuo modello finale.

La matrice di importanza di un modello xgboost è in realtà un oggetto data.table con la prima colonna che elenca i nomi di tutte le funzionalità effettivamente utilizzate negli alberi potenziati. La seconda colonna è la metrica Guadagno che implica il contributo relativo della caratteristica corrispondente al modello calcolato prendendo il contributo di ciascuna caratteristica per ciascun albero nel modello. Un valore più elevato di questa metrica rispetto a un'altra caratteristica implica che è più importante per generare una previsione.


7

Ero curioso di questo e ho fatto alcuni test.

Ho addestrato un modello sul set di dati di diamanti e ho osservato che la variabile "x" è la più importante per prevedere se il prezzo di un diamante è superiore a una determinata soglia. Quindi, ho aggiunto più colonne altamente correlate a x, ho eseguito lo stesso modello e osservato gli stessi valori.

Sembra che quando la correlazione tra due colonne sia 1, xgboost rimuove la colonna aggiuntiva prima di calcolare il modello, quindi l'importanza non viene influenzata. Tuttavia, quando si aggiunge una colonna parzialmente correlata a un'altra, quindi con un coefficiente inferiore, viene ridotta l'importanza della variabile originale x.

Ad esempio, se aggiungo una variabile xy = x + y, l'importanza di x e y diminuisce. Allo stesso modo, l'importanza di x diminuisce se aggiungo nuove variabili con r = 0.4, 0.5 o 0.6, anche se solo di un po '.

Penso che la collinearità non sia un problema per aumentare quando si calcola l'accuratezza del modello, perché l'albero decisionale non importa quale delle variabili viene utilizzata. Tuttavia, potrebbe influire sull'importanza delle variabili, poiché la rimozione di una delle due variabili correlate non ha un grande impatto sull'accuratezza del modello, dato che l'altra contiene informazioni simili.

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

Valuta un modello sui dati dei diamanti

Prevediamo se il prezzo è superiore a 400, date tutte le variabili numeriche disponibili (carati, profondità, tabella, x, y, x)

Si noti che x è la variabile più importante, con un punteggio di guadagno di importanza di 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

Modello addestrato su Diamanti, aggiungendo una variabile con r = 1 a x

Qui aggiungiamo una nuova colonna, che tuttavia non aggiunge alcuna nuova informazione, poiché è perfettamente correlata a x.

Si noti che questa nuova variabile non è presente nell'output. Sembra che xgboost rimuova automaticamente le variabili perfettamente correlate prima di iniziare il calcolo. Il guadagno di importanza di x è lo stesso, 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

Modello addestrato su Diamanti, aggiungendo una colonna per x + y

Aggiungiamo una nuova colonna xy = x + y. Questo è parzialmente correlato sia a x che a y.

Si noti che l'importanza di xey è leggermente ridotta, passando da 0,3759 a 0,3592 per xe da 0,116 a 0,079 per 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

Modello addestrato sui dati Diamonds, modificato con l'aggiunta di colonne ridondanti

Aggiungiamo tre nuove colonne correlate a x (r = 0.4, 0.5 e 0.6) e vediamo cosa succede.

Si noti che l'importanza di x viene ridotta, passando da 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

6

C'è una risposta da Tianqi Chen (2018).

Questa differenza ha un impatto su un caso angolare nell'analisi dell'importanza delle caratteristiche: le caratteristiche correlate. Immagina due funzioni perfettamente correlate, la funzione A e la funzione B. Per un albero specifico, se l'algoritmo ne ha bisogno, ne sceglierà una a caso (vero sia in potenziamento che in Random Forests ™).

Tuttavia, in Random Forests ™ questa scelta casuale verrà effettuata per ciascun albero, poiché ogni albero è indipendente dagli altri. Pertanto, approssimativamente, a seconda dei parametri, il 50% degli alberi sceglierà la funzione A e l'altro 50% sceglierà la funzione B. Quindi l'importanza delle informazioni contenute in A e B (che è la stessa, perché sono perfettamente correlate ) è diluito in A e B. Quindi non saprai facilmente che queste informazioni sono importanti per prevedere ciò che vuoi prevedere! È ancora peggio quando hai 10 funzioni correlate ...

Nel potenziamento, quando l'algoritmo ha appreso un legame specifico tra funzionalità ed esito, cercherà di non focalizzarsi di nuovo su di esso (in teoria è ciò che accade, la realtà non è sempre così semplice). Pertanto, tutta l'importanza sarà sulla funzione A o sulla funzione B (ma non su entrambi). Saprai che una caratteristica ha un ruolo importante nel collegamento tra le osservazioni e l'etichetta. Sta ancora a te cercare le funzionalità correlate a quelle rilevate come importanti se devi conoscerle tutte.

Riassumendo, Xgboost non usa casualmente le caratteristiche correlate in ogni albero, il cui modello di foresta casuale soffre di una tale situazione.

Riferimento :

Tianqi Chen, Michaël Benesty, Tong He. 2018. "Comprendi il tuo set di dati con Xgboost." Https://cran.r-project.org/web/packages/xgboost/vignettes/discoverYourData.html#numeric-vs-categorical-variables .


2

Un'osservazione sulla risposta di Sandeep: Supponendo che 2 delle tue funzioni siano altamente colinear (diciamo pari al 99% del tempo) In effetti è selezionata solo 1 funzione per ogni divisione, ma per la divisione successiva, l'xgb può selezionare l'altra funzione. Pertanto, la classifica delle funzioni xgb probabilmente classificherà le 2 caratteristiche lineari allo stesso modo. Senza alcune conoscenze preliminari o altre elaborazioni di funzionalità, non si ha quasi alcun mezzo da questa classifica fornita per rilevare che le 2 funzionalità siano colinear.

Ora, per quanto riguarda l'importanza relativa che genera l'xgboost, dovrebbe essere molto simile (o forse esattamente simile) alla classifica dell'albero potenziata con gradiente sklearn. Vedi qui per le spiegazioni.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.