Byłem tego ciekawy i przeprowadziłem kilka testów.
Przeszkoliłem model zestawu danych o diamentach i zauważyłem, że zmienna „x” jest najważniejsza do przewidzenia, czy cena diamentu jest wyższa niż określony próg. Następnie dodałem wiele kolumn silnie skorelowanych z x, uruchomiłem ten sam model i zaobserwowałem te same wartości.
Wydaje się, że gdy korelacja między dwiema kolumnami wynosi 1, xgboost usuwa dodatkową kolumnę przed obliczeniem modelu, więc nie ma to wpływu na ważność. Jednak po dodaniu kolumny częściowo skorelowanej z inną, a więc o niższym współczynniku, ważność oryginalnej zmiennej x jest zmniejszana.
Na przykład, jeśli dodam zmienną xy = x + y, znaczenie zarówno x, jak i y maleje. Podobnie znaczenie x maleje, jeśli dodam nowe zmienne o wartości r = 0,4, 0,5 lub 0,6, choć tylko odrobinę.
Myślę, że kolinearność nie stanowi problemu dla wzmocnienia, gdy obliczasz dokładność modelu, ponieważ drzewo decyzyjne nie dba o to, która ze zmiennych jest używana. Może to jednak wpłynąć na ważność zmiennych, ponieważ usunięcie jednej z dwóch skorelowanych zmiennych nie ma dużego wpływu na dokładność modelu, biorąc pod uwagę, że druga zawiera podobne informacje.
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
Oceń model na podstawie danych diamentów
Przewidujemy, czy cena jest wyższa niż 400, biorąc pod uwagę wszystkie dostępne zmienne numeryczne (karat, głębokość, tabela, x, y, x)
Zauważ, że x jest najważniejszą zmienną, z wynikiem przyrostu ważności wynoszącym 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
Model trenowany na diamentach, dodając zmienną o wartości r = 1 do x
Tutaj dodajemy nową kolumnę, która jednak nie dodaje żadnych nowych informacji, ponieważ jest doskonale skorelowana z x.
Zauważ, że ta nowa zmienna nie jest obecna na wyjściu. Wydaje się, że xgboost automatycznie usuwa doskonale skorelowane zmienne przed rozpoczęciem obliczeń. Wzrost znaczenia x jest taki sam, 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
Model trenowany na Diamentach, dodając kolumnę dla x + y
Dodajemy nową kolumnę xy = x + y. Jest to częściowo skorelowane zarówno z x, jak i y.
Zauważ, że znaczenie xiy jest nieco zmniejszone, z 0,3759 do 0,3592 dla xi od 0,116 do 0,079 dla 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
Model wytrenowany na danych diamentów, zmodyfikowany przez dodanie zbędnych kolumn
Dodajemy trzy nowe kolumny, które są skorelowane z x (r = 0,4, 0,5 i 0,6) i widzimy, co się stanie.
Zauważ, że znaczenie x zmniejsza się, z 0,3759 do 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