본문 바로가기

Theory/Statistics

Regression - 다중공선성 (Multicollinearity)

반응형

다중 선형 회귀에서의 전제는 독립 변수간 상관 관계가 없이 서로 독립이어야 한다는 점입니다. 만약 독립 변수간에 선형 관계가 존재한다면 이는 다중 선형 회귀에서 다중공선성 (multicollinearity)가 존재한다고 하며 이는 회귀 분석에 악영향을 끼치기 때문에 모델 훈련 전 미리 제거해야 합니다.

선형 회귀는 기본적으로 다음 수식에서 $X^T X$의 역행렬을 구하는 문제입니다. 만약 하나의 독립 변수가 다른 독립 변수에 대해 선형적으로 설명된다면 $X$의 한 열이 다른 열의 선형 결합으로 표현되므로 행렬의 rank가 줄어들어 invertible 해지지 않습니다. 물론 완벽히 선형 결합으로 표현되지는 않을테니 역행렬 자체는 구할 수 있겠으나 수치계산상으로 불안정해지고 회귀 계수의 표준오차와 p-value가 급격하게 커지게 됩니다.

직관적으로는 다중 공선성을 가지는 여러 개의 설명 변수가 종속 변수를 설명할 때 특정한 몇 변수들이 종속 변수에 대한 설명력의 대부분을 차지하여 나머지 설명 변수들의 종속 변수에 대한 설명력이 작아져 회귀 계수의 귀무가설 "회귀 계수가 0" 의 p-value 가 상대적으로 높아지게 됩니다. 또한, 회귀 계수의 의미는 다른 설명 변수들을 고정시켰을 때 특정 설명 변수의 변화가 종속 변수의 변화의 얼마나 영향을 미치는지에 관한 것으로 변수들이 큰 상관관계를 가졌을 때 종속 변수와 각 설명 변수 간의 관계를 제대로 표현하지 못한다는 것입니다.

다중공선성의 존재 여부는 회귀계수의 표준오차나 p-value가 지나치게 높을 때 파악할 수 있지만 대표적으로 VIF (Variation Inflation Factor) 가 사용됩니다.

Variation inflation factor

VIF는 각 독립 변수를 다른 독립 변수에 대해 선형 회귀한 결과를 이용한 것으로 독립 변수 $X_i$에 대한 VIF 값은 다음과 같이 결정됩니다.

$VIF_i=\frac{1}{1-R_i^2}$

$R_i^2$는 $X_i$를 $X_i$를 제외한 다른 모든 독립 변수로 선형 회귀한 결정계수로 $R_i^2$가 높다면 $VIF_i$ 값이 커지고 반대의 경우에면 작아집니다. 일반적으로 10이 넘으면 다중공선성이 존재한다고 판단하며 5가 넘으면 주의할 필요가 있는 것으로 간주합니다. 특히 두 개의 독립 변수가 서로 상관관계가 있다면 각 독립 변수에 대한 VIF가 둘 다 높을 것이기 때문에 어느 하나의 VIF만 높은 경우는 없습니다.

예를 들어 어떠한 독립 변수의 VIF 값이 5.27이라면 해당 변수의 회귀 계수의 표준 오차가 다른 독립 변수와 관련이 없었을 때에 비해 $\sqrt{5.27}=2.3$ 배 증가한 것이라 해석할 수 있습니다.

Example

이번 예제는 집값 데이터로 다음과 같이 구성되어 있습니다.

범주형 변수를 제외한 area/bedrooms/bathrooms 의 수치형 변수만 사용한다고 가정했을 때 먼저 시각적으로 pairplot이나 상관계수 heatmap을 통하여 빠르게 파악할 수 있습니다.

import seaborn as sns
sns.heatmap(df[['area', 'bedrooms', 'bathrooms']].corr(), annot=True)

각 변수들 모두 상관관계가 강하게 있는 것으로 파악되나 특히 bathrooms/bedrooms 는 매우 강한 양의 상관관계가 있는 것을 볼 수 있습니다. 먼저 모든 독립 변수에 대해 OLS를 돌려보겠습니다.

import statsmodels.api as sm

df['intercept'] = 1
lm = sm.OLS(df['price'], df[['intercept', 'bedrooms', 'bathrooms', 'area']])
results = lm.fit()
results.summary()

OLS 함수에는 상수항이 기본적으로 들어 있지 않으므로 정확한 VIF 분석을 위해 intercept 항을 1로 해서 넣어줍니다. Intercept는 데이터 전체의 평균으로 이를 생략했을시 유의미한 $R^2_i$를 얻을 수 없습니다. OLS 결과를 유심히 보면 bedrooms 의 상관계수가 -2925로 집값과 음의 상관관계를 가지고 있음을 알 수 있습니다. 즉, 다중공선성으로 인해 회귀 결과가 왜곡된 것입니다.

statsmodels.stats.outlier_influence 모듈의 variance_inflation_factor 함수로 VIF 값을 계산하면 다음과 같습니다.

from patsy import dmatrices
from statsmodels.stats.outliers_influence import variance_inflation_factor

result1, result2 = dmatrices('price ~ area + bedrooms + bathrooms', df, return_type = 'dataframe')
vif = pd.DataFrame()
vif["VIF Factor"] = [variance_inflation_factor(result2.values, i) for i in range(result2.shape[1])]
vif["features"] = result2.columns 
print(vif)

bedrooms와 bathrooms가 10 이상이므로 서로 강한 상관관계를 가지고 있음을 확인할 수 있습니다. 두 변수 중 bathrooms 변수를 제거하고 다시 OLS를 수행하면,

# bethrooms를 제외하고 분산 팽창 요인을 확인하고 선형 회귀 분석 수행
result1, result2 = dmatrices('price ~ area + bedrooms', df, return_type = 'dataframe') 
vif = pd.DataFrame()
vif["VIF Factor"] = [variance_inflation_factor(result2.values, i) for i in range(result2.shape[1])]
vif["features"] = result2.columns 
print(vif)
print('\n')

lm = sm.OLS(df['price'], df[['intercept', 'bedrooms', 'area']])
results = lm.fit()
results.summary()

회귀 계수의 p-value가 높긴 하지만 정상적으로 집값과 양의 상관관계를 가지고 있음을 볼 수 있고 VIF 또한 안정적으로 10 미만의 값이 나왔습니다. 특히 bathrooms 열을 제거하더라도 $R^2$가 변하지 않음을 알 수 있습니다. 즉, bathrooms 독립 변수가 제거되더라도 bedrooms 변수로 설명이 충분히 되므로 모델의 예측력에 영향을 미치지 않았음을 알 수 있습니다.

반응형