회귀 분석으로 보는 심슨의 역설
심슨의 역설을 보통은 회귀 분석으로 설명하지 않는다. 그런데 회귀 분석으로 보면 보다 명확하다. 심슨 역설의 전형적인 사례를 펭귄 부리의 길이와 높이를 통해 살펴보도록 하자.
culmen
은 새의 부리를 뜻한다. 옆 그림에서 보듯이 length
는 부리의 앞으로 튀어나온 길이를, depth
는 부리의 높이를 의미한다. 아래 보듯이 이 데이터는 펭귄의 세 가지 종족, 성별 등을 별도로 담고 있다.
# Basic packages
import pandas as pd
import numpy as np
import pandas as pd
import seaborn as sns
from scipy import stats
import matplotlib.pyplot as plt
# Stats models pip
import statsmodels.formula.api as sm
import statsmodels as statsmodels
% matplotlib inline
csv_addr = "data/penguins_size.csv"
plt.style.use("fivethirtyeight" )# for pretty graphs
df = pd.read_csv('data/penguins_size.csv' )
df.head();
#df.info();
df = df.dropna()
df.info()
<class 'pandas.core.frame.DataFrame'>
Index: 334 entries, 0 to 343
Data columns (total 7 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 species 334 non-null object
1 island 334 non-null object
2 culmen_length_mm 334 non-null float64
3 culmen_depth_mm 334 non-null float64
4 flipper_length_mm 334 non-null float64
5 body_mass_g 334 non-null float64
6 sex 334 non-null object
dtypes: float64(4), object(3)
memory usage: 20.9+ KB
plt.rcParams['figure.figsize' ] = [8 , 4 ]
sns.set (font_scale= 0.7 )
fig, (ax1, ax2) = plt.subplots(ncols= 2 , sharey= True )
sns.regplot(x = 'culmen_length_mm' ,y = 'culmen_depth_mm' , data = df, scatter_kws= {'alpha' : 0.4 }, ax= ax1)
r = stats.pearsonr(df['culmen_length_mm' ], df['culmen_depth_mm' ])[0 ]
ax1.text(.03 , 1 , 'r= {:.3f} ' .format (r), transform= ax1.transAxes)
colors = ['darkorange' , 'royalblue' , '#555555' ]
markers = ['.' , '+' , 'x' ]
#
for i, value in enumerate (df['species' ].unique()):
ax2 = sns.regplot(x= "culmen_length_mm" , y= "culmen_depth_mm" , ax= ax2,
scatter_kws= {'alpha' : 0.4 },
color= colors[i],
#marker=markers[i],
data= df[df['species' ] == value],
label= value)
ax2.legend(loc= 'best' );
패널의 왼쪽 그림에서 보듯이 종 구분 없이 펭귄 부리의 길이와 높이를 보면 서로 음의 상관성을 지니고 있는 듯 보인다. 그런데 이를 종별로 구별해서 살펴보면 오히려 길이와 높이는 양의 상관성을 지니고 있다.
ols1 = sm.ols(formula= "culmen_depth_mm ~ culmen_length_mm" , data= df).fit(use_t= True )
ols2 = sm.ols(formula= "culmen_depth_mm ~ species + culmen_length_mm" , data= df).fit(use_t= True )
ols3 = sm.ols(formula= "culmen_depth_mm ~ species * culmen_length_mm" , data= df).fit(use_t= True )
#ols1.summary()
#ols2.summary()
from stargazer.stargazer import Stargazer
stargazer = Stargazer([ols1, ols2, ols3])
stargazer
#regs = [ols1, ols2, ols3]
#from statsmodels.iolib.summary2 import summary_col
#print(summary_col(
# regs,
# stars=True,
# float_format='%0.2f',
# model_names=['(1)','(2)','(3)'],
# info_dict={
# 'N':lambda x: "{0:d}".format(int(x.nobs)),
# 'F': lambda x: "{0:.2f}".format(x.fvalue),
# },
# regressor_order=['Intercept','culmen_length_mm','secies'])
# )
Dependent variable: culmen_depth_mm (1) (2) (3)
Intercept 20.786*** 10.619*** 11.488***
(0.854) (0.691) (1.162)
culmen_length_mm -0.082*** 0.199*** 0.177***
(0.019) (0.018) (0.030)
species[T.Chinstrap] -1.919*** -3.919*
(0.226) (2.070)
species[T.Chinstrap]:culmen_length_mm 0.046
(0.046)
species[T.Gentoo] -5.080*** -6.187***
(0.194) (1.778)
species[T.Gentoo]:culmen_length_mm 0.027
(0.041)
Observations 334 334 334 R2 0.052 0.766 0.767 Adjusted R2 0.049 0.764 0.764 Residual Std. Error 1.919 (df=332) 0.956 (df=330) 0.957 (df=328) F Statistic 18.313*** (df=1; 332) 360.759*** (df=3; 330) 216.026*** (df=5; 328)
Note: * p<0.1; ** p<0.05; *** p<0.01
회귀 분석에서 종을 통제한 경우와 그렇지 않은 경우의 culmen_length_mm
(부리의 길이)의 계수를 비교해보자. (1)은 종족을 통제하지 않은 회귀식으로 culmen_length_mm
의 계수는 음수이다. 반면 종족을 통제한 (2)의 회귀식은 종족의 구분해 각 절편과 해당 종족 내의 부리의 길이와 높이의 관계를 계산해 이를 적절하게 가중 평균한 값이 culmen_length_mm
의 계수가 된다. 회귀 테이블에서 보듯이 culmen_length_mm
의 계수는 음수에서 양수로 바뀌어 있다.
나머지 계수의 의미는 기본이 되는 Adelie 종족을 기준으로 다른 두 개의 종족의 절편이 얼마나 떨어져 있는지를 보여준다. 회귀식을 적어보면 다음과 같다.
식 (1) \(y_i = \alpha_i + \beta x_i\)
식 (2) \(y_i = \alpha_i + \beta x_i + D_{1i} + D_{2i}\)
\(y_i\) : culmen_depth_mm
부리의 높이
\(x_i\) : culmen_length_mm
부리의 길이
\(D_{1i}\) : 종족이 Chinstrap
일 경우 1 이외는 0
\(D_{2i}\) : 종족이 Gentoo
일 경우 1이외는 0
식 (3)은 \(\beta_i\) 가 그룹별로 달라지는지 여부를 교호작용 항목을 통해 확인했다. (3)이 보여주듯이 그룹별로 \(\beta_i\) 는 통계적으로 유의미한 차이가 없다.