XGBoost는 다중 공선 성을 자체적으로 처리합니까?


23

현재 21 개의 기능 (약 150 개의 기능 목록에서 선택)이있는 데이터 세트에서 XGBoost를 사용하고 있으며 ~ 98 개의 기능을 얻기 위해 핫 코드로 코딩했습니다. 이러한 98 가지 기능 중 일부는 예를 들어 중복됩니다. 변수 (기능) 도 및 .에이에이기음에이

내 질문은 :

  • 어떻게 ( 만약? ) 의사 결정 트리 핸들 다중 공선을 힘 입어합니까?
  • 다중 공선 성이 존재하면 예측이 처리되지 않으면 예측에 어떤 영향을 미칩니 까?

내가 이해 한 바에 따르면, 모델은 하나 이상의 트리를 학습하고 최종 예측은 개별 예측의 "가중 합"과 같은 것을 기반으로합니다. 따라서 이것이 정확하다면 Boosted Decision Trees 변수 간의 상호 의존성을 처리 할 수 ​​있어야합니다.

또한 관련 참고 사항-XGBoost의 변수 중요도 개체는 어떻게 작동합니까?


나무가 다중 공선 성을 처리 할 수 ​​있다는 것을 알고 있습니다. 그러나 회귀 기반 XGBoost는 어떻습니까? 다중 공선 성도 처리 할 수 ​​있습니까? > 의사 결정 나무는 본질적으로 다중 공선성에 면역성이 있습니다. 예를 들어, 99 % 상관 된 2 개의 피처가있는 경우> 분할을 결정할 때 트리는 그 중 하나만 선택합니다. 로지스틱 회귀와 같은 다른 모델은 두 기능을 모두 사용합니다. 부스트 트리는 개별 의사 결정 트리를 사용하기 때문에 다중 공선성에 영향을받지 않습니다. 그러나 tra에 사용 된 모든 데이터 세트에서 중복 기능을 제거하는 것이 좋습니다.
Jay Saxena

답변:


27

의사 결정 트리는 본질적으로 다중 공선성에 면역입니다. 예를 들어, 99 % 상관 된 2 개의 피쳐가있는 경우 분할을 결정할 때 트리는 그 중 하나만 선택합니다. 로지스틱 회귀와 같은 다른 모델은 두 기능을 모두 사용합니다.

부스트 트리는 개별 의사 결정 트리를 사용하기 때문에 다중 공선성에 영향을받지 않습니다. 그러나 모델 알고리즘에 관계없이 교육에 사용 된 모든 데이터 세트에서 중복 기능을 제거하는 것이 좋습니다. 새 기능을 파생시키기 때문에이 방법을 사용하고 각 기능의 중요성을 평가하며 최종 모델에 가장 적합한 기능 만 유지할 수 있습니다.

xgboost 모델의 중요도 행렬은 실제로 boosted 트리에서 실제로 사용 된 모든 기능의 이름을 나열하는 첫 번째 열이있는 data.table 객체입니다. 두 번째 열은 모델의 각 트리에 대한 각 기능의 기여를 계산하여 계산 된 모델에 대한 해당 기능의 상대적 기여를 암시하는 게인 메트릭입니다. 다른 측정 항목과 비교할 때이 측정 항목의 값이 높을수록 예측 생성에 더 중요합니다.


7

나는 이것에 대해 궁금했고 몇 가지 테스트를했습니다.

다이아몬드 데이터 세트에 대한 모델을 학습했으며, 다이아몬드 가격이 특정 임계 값보다 높은지 여부를 예측하는 데 변수 "x"가 가장 중요하다는 것을 관찰했습니다. 그런 다음 x와 관련성이 높은 여러 열을 추가하고 동일한 모델을 실행하고 동일한 값을 관찰했습니다.

두 열 사이의 상관 관계가 1 인 경우 xgboost는 모델을 계산하기 전에 추가 열을 제거하므로 중요도에 영향을 미치지 않습니다. 그러나 부분적으로 다른 열과 상관 관계가있는 열을 추가하여 계수가 낮 으면 원래 변수 x의 중요성이 낮아집니다.

예를 들어 변수 xy = x + y를 추가하면 x와 y의 중요성이 감소합니다. 마찬가지로 r = 0.4, 0.5 또는 0.6 인 새 변수를 조금만 추가해도 x의 중요성이 줄어 듭니다.

의사 결정 트리는 사용되는 변수 중 하나를 신경 쓰지 않기 때문에 모형의 정확도를 계산할 때 공선 성이 부스팅에 문제가되지 않는다고 생각합니다. 그러나 상관 관계가있는 두 변수 중 하나를 제거해도 다른 정보가 비슷한 경우 모델의 정확도에 큰 영향을 미치지 않기 때문에 변수의 중요성에 영향을 줄 수 있습니다.

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

다이아몬드 데이터에서 모델 평가

사용 가능한 모든 숫자 변수 (캐럿, 깊이, 테이블, x, y, x)를 고려할 때 가격이 400보다 높은지 예측합니다.

x는 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

x에 r = 1 인 변수를 추가하여 다이아몬드에 대해 훈련 된 모델

여기에 새로운 열을 추가하지만 x와 완벽하게 상관되어 있으므로 새로운 정보를 추가하지 않습니다.

이 새 변수는 출력에 없습니다. xgboost는 계산을 시작하기 전에 완벽하게 상관 된 변수를 자동으로 제거하는 것으로 보입니다. x의 중요도는 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

x + y에 대한 열을 추가하여 다이아몬드에 대해 훈련 된 모델

새로운 열 xy = x + y를 추가합니다. 이것은 부분적으로 x와 y와 상관됩니다.

x와 y의 중요성은 x의 경우 0.3759에서 0.3592로, y의 경우 0.116에서 0.079로 약간 줄어 듭니다.

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

다이아몬드 데이터에 대해 훈련 된 모델, 중복 열을 추가하여 수정

x (r = 0.4, 0.5 및 0.6)와 상관 관계가있는 3 개의 새로운 열을 추가하고 결과를 확인합니다.

x의 중요성이 줄어들면서 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

6

Tianqi Chen (2018)의 답변이 있습니다.

이 차이점은 피처 중요도 분석에서 상관 관계있는 피처에 영향을 미칩니다. 기능 A와 기능 B가 완벽하게 상관 된 두 기능을 상상해보십시오. 하나의 특정 트리에 대해 알고리즘 중 하나가 필요한 경우 임의로 선택합니다 (부스팅 및 랜덤 포레스트 ™ 모두에 해당).

그러나 Random Forests ™에서는 각 트리가 다른 트리와 독립적이기 때문에 각 트리에 대해이 임의의 선택이 수행됩니다. 따라서 대략적으로 매개 변수에 따라 트리의 50 %가 피처 A를 선택하고 다른 50 %는 피처 B를 선택합니다. 따라서 A와 B에 포함 된 정보의 중요성 (완전히 상관되어 있기 때문에 동일 함) )는 A와 B로 희석되어 있으므로 예측하려는 내용을 예측하는 데이 정보가 중요하다는 것을 쉽게 알 수 없습니다! 상관 된 기능이 10 개 있으면 더 나빠집니다…

부스팅에서 알고리즘이 기능과 결과 사이의 특정 링크를 알게되면 다시 초점을 맞추려고하지 않습니다 (이론적으로 발생하는 상황에서 현실이 항상 그렇게 단순하지는 않습니다). 따라서 중요한 것은 기능 A 또는 기능 B에 있습니다 (둘다는 아님). 관찰과 레이블 사이의 링크에서 하나의 기능이 중요한 역할을한다는 것을 알게 될 것입니다. 상관 관계가있는 모든 기능을 알아야하는 경우 중요한 것으로 감지 된 기능을 검색하는 것은 여전히 ​​사용자의 몫입니다.

요약하면, Xgboost는 각 트리에서 상관 된 기능을 임의로 사용하지 않으며, 임의의 포리스트 모델은 이러한 상황으로 인해 어려움을 겪습니다.

참고 :

Tianqi Chen, Michaël Benesty, Tong He. 2018.“Xgboost로 데이터 세트 이해.” https://cran.r-project.org/web/packages/xgboost/vignettes/discoverYourData.html#numeric-vs-categorical-variables .


2

Sandeep의 답변에 대한 언급 : 두 기능이 동일 선상에 있다고 가정하면 (시간의 99 %와 동일) 각 분할에서 하나의 기능 만 선택되지만 다음 분할에서는 xgb가 다른 기능을 선택할 수 있습니다. 따라서 xgb 피쳐 순위는 아마도 2 개의 동일 선형 피쳐의 순위를 지정할 것입니다. 사전 지식이나 기타 피쳐 처리가 없으면이 제공된 순위에서 두 피쳐가 동일 선상에 있음을 감지 할 수단이 거의 없습니다.

이제 xgboost를 출력하는 상대적인 중요성에 대해서는 sklearn gradient boostined tree rank와 매우 유사해야합니다. 설명 은 여기 를 참조 하십시오 .

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.