6  그룹 회귀와 더미 회귀

그룹화된 데이터의 회귀분석

모든 데이터 포인트가 똑같은 무게를 갖지는 않습니다. ENEM 데이터셋을 다시 보면, 작은 학교의 점수보다 큰 학교의 점수를 훨씬 더 믿게 됩니다. 큰 학교가 더 낫다거나 하는 이야기가 아닙니다. 단지 규모가 크면 분산이 작기 때문입니다.

코드
import warnings
warnings.filterwarnings('ignore')

import pandas as pd
import numpy as np
from scipy import stats
from matplotlib import style
import seaborn as sns
from matplotlib import pyplot as plt
import statsmodels.formula.api as smf

style.use("fivethirtyeight")
코드
np.random.seed(876)
enem = pd.read_csv("./data/enem_scores.csv").sample(200)
plt.figure(figsize=(8,4))
sns.scatterplot(y="avg_score", x="number_of_students", data=enem)
sns.scatterplot(y="avg_score", x="number_of_students", s=100, label="Trustworthy",
                data=enem.query(f"number_of_students=={enem.number_of_students.max()}"))
sns.scatterplot(y="avg_score", x="number_of_students", s=100, label="Not so Much",
                data=enem.query(f"avg_score=={enem.avg_score.max()}"))
plt.title("ENEM Score by Number of Students in the School");

위 데이터에서 직관적으로 생각하면, 왼쪽 점들은 오른쪽 점들보다 모델에 미치는 영향이 작아야 합니다. 사실 오른쪽 점 하나하나는 수많은 데이터 포인트를 하나로 묶어 놓은 것입니다. 이 묶음을 풀어서 그룹화하지 않은 데이터로 선형회귀를 돌릴 수 있다면, 오른쪽 점들은 왼쪽의 낱개 점 하나보다 모델 추정에 훨씬 크게 기여할 것입니다.

이처럼 분산이 낮은 영역과 높은 영역이 함께 있는 현상을 이분산성(heteroskedasticity)이라고 합니다. 쉽게 말해 이분산성은 특성 값에 따라 분산이 일정하지 않은 상태를 말합니다. 위 예에서는 특성인 표본 크기가 커질수록 분산이 줄어드는 것을 볼 수 있습니다. 다른 예를 들면, 나이에 따른 임금을 그려 보면 젊은 사람보다 나이 든 사람의 임금 분산이 더 큽니다. 하지만 분산이 달라지는 가장 흔한 이유는 단연 그룹화된 데이터입니다.

위와 같은 그룹화된 데이터는 데이터 분석에서 아주 흔합니다. 한 가지 이유는 기밀 유지입니다. 정부와 기업은 지켜야 할 개인정보 보호 규정이 있어서 개인 단위 데이터를 넘겨줄 수 없습니다. 외부 연구자에게 데이터를 내보내야 한다면 데이터를 그룹화하는 방법밖에 없습니다. 이렇게 하면 개인들이 한데 묶여서 더는 누구인지 특정할 수 없게 됩니다.

다행히 회귀분석은 이런 데이터도 꽤 잘 다룹니다. 어떻게 다루는지 이해하기 위해, 먼저 앞에서 본 임금과 교육 데이터처럼 그룹화되지 않은 데이터를 가져오겠습니다. 이 데이터는 근로자 한 명당 한 행으로 되어 있어서, 개인마다 임금과 교육 연수를 알 수 있습니다.

코드
wage = pd.read_csv("./data/wage.csv")[["wage", "lhwage", "educ", "IQ"]]

wage.head()
wage lhwage educ IQ
0 769 2.956212 12 93
1 808 2.782539 18 119
2 825 3.026504 14 108
3 650 2.788093 12 96
4 562 2.642622 11 74

교육 연수가 로그 시간당 임금과 어떻게 연관되는지 알아보려고 회귀 모델을 돌리면 다음 결과를 얻습니다.

코드
model_1 = smf.ols('lhwage ~ educ', data=wage).fit()
model_1.summary().tables[1]
coef std err t P>|t| [0.025 0.975]
Intercept 2.2954 0.089 25.754 0.000 2.121 2.470
educ 0.0529 0.007 8.107 0.000 0.040 0.066

이제 잠시 이 데이터에 기밀 유지 제약이 걸려 있다고 해 봅시다. 데이터 제공자가 개인 단위 데이터를 줄 수 없는 상황입니다. 그래서 대신 모든 사람을 교육 연수별로 묶고, 그룹마다 평균 로그 시간당 임금과 인원수만 달라고 요청합니다. 그러면 데이터 포인트가 10개만 남습니다.

코드
group_wage = (wage
              .assign(count=1)
              .groupby("educ")
              .agg({"lhwage":"mean", "count":"count"})
              .reset_index())

group_wage
educ lhwage count
0 9 2.856475 10
1 10 2.786911 35
2 11 2.855997 43
3 12 2.922168 393
4 13 3.021182 85
5 14 3.042352 77
6 15 3.090766 45
7 16 3.176184 150
8 17 3.246566 40
9 18 3.144257 57

걱정하지 마세요! 회귀분석은 빅데이터가 있어야만 작동하는 게 아닙니다! 선형회귀모델에 가중치를 주면 됩니다. 이렇게 하면 모델이 작은 그룹보다 표본 크기가 큰 그룹을 더 많이 고려합니다. smf.ols를 가중 최소제곱법(weighted least squares)을 뜻하는 smf.wls로 바꾼 것을 눈여겨보세요. 알아채기 어려울 만큼 작은 차이지만, 결과는 완전히 달라집니다.

코드
model_2 = smf.wls('lhwage ~ educ', data=group_wage, weights=group_wage["count"]).fit()
model_2.summary().tables[1]
coef std err t P>|t| [0.025 0.975]
Intercept 2.2954 0.078 29.327 0.000 2.115 2.476
educ 0.0529 0.006 9.231 0.000 0.040 0.066

그룹화한 모델의 educ 매개변수 추정값이 그룹화하지 않은 데이터의 추정값과 아주 가깝다는 점에 주목하세요(사실 이번 경우에는 똑같습니다). 또한 데이터 포인트가 10개뿐인데도 통계적으로 유의한 계수를 얻었습니다. 점의 개수는 줄었지만 그룹화하면서 분산도 크게 줄었기 때문입니다. 표준오차가 조금 작아지고 t 통계량이 조금 커진 점도 보세요. 분산에 대한 정보 일부를 잃었으니 더 보수적으로 접근해야 하기 때문입니다. 데이터를 그룹화하고 나면 각 그룹 안의 분산이 얼마나 큰지 알 수 없습니다. 위 결과를 아래의 가중치 없는 모델 결과와 비교해 보세요.

힌트옮긴이

원문 설명과 달리, 정보를 잃어 더 보수적이어야 한다면 표준오차는 작아지는 것이 아니라 커져야 합니다. 실제 출력에서는 그룹화한 가중 회귀의 표준오차(0.006)가 그룹화하지 않은 회귀(0.007)보다 조금 작으니, 원문의 설명과 출력이 맞지 않습니다. 본문은 원문 그대로 옮겼습니다.

코드
model_3 = smf.ols('lhwage ~ educ', data=group_wage).fit()
model_3.summary().tables[1]
coef std err t P>|t| [0.025 0.975]
Intercept 2.3650 0.082 28.988 0.000 2.177 2.553
educ 0.0481 0.006 8.136 0.000 0.034 0.062

매개변수 추정값이 더 작습니다. 이 회귀분석이 모든 점에 같은 가중치를 주고 있기 때문입니다. 그룹화한 점들 위에 모델을 그려 보면, 가중치 없는 모델은 왼쪽 아래의 작은 점들을 필요 이상으로 중요하게 다루고 있습니다. 그 결과 회귀선의 기울기가 더 낮아집니다.

코드
sns.scatterplot(x="educ", y = "lhwage", size="count", legend=False, data=group_wage, sizes=(40, 400))
plt.plot(wage["educ"], model_2.predict(wage["educ"]), c="C1", label = "Weighted")
plt.plot(wage["educ"], model_3.predict(wage["educ"]), c="C2", label = "Non Weighted")
plt.xlabel("Years of Education")
plt.ylabel("Log Hourly Wage")
plt.legend();

요점은 이렇습니다. 회귀분석은 개인 단위 데이터든 집계된 데이터든 모두 다룰 수 있는 놀라운 도구이지만, 집계된 데이터라면 가중치를 써야 합니다. 가중 회귀분석을 하려면 평균 통계량이 필요합니다. 합계도, 표준편차도, 중앙값도 아닌 평균입니다! 공변량과 종속변수 모두 평균이어야 합니다. 그룹화된 데이터에 가중 회귀분석을 한 결과가 그룹화하지 않은 데이터의 회귀분석 결과와 정확히 일치하지는 않는다는 점만 기억하세요. 그래도 꽤 비슷하게 나옵니다.

마지막으로 그룹화된 데이터 모델에 공변량을 더 추가한 예를 보고 마무리하겠습니다.

코드
group_wage = (wage
              .assign(count=1)
              .groupby("educ")
              .agg({"lhwage":"mean", "IQ":"mean", "count":"count"})
              .reset_index())

model_4 = smf.wls('lhwage ~ educ + IQ', data=group_wage, weights=group_wage["count"]).fit()
print("Number of observations:", model_4.nobs)
model_4.summary().tables[1]
Number of observations: 10.0
coef std err t P>|t| [0.025 0.975]
Intercept 1.8821 0.324 5.800 0.001 1.115 2.649
educ 0.0257 0.021 1.198 0.270 -0.025 0.077
IQ 0.0077 0.006 1.309 0.232 -0.006 0.022

이 예에서는 앞서 넣은 교육 연수 외에 IQ를 특성으로 추가했습니다. 방법은 거의 같습니다. 그룹별 평균과 인원수를 구하고, 평균값으로 회귀하되 인원수를 가중치로 씁니다.

더미를 위한 회귀분석

더미변수(dummy variable)는 범주형 변수를 이진 열로 인코딩한 것입니다. 예를 들어 모델에 넣고 싶은 성별 변수가 있다고 합시다. 이 변수는 남성(male), 여성(female), 기타 성별(other)의 세 범주로 되어 있습니다.

gender
male
female
female
other
male

모델은 숫자만 받으므로 이 범주를 숫자로 바꿔야 합니다. 선형회귀에서는 이때 더미를 씁니다. 각 범주에 해당하는지를 0/1 열로 인코딩하는 방식입니다. 그리고 범주 하나는 기준 범주로 남겨 두고 열을 만들지 않습니다. 마지막 범주는 나머지 범주들의 선형결합이므로 이렇게 해야 합니다. 바꿔 말하면, 나머지 범주에 대한 정보를 알면 마지막 범주는 저절로 알 수 있습니다. 이 예에서 어떤 사람이 여성도 아니고 기타 성별도 아니라면 그 사람은 남성이라고 추론할 수 있습니다.

gender female other
male 0 0
female 1 0
female 1 0
other 0 1
male 0 0

사실 A/B 테스트를 다룰 때 이미 간단한 형태의 더미 회귀분석을 했습니다. 좀 더 일반적으로 말하면, 이진 처치를 다룰 때는 처치를 더미변수로 나타냅니다. 이 경우 더미의 회귀계수는 회귀선 절편의 증가분, 즉 실험군과 대조군의 평균 차이입니다.

좀 더 구체적으로, 12학년 졸업이 시간당 임금에 미치는 효과를 추정하는 문제를 생각해 봅시다(교란은 일단 무시하겠습니다). 아래 코드에서는 교육 연수가 12년보다 긴지를 나타내는 처치 더미변수 T를 만들었습니다.

힌트옮긴이

제목 ’Regression for Dummies’는 ’왕초보를 위한 ○○’에 해당하는 입문서 시리즈 ’For Dummies’와 더미변수를 엮은 말장난입니다.

힌트옮긴이

미국 학제에서 12학년은 고등학교 마지막 학년이므로, 12학년 졸업은 고등학교 졸업을 뜻합니다.

코드
wage = (pd.read_csv("./data/wage.csv")
        .assign(hwage=lambda d: d["wage"] / d["hours"])
        .assign(T=lambda d: (d["educ"] > 12).astype(int)))

wage[["hwage", "IQ", "T"]].head()
hwage IQ T
0 19.225 93 0
1 16.160 119 1
2 20.625 108 1
3 16.250 96 0
4 14.050 74 0

더미는 일종의 스위치처럼 작동합니다. 이 예에서 더미가 켜져 있으면 예측값은 절편에 더미 계수를 더한 값입니다. 더미가 꺼져 있으면 예측값은 절편뿐입니다.

코드
smf.ols('hwage ~ T', data=wage).fit().summary().tables[1]
coef std err t P>|t| [0.025 0.975]
Intercept 19.9405 0.436 45.685 0.000 19.084 20.797
T 4.9044 0.626 7.830 0.000 3.675 6.134

이 경우 12학년을 마치지 않은 사람(더미 꺼짐)의 평균 소득은 19.9입니다. 12학년을 마친 사람(더미 켜짐)의 예측값, 곧 평균 소득은 24.8449(19.9405 + 4.9044)입니다. 따라서 더미 계수는 평균의 차이를 포착하며, 이 예에서는 4.9044입니다.

좀 더 형식적으로 말하면, 처치 지표처럼 독립변수가 이진일 때 회귀분석은 평균 처치효과(ATE)를 완벽하게 포착합니다. 회귀분석은 조건부 기댓값 함수(conditional expectation function, CEF) \(E[Y|X]\)의 선형 근사인데, 이 특수한 경우에는 CEF 자체가 선형이기 때문입니다. 즉, \(E[Y_i|T_i=0]=\alpha\), \(E[Y_i|T_i=1] = \alpha + \beta\)로 정의할 수 있고, 그러면 CEF는 다음과 같습니다.

\[ E[Y_i|T_i] = E[Y_i|T_i=0] + \beta T_i = \alpha + \beta T_i \]

그리고 \(\beta\)는 평균의 차이이며, 무작위 데이터라면 ATE입니다.

\[ \beta = [Y_i|T_i=1] - [Y_i|T_i=0] \]

힌트옮긴이

위 식은 원문 그대로이며, 각 항 앞에 기댓값 기호 E가 빠져 있습니다. 즉 β는 T=1일 때 Y의 기댓값에서 T=0일 때 Y의 기댓값을 뺀 값입니다.

변수를 더 넣으면 더미 계수는 조건부 평균 차이가 됩니다. 예를 들어 앞의 모델에 IQ를 추가한다고 해 봅시다. 이제 더미 계수는 IQ를 고정했을 때 12학년을 졸업하면 임금이 얼마나 오를지를 알려 줍니다. 예측값을 그려 보면 평행한 직선 두 개가 보입니다. 한 직선에서 다른 직선으로 뛰어오르는 폭이 12학년을 마쳤을 때 기대할 수 있는 증가분입니다. 두 직선은 효과가 일정하다는 것도 보여 줍니다. IQ가 얼마든 12학년 졸업으로 얻는 이득은 누구에게나 같습니다.

코드
m = smf.ols('hwage ~ T+IQ', data=wage).fit()
plt_df = wage.assign(y_hat = m.fittedvalues)

plt.plot(plt_df.query("T==1")["IQ"], plt_df.query("T==1")["y_hat"], c="C1", label="T=1")
plt.plot(plt_df.query("T==0")["IQ"], plt_df.query("T==0")["y_hat"], c="C2", label="T=0")
plt.title(f"E[T=1|IQ] - E[T=0|IQ] = {round(m.params['T'], 2)}")
plt.ylabel("Wage")
plt.xlabel("IQ")
plt.legend();

이 모델을 식으로 쓰면 이유를 알 수 있습니다.

\[ wage_i = \beta_0 + \beta_1T_i + \beta_2 IQ_i + e_i \]

여기서 \(\beta_1\)은 조건부 평균 차이이고 상수이며, 이 예에서는 3.16입니다. 상호작용(interaction) 항을 추가하면 이 모델을 더 유연하게 만들 수 있습니다.

\[ wage_i = \beta_0 + \beta_1T_i + \beta_2 IQ_i + \beta_3 IQ_i * T_i + e_i \]

조금 복잡해졌으니 이 모델에서 각 매개변수가 무엇을 뜻하는지 하나씩 살펴보겠습니다. 먼저 절편 \(\beta_0\)입니다. 이 녀석은 딱히 흥미로운 해석이 없습니다. 처치가 0(12학년을 졸업하지 않음)이고 IQ도 0일 때의 기대 임금입니다. IQ가 0인 사람은 없을 테니 이 매개변수는 별 의미가 없습니다. \(\beta_1\)도 사정이 비슷합니다. 이 매개변수는 IQ가 0일 때 12학년을 마치면 기대할 수 있는 임금 증가분입니다. 역시 IQ가 0일 리는 없으니 특별히 흥미로운 의미는 없습니다. 이제 \(\beta_2\)는 조금 더 흥미롭습니다. 처치받지 않은 사람에게서 IQ가 임금을 얼마나 올리는지 알려 줍니다. 이 예에서는 0.11 정도입니다. 12학년을 마치지 않은 사람은 IQ가 1점 오를 때마다 시간당 11센트를 더 벌 것으로 기대할 수 있다는 뜻입니다. 마지막으로 가장 흥미로운 매개변수는 \(\beta_3\)입니다. IQ가 12학년 졸업의 효과를 얼마나 키우는지 알려 줍니다. 이 예에서는 0.024인데, IQ가 1점 오를 때마다 12학년 졸업으로 얻는 이득이 2센트씩 늘어난다는 뜻입니다. 대단치 않아 보일 수 있지만, IQ가 60인 사람과 140인 사람을 비교해 보세요. 12학년을 졸업하면 앞사람은 임금이 1.44달러(60 * 0.024) 오르지만, IQ가 140인 사람은 3.36달러(140 * 0.024)를 더 벌게 됩니다.

간단히 모델링 용어로 말하면, 이 상호작용 항 덕분에 처치효과가 특성 수준(이 예에서는 IQ뿐)에 따라 달라질 수 있습니다. 그 결과 예측선을 그려 보면 두 직선이 더는 평행하지 않고, 12학년을 졸업한 사람들(T=1)의 직선이 IQ에 따른 기울기가 더 가파릅니다. IQ가 높은 사람일수록 졸업으로 얻는 이득이 더 크다는 뜻입니다. 이를 효과 수정(effect modification) 또는 이질적 처치효과(heterogeneous treatment effect)라고 부르기도 합니다.

코드
m = smf.ols('hwage ~ T*IQ', data=wage).fit()
plt_df = wage.assign(y_hat = m.fittedvalues)

plt.plot(plt_df.query("T==1")["IQ"], plt_df.query("T==1")["y_hat"], c="C1", label="T=1")
plt.plot(plt_df.query("T==0")["IQ"], plt_df.query("T==0")["y_hat"], c="C2", label="T=0")
plt.title(f"E[T=1|IQ] - E[T=0|IQ] = {round(m.params['T'], 2)}")
plt.ylabel("Wage")
plt.xlabel("IQ")
plt.legend();

마지막으로 모델의 모든 변수가 더미인 경우를 살펴보겠습니다. 이를 위해 IQ를 구간 4개로 나누고, 교육 연수를 범주로 다루겠습니다.

코드
wage_ed_bins = (wage
                .assign(IQ_bins = lambda d: pd.qcut(d["IQ"], q=4, labels=range(4)))
                [["hwage", "educ", "IQ_bins"]])

wage_ed_bins.head()
hwage educ IQ_bins
0 19.225 12 1
1 16.160 18 3
2 20.625 14 2
3 16.250 12 1
4 14.050 11 0

교육 연수를 범주로 다루면 교육의 효과를 더는 매개변수 하나로 제한하지 않습니다. 대신 교육 연수마다 고유한 효과를 갖도록 허용합니다. 이렇게 하면 교육의 효과가 이제 모수적이지 않으므로 유연성이 생깁니다. 이 모델은 그저 교육 연수별 평균 임금을 계산할 뿐입니다.

코드
model_dummy = smf.ols('hwage ~ C(educ)', data=wage).fit()
model_dummy.summary().tables[1]
coef std err t P>|t| [0.025 0.975]
Intercept 18.5600 3.011 6.164 0.000 12.651 24.469
C(educ)[T.10] -0.7874 3.414 -0.231 0.818 -7.488 5.913
C(educ)[T.11] 0.1084 3.343 0.032 0.974 -6.452 6.669
C(educ)[T.12] 1.7479 3.049 0.573 0.567 -4.236 7.732
C(educ)[T.13] 4.3290 3.183 1.360 0.174 -1.918 10.576
C(educ)[T.14] 4.0888 3.200 1.278 0.202 -2.192 10.370
C(educ)[T.15] 6.3013 3.329 1.893 0.059 -0.231 12.834
C(educ)[T.16] 7.2225 3.110 2.323 0.020 1.120 13.325
C(educ)[T.17] 9.5905 3.366 2.849 0.004 2.984 16.197
C(educ)[T.18] 7.3681 3.264 2.257 0.024 0.962 13.775
코드
plt.scatter(wage["educ"], wage["hwage"])
plt.plot(wage["educ"].sort_values(), model_dummy.predict(wage["educ"].sort_values()), c="C1")
plt.xlabel("Years of Education")
plt.ylabel("Hourly Wage");

먼저 이 모델은 교육이 임금에 영향을 미치는 함수 형태에 대한 가정을 모두 없앤다는 점에 주목하세요. 더는 로그를 쓸지 고민할 필요가 없습니다. 본질적으로 이 모델은 완전히 비모수적입니다. 하는 일이라고는 교육 연수별 임금의 표본평균을 구하는 것뿐입니다. 위 그래프에서도 이를 확인할 수 있는데, 적합된 선은 특정한 형태가 없습니다. 그 대신 교육 연수별 표본평균을 이은 내삽(interpolation)선입니다. 매개변수 하나를 직접 재구성해 봐도 알 수 있습니다. 예를 들어 교육 연수 17년의 매개변수는 이 모델에서 9.5905입니다. 아래에서 보듯이 이 값은 기준 교육 연수(9년)인 사람들과 교육 연수가 17년인 사람들의 차이일 뿐입니다.

\[ \beta_{17} = E[Y|T=17]-E[Y|T=9] \]

대신 이렇게 유연성을 허용하면 통계적 유의성을 잃는다는 대가가 따릅니다. 몇몇 교육 연수에서 p 값이 얼마나 큰지 보세요.

코드
t1 = wage.query("educ==17")["hwage"]
t0 = wage.query("educ==9")["hwage"]
print("E[Y|T=9]:", t0.mean())
print("E[Y|T=17]-E[Y|T=9]:", t1.mean() - t0.mean())
E[Y|T=9]: 18.56
E[Y|T=17]-E[Y|T=9]: 9.590472362353516

더미 공변량을 모델에 더 넣으면, 교육의 매개변수는 각 더미 그룹에서의 효과를 가중평균한 값이 됩니다.

\[ E\{ \ (E[Y_i|T=1, Group_i] - E[Y_i|T=0, Group_i])w(Group_i) \ \} \]

\(w(Group_i)\)는 그룹 내 처치의 분산 \(Var(T_i|Group_i)\)와 정확히 같지는 않지만 비례합니다. 여기서 자연스럽게 떠오르는 질문이 있습니다. 그룹 가중치로 표본 크기를 쓰는 완전한 비모수 추정량을 쓰면 되지 않을까요? 그것도 타당한 추정량이지만, 회귀분석이 하는 방식은 아닙니다. 회귀분석은 처치의 분산을 가중치로 쓰기 때문에 처치가 많이 변하는 그룹에 더 큰 가중치를 둡니다. 직관적으로도 말이 됩니다. 처치가 거의 일정하다면(예를 들어 한 명만 처치받고 나머지는 모두 처치받지 않았다면) 표본 크기가 아무리 커도 소용없습니다. 처치효과를 알려 주는 정보가 별로 없기 때문입니다.

코드
model_dummy_2 = smf.ols('hwage ~ C(educ) + C(IQ_bins)', data=wage_ed_bins).fit()
model_dummy_2.summary().tables[1]
coef std err t P>|t| [0.025 0.975]
Intercept 18.4178 2.991 6.158 0.000 12.548 24.288
C(educ)[T.10] -1.2149 3.392 -0.358 0.720 -7.872 5.442
C(educ)[T.11] -0.4687 3.332 -0.141 0.888 -7.008 6.070
C(educ)[T.12] 0.3400 3.059 0.111 0.912 -5.664 6.344
C(educ)[T.13] 2.4103 3.206 0.752 0.452 -3.882 8.702
C(educ)[T.14] 1.8040 3.238 0.557 0.578 -4.551 8.159
C(educ)[T.15] 3.8599 3.369 1.146 0.252 -2.752 10.472
C(educ)[T.16] 4.4060 3.171 1.390 0.165 -1.817 10.629
C(educ)[T.17] 6.7470 3.422 1.971 0.049 0.030 13.464
C(educ)[T.18] 4.3463 3.332 1.304 0.192 -2.194 10.886
C(IQ_bins)[T.1] 1.4216 0.898 1.584 0.114 -0.340 3.183
C(IQ_bins)[T.2] 2.9717 0.930 3.195 0.001 1.146 4.797
C(IQ_bins)[T.3] 3.7879 1.022 3.708 0.000 1.783 5.793

핵심 요약

이 장은 어떤 데이터 포인트가 다른 데이터 포인트보다 더 중요하다는 이야기로 시작했습니다. 선형모델을 추정할 때는 표본 크기가 크고 분산이 작은 데이터 포인트에 더 큰 가중치를 줘야 합니다. 이어서 모델에 표본 가중치를 쓰기만 하면 선형회귀가 그룹화되고 익명화된 데이터도 우아하게 다룰 수 있다는 것을 보았습니다.

다음으로 더미 회귀분석으로 넘어갔습니다. 더미 회귀분석을 쓰면 처치가 결과에 영향을 미치는 함수 형태를 전혀 가정하지 않는 비모수 모델을 만들 수 있다는 것을 보았습니다. 그리고 더미 회귀분석에 담긴 직관을 살펴보았습니다.

참고 자료

저는 이 책 전체를 Joshua Angrist, Alberto Abadie, Christopher Walters의 훌륭한 계량경제학 강의에 바치는 헌사라고 생각합니다. 이 책에 담긴 아이디어 대부분은 이들이 미국경제학회(American Economic Association)에서 한 강의에서 가져왔습니다. 힘든 2020년을 버틸 수 있는 것도 이 강의들을 보는 덕분입니다. * Cross-Section Econometrics * Mastering Mostly Harmless Econometrics

Angrist의 멋진 책들도 참고 자료로 소개하고 싶습니다. 이 책들 덕분에 계량경제학, 이들 표현으로는 ’Metrics가 아주 유용할 뿐 아니라 무척 재미있다는 것을 알게 되었습니다.

마지막 참고 자료는 Miguel Hernan과 Jamie Robins의 책입니다. 까다로운 인과적 질문에 답해야 할 때마다 믿음직한 동반자가 되어 주었습니다.

기여하기

Causal Inference for the Brave and True는 과학의 통계학이라 할 수 있는 인과추론을 다루는 오픈소스 자료입니다. 파이썬 기반의 무료 소프트웨어만 사용하며, 돈이 없어도, 배경지식이 많지 않아도 누구나 볼 수 있는 자료를 목표로 합니다. 이 책이 도움이 되었고 후원하고 싶다면 Patreon을 방문해 주세요. 금전적으로 기여하기 어렵다면 오타를 고치거나, 수정할 부분을 제안하거나, 이해하기 어려웠던 부분에 의견을 주는 것으로도 도울 수 있습니다. 책의 저장소에서 이슈를 열어 주세요. 마지막으로 이 내용이 마음에 들었다면 도움이 될 만한 사람들과 공유하고 GitHub에서 스타를 눌러 주세요.

힌트옮긴이

한국어판의 오역이나 오탈자는 한국어판 이슈 페이지에 알려 주세요. 한국어판이 도움이 되었다면 한국어판 저장소에도 스타를 부탁드립니다.

의견 나누기

번역이 어색한 곳, 더 쉬운 설명, 궁금한 점을 남겨 주세요. GitHub 계정으로 로그인하면 댓글을 달 수 있고, 남긴 의견은 GitHub Discussions에 장별로 모입니다.