library(tidyverse)
library(data.table)
library(recipes)
library(broom)
다중공선성 의미
다중공선성은 설명변수 간에 높은 상관관계가 존재하는 경우를 의미한다. 보통 설명변수 간의 correlation plot을 참고해서 다중공선성 여부를 1차적으로 확인할 수 있다. 다만 다중공선성은 각 변수의 pair 관계의 상관관계가 아닌 다변수간의 상관관계를 의미하는 포괄적인 개념이므로, correlation plot과 분산팽창계수(
다중공선성이 있을 경우 발생하는 문제점
다중공선성이 있을 경우 회귀계수 추정량의 분산이 커지는 문제가 있다. 추정량의 분산이 크다는 의미는 데이터가 바뀌었을 때, 값의 변동이 크다는 의미이고, 이는 데이터를 통해 구한 회귀계수를 신뢰할 수 없다는 것을 의미한다.
Example
먼저 다중회귀모형에서 다중공선성이 있을 때, 회귀계수의 추정량의 분산이 어떻게 변화하는지를 알아보자.
간단하게, 설명변수
표준화된 설명변수
<- matrix(c(1, 0.99, 0.85, 0.99, 1, 0.95, 0.85, 0.95, 1), ncol = 3)
xtx xtx
[,1] [,2] [,3]
[1,] 1.00 0.99 0.85
[2,] 0.99 1.00 0.95
[3,] 0.85 0.95 1.00
solve(xtx)
[,1] [,2] [,3]
[1,] -15.60 29.20 -14.480
[2,] 29.20 -44.40 17.360
[3,] -14.48 17.36 -3.184
분산팽창계수(variance inflation factor)
다중공선성을 측정하는 대표적인 측도로 분산팽창계수가 있다.
Example
set.seed(1)
<- rnorm(10)
X1 <- X1*runif(10)
X2 <- rnorm(10)
y <- data.frame(X1, X2, y)
dat
cor(dat)
X1 X2 y
X1 1.0000000 0.8207918 -0.2047086
X2 0.8207918 1.0000000 -0.5307451
y -0.2047086 -0.5307451 1.0000000
<- lm(y~., dat) fit
library(car)
vif(fit)
X1 X2
3.064656 3.064656
<- lm(X1 ~ .-y, dat)
fit2 <- glance(fit2)
result
1/(1-result$r.squared)
[1] 3.064656
해석을 해보면
condition number
다중공선성은
condition number는 R base 함수인 kappa()
를 통해 구할 수 있다.
<- t(model.matrix(fit))%*%model.matrix(fit)
xtx kappa(xtx, exact = T)
[1] 33.00623
<- svd(xtx)
svd_d $d[1]/svd_d$d[3] svd_d
[1] 33.00623
보통
generalized linear model에서의 다중공선성 문제
일반화선형모형의 경우
이전의 선형모형과 유사하게, 일반화선형모형의
Example
set.seed(1)
<- rnorm(10)
X1 <- X1*runif(10)
X2 <- rbinom(10, 1, 0.3)
y <- data.frame(X1, X2, y)
dat
<- glm(y~., family = binomial, dat) fit
vcov()
를 통해 구할 수 있다.
vcov(fit)
(Intercept) X1 X2
(Intercept) 0.9009862 -0.7664066 0.6210139
X1 -0.7664066 3.5509802 -7.4328529
X2 0.6210139 -7.4328529 28.2736799
<- fit$fitted.values
p <- p*(1-p)
w <- model.matrix(fit)
X
solve(t(X)%*%diag(w)%*%X)
(Intercept) X1 X2
(Intercept) 0.9009921 -0.7664113 0.6210083
X1 -0.7664113 3.5509949 -7.4329015
X2 0.6210083 -7.4329015 28.2739839
vcov()
의
tidy(fit)$std.error[1]^2
[1] 0.9009862
따라서 GLM에서도 다중회귀모형과 마찬가지로, 모형 적합 시에 다중공선성도 체크해줘야 한다.
generalized variance inflation factor (GVIF)
일반적으로 vif는 범주형변수 혹은 polynomial 항에 대해서는 계산하지 않는다. 모델의 기본적인 구조에 의해 가상으로 생성되는 항이기 때문이다. 범주형변수 혹은 polynomial 항에 대해서 vif를 계산하고자 한다면 GVIF를 고려해볼 수 있다.
먼저 다음과 같은 회귀식을 고려해보자.
: indicator variable or polynomial term : 을 제외한 나머지 수치형 변수
: 의 correlation matrix : 를 제외한 전체의 correlation matrix
GVIF는 전체 변수의 상관행렬의 determinant에서 범주형변수의 상관행렬의 determinant가 차지하는 비율로 정의되는 것을 확인할 수 있다.
Example
먼저 iris 데이터로 GVIF를 계산결과를 확인해본다. iris 데이터에는 species 변수가 범주형 변수이므로, species 변수에 대해서 GVIF를 계산해본다.
%>% str() iris
'data.frame': 150 obs. of 5 variables:
$ Sepal.Length: num 5.1 4.9 4.7 4.6 5 5.4 4.6 5 4.4 4.9 ...
$ Sepal.Width : num 3.5 3 3.2 3.1 3.6 3.9 3.4 3.4 2.9 3.1 ...
$ Petal.Length: num 1.4 1.4 1.3 1.5 1.4 1.7 1.4 1.5 1.4 1.5 ...
$ Petal.Width : num 0.2 0.2 0.2 0.2 0.2 0.4 0.3 0.2 0.2 0.1 ...
$ Species : Factor w/ 3 levels "setosa","versicolor",..: 1 1 1 1 1 1 1 1 1 1 ...
<- iris %>%
iris_dat mutate(Species = as.factor(Species))
<- lm(Sepal.Length~., iris)
fit <- model.matrix(fit) X
먼저 design matrix를 구해서 X로 저장한다.
<- X[, 5:6]
X1 <- X[, 2:4]
X2 <- X[,-1] X_nonconst
det(cor(X1))*det(cor(X2)))/det(cor(X_nonconst)) (
[1] 40.03918
::vif(fit) car
GVIF Df GVIF^(1/(2*Df))
Sepal.Width 2.227466 1 1.492470
Petal.Length 23.161648 1 4.812655
Petal.Width 21.021401 1 4.584910
Species 40.039177 2 2.515482
species
에 대한 계산 결과는 car::vif()
와 같은 것을 확인할 수 있다.
어떻게 처리해야 하는가?
- 그냥 처리하지 않는다
- 풀고자 하는 문제가 예측 task라면 갖고 있는 데이터가 대표성이 있다는 가정 하에 크게 문제가 되지 않는다.
- 변수를 제거한다
- 변수 간의 의미가 중복되는 경우 제거하는 것을 고려해볼 수 있다
- 다항식 혹은 상호작용항의 경우 중심화를 통해 다중공선성을 보정해볼 수 있다
- 주성분 분석을 통해 다중공선성이 높은 변수를 그룹화할 수 있다
- LASSO regression을 통해 변수 선택을 고려해볼 수 있다
Example
3번 중심화의 영향을 예시로 알아보자
<- lm(Sepal.Length~. + Petal.Length*Sepal.Width, iris)
fit1 ::vif(fit1) car
there are higher-order terms (interactions) in this model
consider setting type = 'predictor'; see ?vif
GVIF Df GVIF^(1/(2*Df))
Sepal.Width 7.338253 1 2.708921
Petal.Length 102.800499 1 10.139058
Petal.Width 22.012759 1 4.691776
Species 41.330982 2 2.535531
Sepal.Width:Petal.Length 72.972392 1 8.542388
Sepal.Width:Petal.Length를 상호작용항으로 추가했을 때, vif는 8.54로 높은 것을 볼 수 있다.
library(recipes)
<- iris %>%
center_dat recipe(Sepal.Length~.) %>%
step_center(all_numeric_predictors()) %>%
step_interact(~Petal.Length:Sepal.Width) %>%
prep() %>%
juice()
<- lm(Sepal.Length~., center_dat)
fit2 ::vif(fit2) car
GVIF Df GVIF^(1/(2*Df))
Sepal.Width 2.396217 1 1.547972
Petal.Length 23.176426 1 4.814190
Petal.Width 22.012759 1 4.691776
Species 41.330982 2 2.535531
Petal.Length_x_Sepal.Width 1.444820 1 1.202007
centering을 한 후에 결과를 보면 Sepal.Width:Petal.Length 항의 경우 vif=1.2로 크게 개선된 것을 확인할 수 있다.
참고자료
colinearity in generalized linear models, p.32, chapter 2.5.1
http://web.vu.lt/mif/a.buteikis/wp-content/uploads/PE_Book/4-5-Multiple-collinearity.html
Citation
@online{don2024,
author = {Don, Don and Don, Don},
title = {Multicolinearity},
date = {2024-01-29},
url = {https://dondonkim.netlify.app/posts/logistic_reg},
langid = {en}
}