Python 기초 통계

Python으로 하는 기초 통계 분석법


수강중

13. 다중공선성

동영상이 없는 텍스트 강의 자료입니다.

공선성(collinearity): 하나의 독립변수가 다른 하나의 독립변수로 잘 예측되는 경우, 또는 서로 상관이 높은 경우

다중공선성(multicollinearity): 하나의 독립변수가 다른 여러 개의 독립변수들로 잘 예측되는 경우

(다중)공선성이 있으면:

  • 계수 추정이 잘 되지 않거나 불안정해져서 데이터가 약간만 바뀌어도 추정치가 크게 달라질 수 있다
  • 계수가 통계적으로 유의미하지 않은 것처럼 나올 수 있다

(다중)공선성의 진단

  • 분산팽창계수(VIF, Variance Inflation Factor)를 구하여 판단
  • 엄밀한 기준은 없으나 보통 10보다 크면 다중공선성이 있다고 판단(5를 기준으로 하기도 함)

예제 데이터

crab.csv를 다운로드 받아 연다. 이 데이터는 게의 크기와 무게 등을 측정한 데이터이다.

import pandas as pd
df = pd.read_csv('crab.csv')
df.head()
crab sat y weight width color spine
0 1 8 1 3.05 28.3 2 3
1 2 0 0 1.55 22.5 3 3
2 3 9 1 2.30 26.0 1 1
3 4 0 0 2.10 24.8 3 3
4 5 4 1 2.60 26.0 3 3

회귀분석

from statsmodels.formula.api import ols

모형을 만든다.

model = ols('y ~ sat + weight + width', df)

모형을 적합시킨다.

res = model.fit()

분석 결과를 확인한다.

res.summary()
OLS Regression Results
Dep. Variable: y R-squared: 0.514
Model: OLS Adj. R-squared: 0.506
Method: Least Squares F-statistic: 59.69
Date: Thu, 23 Jan 2020 Prob (F-statistic): 2.30e-26
Time: 16:11:28 Log-Likelihood: -55.831
No. Observations: 173 AIC: 119.7
Df Residuals: 169 BIC: 132.3
Df Model: 3
Covariance Type: nonrobust
coef std err t P>|t| [0.025 0.975]
Intercept -0.9366 0.500 -1.872 0.063 -1.924 0.051
sat 0.0971 0.009 11.018 0.000 0.080 0.115
weight -0.0465 0.098 -0.475 0.635 -0.240 0.147
width 0.0535 0.026 2.023 0.045 0.001 0.106
Omnibus: 29.724 Durbin-Watson: 1.475
Prob(Omnibus): 0.000 Jarque-Bera (JB): 7.545
Skew: 0.086 Prob(JB): 0.0230
Kurtosis: 1.992 Cond. No. 526.


Warnings:
[1] Standard Errors assume that the covariance matrix of the errors is correctly specified.

결과를 보면 유의수준 5%에서 satwidth는 통계적으로 유의미하고, weight는 유의미하지 않게 나왔다.

VIF 계산

statsmodels에서 variance_inflation_factor 함수를 불러들인다.

from statsmodels.stats.outliers_influence import variance_inflation_factor

모형식에서 독립변수는 절편, sat, weight, width 순이다.

model.exog_names
['Intercept', 'sat', 'weight', 'width']

X의 1번째 독립변수 sat의 VIF를 계산한다.

variance_inflation_factor(model.exog, 1)
1.15883687808578

X의 2번째 독립변수 weight의 VIF를 계산한다.

variance_inflation_factor(model.exog, 2)
4.8016794240392375

한 번에 모든 컬럼의 VIF를 계산한다.

pd.DataFrame({'컬럼': column, 'VIF': variance_inflation_factor(model.exog, i)} 
             for i, column in enumerate(model.exog_names)
             if column != 'Intercept')  # 절편의 VIF는 구하지 않는다.
컬럼 VIF
0 sat 1.158837
1 weight 4.801679
2 width 4.688660

weightwidth의 VIF가 각각 4.8과 4.6이다. 게의 무게(weight)와 너비(width)는 서로 상관이 높기 때문에 VIF가 약간 높게 나타나는 것이다.

대처

  • 계수가 통계적으로 유의미하지 않다면 대처
    • 계수가 통계적으로 유의미하다면 VIF가 크더라도 특별히 대처할 필요없음
  • 변수들을 더하거나 빼서 새로운 변수를 만든다
    • (개념적으로나 이론적으로) 두 예측변수를 더하거나 빼더라도 문제가 없는 경우
      • 예) 남편의 수입과 아내의 수입이 서로 상관이 높다면, 두 개를 더해 가족 수입이라는 하나의 변수로 투입한다
    • 더하거나 빼기 어려운 경우는 변수를 모형에서 제거한다
      • 단, 변수를 제거하는 것은 자료의 다양성을 해치고, 분석하려던 가설이나 이론에 영향을 미칠 수 있기 때문에 가급적 자제

weightwidth가 VIF 기준을 넘는 것은 아니지만 실험삼아 width를 제거해보자.

model = ols('y ~ sat + weight', df)
model.fit().summary()
OLS Regression Results
Dep. Variable: y R-squared: 0.503
Model: OLS Adj. R-squared: 0.497
Method: Least Squares F-statistic: 85.93
Date: Thu, 23 Jan 2020 Prob (F-statistic): 1.63e-26
Time: 16:18:20 Log-Likelihood: -57.901
No. Observations: 173 AIC: 121.8
Df Residuals: 170 BIC: 131.3
Df Model: 2
Covariance Type: nonrobust
coef std err t P>|t| [0.025 0.975]
Intercept 0.0495 0.114 0.433 0.665 -0.176 0.275
sat 0.0976 0.009 10.982 0.000 0.080 0.115
weight 0.1260 0.049 2.598 0.010 0.030 0.222
Omnibus: 40.033 Durbin-Watson: 1.433
Prob(Omnibus): 0.000 Jarque-Bera (JB): 8.709
Skew: 0.121 Prob(JB): 0.0128
Kurtosis: 1.928 Cond. No. 22.7


Warnings:
[1] Standard Errors assume that the covariance matrix of the errors is correctly specified.

이전의 분석에서는 weight가 유의미하지 않게 나왔지만, width를 제거한 후에는 유의미하게 나왔다. weightwidth가 공선성이 있기 때문에 width를 제거하자 weight가 유의미해진 것으로 볼 수 있다.