다중 회귀를 해보니, 다중공선성등의 문제를 맞닥뜨리게 되고, 이것 때문에 유의하지 않은 변수들을 만나게 되고, 그러면 이건 어떻게 해결해야 하는 것인가 고민하게 되고, 도대체 어디까지 이걸 신경 써야 하는가 고민하게 되고, 정답은 과연 있는 것인가 고민하게 되고. 아니 왜 이걸 시작해서 이렇게까지 복잡하게 생각해야 하는가 하는 고민을 하게 되는 고민의 무한 루프 같은 이야기가 되는 것 같은데 말이죠.
일단 왜 다중 회귀분석을 하는가? 하면 여러가지 독립변수가 종속변수에 각각 어떤 영향을 끼치는지 한 번에 알아낼 수 있는 방법이기 때문에 합니다. 그렇죠. 이게 가장 중요한 포인트입니다. 쉽게 다시 말하자면, 이 분석 결과로부터 각각의 Feature들이 종속변수에 "얼마나?" 영향을 미치는지를 알아내는 것이 목적입니다. 목적을 잊으면 안 돼요. 그걸 알아내려고 보니까, 어? 뭔가 서로 영향을 미치네? 이거 정확하게 각각 얼마나 영향을 미치는지 알아내고 싶었는데, 이게 현실이 그렇다 보니 서로 조금씩 섞여서 헷갈려져 버렸네? 가 되어버린 거죠.
그렇기 때문에 각각의 Feature중에서 관심 있는 Feature는 일단 t 통계량이 유의하기만 하면 VIF고 뭐고 일단 채택, 그리고 관심 있는데 유의하지 못한 Feature를 나머지 Feature들 중에 문제가 될 만한 것들을 잘 제거해서 - 모두 제거하는 것이 목적이 아닙니다. - 유의하게 만드는 게 목적이 되겠습니다. 그것만 해결되면 나머지 유의하지 않은 Feature들은 없애거나, 남아 있어도 크게 문제가 되지 않습니다.
그러면 다음과 같은 식으로 사고하고 문제를 해결하면 어떨까 생각합니다.
아, 잠시만 문제 해결 방식을 이야기 하기 전에 표준계수에 대하여 잠시만 이야기하고 넘어가자면, 보통의 회귀분석 결과는 독립변수의 단위가 서로 달라서 어떤 것은 조금만 움직여도 y가 엄청 크게 움직이고, 어떤 것은 많이 움직여도 y가 얼마 변하지 않을 수도 있기 때문에 각각의 독립변수의 영향력을 표준화해서 볼 수 있겠습니다. 혹시나 y까지 정규화를 한다면 절편의 effect를 제거한다고 볼 수 있겠습니다. 하지만 y를 정규화하게 되면 회귀분석에 의한 모델을 설명하기는 좋겠지만, 이 모델을 이용해서 다른 값을 예측하거나 추가 분석하기에는 많이 불편해지니까 그건 감안해 주세요.
자, 그럼 부릉부릉 문제해결을 위한 사고의 과정을 시작해 보시죠.
➊ 계수가 통계적으로 유의하다면 VIF가 크더라도 특별히 대처할 필요가 없음. VIF가 크더라도 계수의 분산이 충분히 작기 떄문입니다.
➋ 계수가 통계적으로 유의하지 않고, VIF가 크더라도 분석에 꼭 필요한 Feature라면 살리는 것이 좋겠죠. 어떻게 살리느냐 하면, 나머지 유의하지 않은 계수중에서 종속변수 y와 나머지 변수의 상관이 적은 것(또는 표준화 계수가 작은 것)과 다중공선성(VIF) 큰 변수들을 고려하여 주요하게 다중공선성에 영향을 미치는 변수를 제거하는 방법을 고려할 수 있겠습니다. 사실상 모든 계수가 유의하면 속이 후련해지겠지마는~ 관심 Feature의 계수가 유의해 지기만 한다면 나머지는 유의하지 않아도 어쩔 수 없는 것 아닌가,라고 생각하고 있습니다. 그래서 목표는 모든 Feature의 계수를 유의하게 하는 것이 아니라 관심 Feature의 계수를 유의하게 하는 것입니다. 이런 이유로 회귀모형에 고려된 모든 변수를 유의하게 만들기 위해 변수를 마구 제거하는 것은 자료의 다양성을 해치고, 분석하려던 가설이나 이론에 영향을 미칠 수 있기 때문에 가급적이면 하지 않도록 꾹꾹 참아야 합니다. 이런 접근이 어느 정도 가장 현실적인 타협점이 아닐까 생각합니다. 이 정도의 목표가 가장 중요한 사항이라고 생각한다면,
⓵ y종속변수와 상관관계가 작은 독립변수 또는 표준화 상관계수가 작은 독립 변수
⓶ VIF가 큰 독립변수,
⓷ 측정이 객관적이지 않거나, 불명확해 보이는 독립변수
들을 먹잇감으로 생각하는 것이 어느정도 합리적인 접근이 아닐까 합니다.
★ 참고로 해당 관심 변수와 상관이 큰 변수 가 있다고 했을 때, 상관이 크다고 해서 다중공선성을 띈다고 꼭 집어 말할 수 없습니다. 즉 어떤 두 변수가 상관이 높다고 해서 꼭 VIF가 높다고 할 수 없다는 뜻입니다. (독립변수가 2개밖에 없다면 다중공선성에 영향을 미치겠지만요) 이런 상관이 큰 변수는 맥락을 잘 보았을 때 매개변수일 가능성이 큽니다.
갑자기 이런 이야기를 꺼내서 미안합니다만, 변수를 선택할 때 상관관계가 크면서 심지어 VIF가 큰 변수가 매개변수이거나, 통제변수일 경우에는 그냥 두는 것이 낫습니다. 매개변수는 의미를 보자면, 인과관계의 논리적인 흐름을 보았을 때의 중간에 끼어 있는 변수를 의미하는데 특정 독립변수로부터 매개하여 우회적으로 종속변수에 영향을 끼치는 변수이고 , 통제변수는 종속변수에 영향을 끼칠 만한 것을 변수로 하여 관심독립변수가 종속변수에게 끼치는 영향을 통제하여 종속변수에 대한 영향력을 더 크게 해석하지 않도록 해 주는 변수를 의미합니다. 이 변수들은 관심변수만 유의하다면 관심변수의 영향력을 명확하게 설명할 수 있게 해주는 변수들이기 때문에 VIF가 크거나 유의하지 않더라도 그냥 두는 편이 올바른 해석이 될 가능성이 크게 되고, 이런 변수를 이용해서는 추가적인 해석으로 매개효과, 조절효과등을 분석할 수 있게 됩니다. 어쨌든 지금 그런 효과들까지 관심 갖기에는 뭐랄까 꼬리에 꼬리를 무는 연쇄질문마가 될 수 있기 때문에 잠시 잊는 것이 상책이겠습니다.
➌ 유의하지 않은 계수들을 어떻게든 해당 변수들을 유의하게 만들어서 속이 후련해 지는 또 다른 방법은
⓵ 변수들을 합하거나 차이를 구해서 새로운 변수를 만드는데, 독립변수끼리 서로 상관이 높은 경우에 더하거나 차이를 만들면 변수가 하나로 줄어서 개선될 수 도 있습니다. 예를 들면 남편의 월급과 아내의 월급이 상관관계를 갖는다면 더해서 가족의 월급으로 새로이 합쳐진 변수를 만드는 하는 방법이 있겠습니다.
⓶ 또는 PCA를 이용해서 하나의 새로운 변수로 압축할 수도 있겠습니다. 예를 들면 국어성적, 영어성적, 일본어 성적은 PCA를 통해서 언어성적이라는 하나의 변수로 압축도 가능하겠습니다.
특히 PCA를 이용하게 되면 PCA로 압축한 Feature끼리는 직교하게 되어 그 안에서는 다중공선성이 사라집니다. 오호. 고마워
이런 걸 Feature Extraction이라고 부릅니다.
➍ 마지막으로 모든 조건을 만족하는 변수의 조합을 찾아내는 좋은 방법이 있습니다. 후후. 그게 뭐냐구요? 바로 노가다입니다. 설명력이 높은 변수로만 회귀식에 포함한다는 뭐 그런 건데요, 아무 변수도 추가하지 않은 맨바닥에서 p value가 작은 유의한 변수를 하나하나 추가하면서 가장 좋은 변수의 조합을 찾아내는 방법이 있고 - 이걸 있어 보이는 유식한 말로 전진 선택법이라고 부릅니다. 또 하나는 다 때려 넣은 후에 p value가 큰 유의하지 않은 변수를 하나하나 제거하면서 적당한 수준의 변수의 조합을 찾아내는 방법입니다. 계수들이 엄청 많을 때 유용할 수 있겠습니다. 이 방법은 INTJ의 분들이 선호하는 방법이 아닐까 문득 생각이 드는군요. 이렇게 하면 어쨌든 유의한 변수의 조합을 찾아낼 수는 있겠습니다.
➎ 진짜 마지막으로는 유의하지 않은 변수는 그냥 그런 채로 두고 회귀모형의 한계를 인정하는 방법이 있습니다. 조금 자존심 상하겠지만요.
어쨌든 회귀모형을 어떤 식으로 구성하여 설명할 것이냐는 것은 순전히 모형을 구성하는 모델링을 하는 닝겐의 몫입니다. 누군가 제 3자가 모형에 대한 지적을 하기에는 회귀모형 자체가 세상을 모두 표현하기에 너무나 불완전한 모형이기 때문입니다.라고 욕먹을 만한 이야기를 입모양으로만 뻐끔뻐끔 붕어처럼 이야기했어야 하는데, 글로 써 버렸군요. 모형이 현상을 그럴듯하게 설명할 수만 있다면 그걸로 만족하는 편이 애초에 행복한 방법 아닐까 생각합니다.
자, 그러면 조금은 진지한 이야기를 다시 하자면요, Feature Selection에서 배제될 만한 Feature를 고르는 것에 대한 대충의 전략에 대하여 "표준화 계수의 크기가 작고(또는 회귀모형 종속변수 y와 상관관계가 적고), VIF가 크고, 측정이 객관적이지 못할 법하고(휴먼에러가 있을 법한 또는 감성적인 측정등), 그리고 분석에 그다지 중요해 보이지 않는 것은 누구?" 정도로 전략을 정하는 것이 어느정도 속 편한 방법이 아닐까 생각합니다.
진지하게 조금 이야기 해보니까 VIF가 높다고 해서 무조건 악당은 아니겠군요.
자, 그러면 진짜로 한번 해보는 것이 정신건강에 좋지 않겠습니까? 일단 한번 해보긴 하는데, 그게 모든 칼럼에 대해서 각각 정규화를 한 후에 표준화 계수를 구하여 분석하는 것이 분석결과를 해석하는 데에 있어 훨씬 나은 인사이트를 얻을 수 있습니다.
자, 이전에 했었던 데이터로 뭔가 해 보겠습니다. 참 지금의 목표는 불필요한 데이터를 제거하여 모델에 남은 모든 계수를 유의하게 만들도록 Feature를 골라내는 것이 목표인데요 - 이런걸 유식한 말로 Feature Selection 하고요 - , 예시의 경우에는 Feature가 많지 않기 때문에 Feature 압축 (PCA), Feature 더하기 등의 Feature Extraction은 고려치 않겠습니다.
우선 데이터는 이렇게 생겼습니다.
df_raw :
음식준비시간 배달숙련도 배달거리 배달시간
79 80 73 152
93 89 96 192
70 65 74 141
89 91 90 180
70 73 78 148
93 88 93 185
# x를 정규화하기 위해 y와 x를 나눠둡시다.
df_data = df_raw.copy()
df_y = df_data.pop('배달시간')
df_x = df_data.copy()
자, 이제 표준화된 계수를 구하기 위해 정규화를 해 봅시다~
# x를 정규화를 합시다~ 룰루랄라
from sklearn.preprocessing import StandardScaler
sc = StandardScaler()
df_x[df_x.columns] = sc.fit_transform(df_x[df_x.columns])
# 정규화한 x와 원래 y를 붙여서 원상복구 합체!
df_data['배달시간'] = df_y
df_data[df_x.columns] = df_x[df_x.columns]
헤헷, 준비되었으니까, 본격적인 회귀를 해봅시다~!
# 이제 회귀를 해봅시다. 후후.
import statsmodels.formula.api as smf
sales = smf.ols("배달시간 ~ 음식준비시간 + 배달숙련도 + 배달거리", data=df_x).fit()
sales.summary() # 회귀결과를 확인해 보자
자, 회귀를 했으니까 그 결과를 뙇! 보시죠. 어떤가요, 결과를 보면,
으때요? 결과를 보니 배달거리를 빼고는 모두 유의하지는 않군요. 힝. 그리고 표준화 계수로는 배달숙련도가 굉장히 영향력이 작다는 점을 기억해 두면 좋겠습니다.
R_squared가 높고, F검정결과도 좋은데 비해, 음식준비시간, 배달숙련도는 유의하지 않고, 배달거리만 유의합니다. 우리가 관심 있는 Feature가 배달거리 하나라면, 여기에서 게임 오버시킬 수도 있는데 말이죠, 추가로 1개 정도의 Feature를 더 찾아내고 싶다면 말이죠,
일단 여기에서 부터 Feature Selection을 위한 전략이 필요한데, 이제부터 하는 이야기를 정답처럼 여기면 안 됩니다만, 어느 정도는 의미가 있다고 생각합니다.
➊ p value가 큰 순서대로 해서 유의하지 않은 변수가 어떤 것들이 있는지 한번 보고요, 왜냐하면 p value가 크다고 함은 계수의 분산이 크다는 의미이니까요, - 그렇다고 해서 p value가 클수록 더 나쁜 계수라고 말할 수는 없다는 점. 그냥 계수의 분산이 크다. 뭐 그런 겁니다. 이제는 잘 이해하겠지요? -
➋ 표준화계수의 크기를 한번 보고요, 영향력이 작은 것은 아무래도 모델에서 빠져도 크게 문제가 안될 가능성이 크니까요.
➌ VIF를 큰 순서대로 보고요, 아무래도 VIF가 크다는 것은 다른 Feature로 설명이 되어서 계수의 분산이 커질테니까요.
➍ 종속변수y를 포함하여 독립변수들과의 공분산을 보고, 종속변수와 Correlation이 적은 변수는 결정계수에 안 좋은 영향을 끼칠 수 있지 않을까 하고 생각해 보는 것도 의미가 있지 않을까 합니다.
➎ 이때는 독립변수 x가 측정이 객관적이지 않고 부정확할 수 있는지도 한번 검토해 보면 좋겠습니다. 측정이 부정확하면 당연히 계수의 분산을 키우겠죠.
➏ 이걸 고려한 변수 리스트를 보고 꼭 필요한 Feature와 그렇지 않은 Feature나누어서 최종 모델을 고려하는 그런 거?라고 생각합니다.
그러면 y(배달시간)을 포함한 correlation과 y를 포함하지 않은 VIF를 일단은 구해보십시다요.
# VIF를 구해 봅시다.
from statsmodels.stats.outliers_influence import variance_inflation_factor
x_cols = [col for col in df_x.columns if col!="배달시간"]
df_x_only = df_x[x_cols]
vif = pd.DataFrame()
vif["VIF Factor"] = [variance_inflation_factor(df_x_only.values, i) for i in range(df_x_only.shape[1])]
vif["features"] = df_x_only.columns # y를 제외하고 x들만으로 vif를 한번 보자
어흠, 배달거리는 VIF도 낮고, 계수도 유의하고 그런거 보니 확실하게 이 다중회귀의 결과에서 독보적인 존재라는 게 드러났습니다. 나머지 중에서 VIF가 큰 것은 음식준비시간이랑 배달숙련도가 값이 좀 높군요. 어허.. 이거 좀 판단하기 어렵네요. 그럼 그냥 VIF 기준으로 음식준비시간을 날리면 될라나요? 아, 이건 좀 아닌 것 같죠? 그렇게 되면 남는 게 배달숙련도가 남게 되는데, 배달 숙련도라는 게, 조금 정량화하기에 적합하지 않은 데이터 아닌가? 하는 생각이 듭니다.
그렇다면 말이죠, 이 두 개 Feature가 종속변수와 어떤 선형관계를 갖는지도 한번 보시죠.
df_data.corr()
이거 보니까, 역시나 배달숙련도가 종속변수인 배달시간과 상관관계가 그 중 낮군요. 표준화 계수를 봐도 2.64로 상당히 영향력이 작습니다. (사실 객관적으로 보면 꽤 높긴 합니다만, 그중이라는 단어에 포커스 하고 영향력이 작다는 것으로 설득력이 있다 할 수 있지 않을까 합니다.)
다시 한번 추리해 보면, 계수의 크기가 작고 (회귀모형 y와 상관관계가 적고), VIF가 큰 것은 누구?라고 생각해 보면, 계수들을 유의하지 못하게 만드는 것은 배달숙련도?, 게다가 배달숙련도는 측정이 조금은 객관적이지도 못할 가능성이 있지 않겠습니까? 호.
이렇다는 이야기는 배달숙련도가 가장 범인에 가까운 변수가 아닐까?하는 결론을 맺을 수 있지 않을까 합니다. 이런 이런 이유로 배달숙련도를 빼고 회귀를 한번 해 봅시다.
sales = smf.ols("배달시간 ~ 음식준비시간 + 배달거리", data=df_x).fit()
어허 이렇게 하니까 회귀모델에 남아있는 모든 계수가 유의하게 되었습니다. 완벽주의자들에게 조금은 위안이 되는 결론을 찾긴 했습니다. 후. 이런 식으로 접근한다는 것이지 이 접근 방법이 정답은 아닙니다. 데이터를 이용해서 모형을 만든다는 것은 정답이 없다는 점을 다시 한번 상기했으면 좋겠고, 최선의 모형이 있을 뿐이라는 점 역시 상기하면 좋겠습니다.
보통 매개변수는 관심 독립변수와 종속변수사이에 우회적인(인과적인) 경로로 종속변수에게 영향을 끼치게 되므로 보통 독립변수와 상관관계가 크거나 모형 안에서 다중공선성을 가지게 될 가능성이 큽니다. 그리고, 통제변수나 조절변수는 관심 독립변수의 종속변수에 대한 영향력이 과장되지 않도록 영향력을 분산하는 변수이므로 관심독립변수와 큰 상관관계가 없는 경우가 많고, 모형안에서 다중공선성을 가지는 경우가 많지 않습니다. 물론 이것은 그럴 가능성이 많다는 것이지 꼭 그렇다고 보기는 어렵습니다. 그냥 Intuition 정도로 마음에 가지고 있다면 분석할 때 도움이 되지 않을까? 하는 정도의 의견입니다. 헤헤.
댓글