From 53c6daa82749224f87c976863dac4401a0c7435d Mon Sep 17 00:00:00 2001 From: SungChul Hong Date: Fri, 28 Oct 2022 23:00:35 +0900 Subject: [PATCH] add chapter12 --- 12-Doubly-Robust-Estimation.ipynb | 632 ++++++++++++++++++++++++++++++ 1 file changed, 632 insertions(+) create mode 100644 12-Doubly-Robust-Estimation.ipynb diff --git a/12-Doubly-Robust-Estimation.ipynb b/12-Doubly-Robust-Estimation.ipynb new file mode 100644 index 0000000..121a12d --- /dev/null +++ b/12-Doubly-Robust-Estimation.ipynb @@ -0,0 +1,632 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# 12 - Doubly Robust Estimation\n", + "\n", + "## 한 우물만 파지마라\n", + "\n", + "앞서 선형회귀와 경향 점수(propensity score)로 가중치 방식을 통해 $E[Y|T=1] - E[Y|T=0] | X$ 를 추정하는 방법을 배웠습니다. 그렇다면 언제, 어떤 것을 써야할까요? 고민된다면 둘 다 쓰세요! Doubly Robust Estimation (이중강건추정) 방법은 어느 둘 중 하나에 의존할 필요가 없도록 경향 점수와 선형회귀방법을 결합했습니다.\n", + "\n", + "사고방식 실험을 통해 어떻게 작동하는지 알아봅시다. 사고방식 실험은 미국 고등학교 학생들을 무작위 추출하여 성장 사고방식의 효과를 알아보기 위한 연구입니다. 실험에서 학생들은 성장 사고방식을 심어주는 세미나에 초청됩니다. 그리고 학생들의 대학재학 기간 학업 능력을 추적하여 점수로 매깁니다. 이 점수는 성취점수로 취합되여 표준화됩니다. 이 실험의 실제 데이터는 학생들의 개인정보이므로 공개되지 않습니다. 대신 [Athey and Wager](https://arxiv.org/pdf/1902.07409.pdf)에서 제공한 실제 데이터와 똑같은 통계 요약치를 가지는 모의실험 데이터를 가지고 진행하겠습니다." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "tags": [ + "hide-input" + ] + }, + "outputs": [], + "source": [ + "import warnings\n", + "warnings.filterwarnings('ignore')\n", + "\n", + "import pandas as pd\n", + "import numpy as np\n", + "from matplotlib import style\n", + "from matplotlib import pyplot as plt\n", + "import seaborn as sns\n", + "\n", + "from sklearn.linear_model import LogisticRegression, LinearRegression\n", + "\n", + "%matplotlib inline\n", + "\n", + "style.use(\"fivethirtyeight\")\n", + "pd.set_option(\"display.max_columns\", 6)" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
schoolidinterventionachievement_score...school_ethnic_minorityschool_povertyschool_size
2597311.480828...-0.515202-0.1698490.173954
3435760-0.987277...-1.3109270.224077-0.426757
996340-0.152340...0.875012-0.7248010.761781
44886700.358336...0.3157550.0545861.862187
26371611.360920...-0.033161-0.9822741.591641
\n", + "

5 rows × 13 columns

\n", + "
" + ], + "text/plain": [ + " schoolid intervention achievement_score ... school_ethnic_minority \\\n", + "259 73 1 1.480828 ... -0.515202 \n", + "3435 76 0 -0.987277 ... -1.310927 \n", + "9963 4 0 -0.152340 ... 0.875012 \n", + "4488 67 0 0.358336 ... 0.315755 \n", + "2637 16 1 1.360920 ... -0.033161 \n", + "\n", + " school_poverty school_size \n", + "259 -0.169849 0.173954 \n", + "3435 0.224077 -0.426757 \n", + "9963 -0.724801 0.761781 \n", + "4488 0.054586 1.862187 \n", + "2637 -0.982274 1.591641 \n", + "\n", + "[5 rows x 13 columns]" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "data = pd.read_csv(\"./data/learning_mindset.csv\")\n", + "data.sample(5, random_state=5)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "실험이 무작위적으로 진행됐지만 교란 변수 (confounding)이 없는 사례처럼은 보이지 않습니다. 한 가지 이유는 처치 변수 (treatment)가 학생들의 세미나 초청권 수령이기 때문입니다. 그래서 참여햘 기회는 무작위이지만 참석 자체는 그렇지 않습니다(초청 받았지만 참석하지 않는 사례들도 곧 다뤄보도록 하겠습니다). 그 증거로 학생들의 성공 기대감과 세미나 참석이 연관성 들 수 있습니다. 높은 기대치를 스스로 되새기는 학생들이 성장 사고방식 세미나에 참석했을 확률이 높을 것 같습니다. " + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "success_expect\n", + "1 0.271739\n", + "2 0.265957\n", + "3 0.294118\n", + "4 0.271617\n", + "5 0.311070\n", + "6 0.354287\n", + "7 0.362319\n", + "Name: intervention, dtype: float64" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "data.groupby(\"success_expect\")[\"intervention\"].mean()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "우리가 알고 있는 것을 토대로 우리는 이것을 해결하기 위해 선형회귀방법이나 로지스틱 회귀분석을 통한 경향 점수 추정을 적용할 수 있습니다. 하기 전에 범주형 변수들을 더미 (dummy) 처리해야합니다. " + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "(10391, 32)\n" + ] + } + ], + "source": [ + "categ = [\"ethnicity\", \"gender\", \"school_urbanicity\"]\n", + "cont = [\"school_mindset\", \"school_achievement\", \"school_ethnic_minority\", \"school_poverty\", \"school_size\"]\n", + "\n", + "data_with_categ = pd.concat([\n", + " data.drop(columns=categ), # dataset without the categorical features\n", + " pd.get_dummies(data[categ], columns=categ, drop_first=False) # categorical features converted to dummies\n", + "], axis=1)\n", + "\n", + "print(data_with_categ.shape)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "이제 doubly robust estimation을 어떻게 작동하는지 이해할 준비가 됐습니다. \n", + "\n", + "## Doubly Robust Estimation\n", + "\n", + "![img](./data/img/doubly-robust/double.png)\n", + "\n", + "추정값을 바로 유도하기보단 먼저 이게 얼마나 멋진지 먼저 보여드리겠습니다.\n", + "\n", + "$\n", + "\\hat{ATE} = \\frac{1}{N}\\sum \\bigg( \\dfrac{T_i(Y_i - \\hat{\\mu_1}(X_i))}{\\hat{P}(X_i)} + \\hat{\\mu_1}(X_i) \\bigg) - \\frac{1}{N}\\sum \\bigg( \\dfrac{(1-T_i)(Y_i - \\hat{\\mu_0}(X_i))}{1-\\hat{P}(X_i)} + \\hat{\\mu_0}(X_i) \\bigg)\n", + "$\n", + "\n", + "여기서 $\\hat{P}(x)$는 경향 점수(예를 들면, 로지스틱 회귀분석을 사용해서 얻은 점수)입니다. $\\hat{\\mu_1}(x)$은 $E[Y|X, T=1]$ 추정치(예를 들면, 선형 회귀분석으로 얻은 예측값)이고 그리고 $\\hat{\\mu_0}(x)$은 $E[Y|X, T=0]$의 추정치입니다. 이미 추측했겠지만 doubly robust estimator의 첫번째 항은 $E[Y_1]$를 추정하고 두번째 항은 $E[Y_0]$을 추정합니다. 두번째 항도 동일한 방식으로 유추가 가능하니 첫번째 항에 대해서 자세히 알아보도록 합시다.\n", + "\n", + "처음 봤을 때, 이 공식이 어려워보입니다. 그러나 쫄지마세요. 뒤에서 매우 단순하다는 것을 보여줍니다. 먼저 코드로 어떻게 이 추정량을 작성하는지 보이겠습니다. 수식보다 코드로 이해하는데 더 친숙한 사람들이 있기 때문이죠. 실제로 이 추정량이 계산되는지 알아보죠, 갈까요?" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [], + "source": [ + "def doubly_robust(df, X, T, Y):\n", + " ps = LogisticRegression(C=1e6, max_iter=1000).fit(df[X], df[T]).predict_proba(df[X])[:, 1]\n", + " mu0 = LinearRegression().fit(df.query(f\"{T}==0\")[X], df.query(f\"{T}==0\")[Y]).predict(df[X])\n", + " mu1 = LinearRegression().fit(df.query(f\"{T}==1\")[X], df.query(f\"{T}==1\")[Y]).predict(df[X])\n", + " return (\n", + " np.mean(df[T]*(df[Y] - mu1)/ps + mu1) -\n", + " np.mean((1-df[T])*(df[Y] - mu0)/(1-ps) + mu0)\n", + " )" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "0.38822197203025405" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "T = 'intervention'\n", + "Y = 'achievement_score'\n", + "X = data_with_categ.columns.drop(['schoolid', T, Y])\n", + "\n", + "doubly_robust(data_with_categ, X, T, Y)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Doubly robust estimator은 세미나에 참석한 학생들이 참석증을 받지 못한 학생들에 비해 성취 점수가 0.388 높다고 기대합니다. 신뢰구간을 위해서 bootstrap 방법을 할 수 있습니다." + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": { + "scrolled": false + }, + "outputs": [], + "source": [ + "from joblib import Parallel, delayed # for parallel processing\n", + "\n", + "np.random.seed(88)\n", + "# run 1000 bootstrap samples\n", + "bootstrap_sample = 1000\n", + "ates = Parallel(n_jobs=4)(delayed(doubly_robust)(data_with_categ.sample(frac=1, replace=True), X, T, Y)\n", + " for _ in range(bootstrap_sample))\n", + "ates = np.array(ates)" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "ATE 95% CI: (0.35365379802081925, 0.41978432347111305)\n" + ] + } + ], + "source": [ + "print(f\"ATE 95% CI:\", (np.percentile(ates, 2.5), np.percentile(ates, 97.5)))" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "sns.distplot(ates, kde=False)\n", + "plt.vlines(np.percentile(ates, 2.5), 0, 20, linestyles=\"dotted\")\n", + "plt.vlines(np.percentile(ates, 97.5), 0, 20, linestyles=\"dotted\", label=\"95% CI\")\n", + "plt.title(\"ATE Bootstrap Distribution\")\n", + "plt.legend();" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "이제 doubly robust estimator 맛을 봤으니 이게 왜 대단한지 보죠. 먼저, $\\hat{P}(x)$ 또는 $\\hat{\\mu}(x)$ 중 하나만 잘 추정한다면 잘 작동하기 때문에 doubly robust 하다고 부릅니다. $E[Y_1]$ 를 추정하는 첫번째 항을 가지고 살펴보도록 하겠습니다. \n", + "\n", + "$\n", + "\\hat{E}[Y_1] = \\frac{1}{N}\\sum \\bigg( \\dfrac{T_i(Y_i - \\hat{\\mu_1}(X_i))}{\\hat{P}(X_i)} + \\hat{\\mu_1}(X_i) \\bigg)\n", + "$\n", + "\n", + "$\\hat{\\mu_1}(x)$ 이 정확하게 추정되었다고 가정해봅시다. 경향 점수 모델이 틀렸다고 해도 걱정할 필요없습니다. 왜냐하면 $\\hat{\\mu_1}(x)$ 정확하다면 $E[T_i(Y_i - \\hat{\\mu_1}(X_i))]=0$ 입니다. $T_i$ 가 곱해져서 처치된 값들만 선택하고 $\\hat{\\mu_1}$ 과의 잔차는 정의상 $0$이 됩니다. 그렇게 되면 추정량은 $\\hat{\\mu_1}(X_i)$ 에만 의존하게 되는데 가정에 의해 $\\hat{\\mu_1}(X_i)$ 은 $E[Y_1]$ 을 정확하게 추정하고 있습니다. 따라서, 교정에 의해 $\\hat{\\mu_1}(X_i)$ 경향 점수 모델을 싹 지워버립니다. 같은 방식으로 $E[Y_0]$ 의 추정량도 이해할 수 있습니다. \n", + "\n", + "글이 아니라 코드를 통해서 보여드릴게요! 다음 추정량에서는 경향 점수를 추정하는 로지스틱 회귀분석을 $0.1$ 에서 $0.9$ 의 값을 갖는 무작위 균일분포의 난수로 대체합니다 (아주 작은 가중치를 줘서 경향 점수 변동이 없어지지 않도록 합니다). 이 난수들은 무작위이기 때문에 경향 점수 모델은 절대 좋다고 할 수 없습니다. 하지만 doubly robust estimator는 여전히 로지스틱 모형으로 경향 점수를 추정했을 때와 매우 유사한 추정치를 갖습니다.\n" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [], + "source": [ + "from sklearn.linear_model import LogisticRegression, LinearRegression\n", + "\n", + "def doubly_robust_wrong_ps(df, X, T, Y):\n", + " # wrong PS model\n", + " np.random.seed(654)\n", + " ps = np.random.uniform(0.1, 0.9, df.shape[0])\n", + " mu0 = LinearRegression().fit(df.query(f\"{T}==0\")[X], df.query(f\"{T}==0\")[Y]).predict(df[X])\n", + " mu1 = LinearRegression().fit(df.query(f\"{T}==1\")[X], df.query(f\"{T}==1\")[Y]).predict(df[X])\n", + " return (\n", + " np.mean(df[T]*(df[Y] - mu1)/ps + mu1) -\n", + " np.mean((1-df[T])*(df[Y] - mu0)/(1-ps) + mu0)\n", + " )" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "0.3796984428841887" + ] + }, + "execution_count": 11, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "doubly_robust_wrong_ps(data_with_categ, X, T, Y)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Bootstrap 방법을 사용한다면 로지스틱 방법보다 추정치의 분산이 약간 큰 것을 알 수 있습니다." + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [], + "source": [ + "np.random.seed(88)\n", + "parallel_fn = delayed(doubly_robust_wrong_ps)\n", + "wrong_ps = Parallel(n_jobs=4)(parallel_fn(data_with_categ.sample(frac=1, replace=True), X, T, Y)\n", + " for _ in range(bootstrap_sample))\n", + "wrong_ps = np.array(wrong_ps)" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Original ATE 95% CI: (0.35365379802081925, 0.41978432347111305)\n", + "Wrong PS ATE 95% CI: (0.3386340898920725, 0.4330454015305953)\n" + ] + } + ], + "source": [ + "print(f\"Original ATE 95% CI:\", (np.percentile(ates, 2.5), np.percentile(ates, 97.5)))\n", + "\n", + "print(f\"Wrong PS ATE 95% CI:\", (np.percentile(wrong_ps, 2.5), np.percentile(wrong_ps, 97.5)))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "앞에서 보셨다시피 경향 점수를 망가뜨려서 약간 다르지만 큰 차이는 아닌 ATE 값들이 나왔습니다. 이 경우는 경향 점수가 잘못되고 평균 추정이 정확했습니다. 다른 상황에서는 어떨까요? \n", + "첫번째 항을 다시 살펴보고 항들의 순서를 바꾸어보겠습니다. \n", + "\n", + "$\n", + "\\hat{E}[Y_1] = \\frac{1}{N}\\sum \\bigg( \\dfrac{T_i(Y_i - \\hat{\\mu_1}(X_i))}{\\hat{P}(X_i)} + \\hat{\\mu_1}(X_i) \\bigg)\n", + "$\n", + "\n", + "$\n", + "\\hat{E}[Y_1] = \\frac{1}{N}\\sum \\bigg( \\dfrac{T_iY_i}{\\hat{P}(X_i)} - \\dfrac{T_i\\hat{\\mu_1}(X_i)}{\\hat{P}(X_i)} + \\hat{\\mu_1}(X_i) \\bigg)\n", + "$\n", + "\n", + "$\n", + "\\hat{E}[Y_1] = \\frac{1}{N}\\sum \\bigg( \\dfrac{T_iY_i}{\\hat{P}(X_i)} - \\bigg(\\dfrac{T_i}{\\hat{P}(X_i)} - 1\\bigg) \\hat{\\mu_1}(X_i) \\bigg)\n", + "$\n", + "\n", + "$\n", + "\\hat{E}[Y_1] = \\frac{1}{N}\\sum \\bigg( \\dfrac{T_iY_i}{\\hat{P}(X_i)} - \\bigg(\\dfrac{T_i - \\hat{P}(X_i)}{\\hat{P}(X_i)}\\bigg) \\hat{\\mu_1}(X_i) \\bigg)\n", + "$\n", + "\n", + "이제 경향 점수 $\\hat{P}(X_i)$ 가 정확하다고 가정해봅시다. 이 경우에는 $E[T_i - \\hat{P}(X_i)]=0$ 가 돼서 $\\hat{\\mu_1}(X_i)$ 와 관련된 항들을 지워버립니다. 이것이 doubly robust estimator 가 가정에 의해서 정확한 경향 점수 가중치 추정량 $\\frac{T_iY_i}{\\hat{P}(X_i)}$ 에만 의존하도록 만듭니다. 따라서 $\\hat{\\mu_1}(X_i)$ 가 틀렸다고 하더라도 경향 점수가 정확하기 때문에 추정량은 정확하게 됩니다. \n", + "\n", + "만약 수식보다 코드를 더 믿는다면 여기서 실제로 보이겠습니다. 아래 코드에서 회귀분석모델을 정규분포난수로 대체합니다. 여지 없이 $\\hat{\\mu}(X_i)$ 는 **틀렸습니다**. 그러나 여전히 doubly robust estimation는 앞서 본 약 0.38과 같은 $\\hat{ATE}$ 를 보입니다. " + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": {}, + "outputs": [], + "source": [ + "from sklearn.linear_model import LogisticRegression, LinearRegression\n", + "\n", + "def doubly_robust_wrong_model(df, X, T, Y):\n", + " np.random.seed(654)\n", + " ps = LogisticRegression(C=1e6, max_iter=1000).fit(df[X], df[T]).predict_proba(df[X])[:, 1]\n", + " \n", + " # wrong mu(x) model\n", + " mu0 = np.random.normal(0, 1, df.shape[0])\n", + " mu1 = np.random.normal(0, 1, df.shape[0])\n", + " return (\n", + " np.mean(df[T]*(df[Y] - mu1)/ps + mu1) -\n", + " np.mean((1-df[T])*(df[Y] - mu0)/(1-ps) + mu0)\n", + " )" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "0.3981405305433191" + ] + }, + "execution_count": 15, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "doubly_robust_wrong_model(data_with_categ, X, T, Y)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "또 bootstrap을 통해 추정치의 분산은 약간 높아지는 것을 확인할 수 있었습니다." + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": {}, + "outputs": [], + "source": [ + "np.random.seed(88)\n", + "parallel_fn = delayed(doubly_robust_wrong_model)\n", + "wrong_mux = Parallel(n_jobs=4)(parallel_fn(data_with_categ.sample(frac=1, replace=True), X, T, Y)\n", + " for _ in range(bootstrap_sample))\n", + "wrong_mux = np.array(wrong_mux)" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Original ATE 95% CI: (0.35365379802081925, 0.41978432347111305)\n", + "Wrong Mu ATE 95% CI: (0.3387086426185005, 0.41978432347111305)\n" + ] + } + ], + "source": [ + "print(f\"Original ATE 95% CI:\", (np.percentile(ates, 2.5), np.percentile(ates, 97.5)))\n", + "print(f\"Wrong Mu ATE 95% CI:\", (np.percentile(wrong_mux, 2.5), np.percentile(ates, 97.5)))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "다시 한번 말하면 조건부 기댓값 모델만 망가뜨렸을 때 약간 다른 ATE 값이 나왔습니다. 나는 doubly robust estimation의 강력함을 저자들에게 확신시켰다고 생각합니다. 인과추론에서 doubly robust estimation의 마법은 일어납니다. 왜냐하면 인과 추정치의 편향을 없애기 위해 두 가지 방법이 있기 때문입니다. 하나는 처치 방식을 잘 모델링하는 것이고 다른 하나는 종속변수를 잘 모델링하는 것입니다. 만약 둘 중에 하나가 정확하다면 진행해도 좋습니다.\n", + "\n", + "실제로 사용할 때 한 가지 주의할 점은 실제로 둘 중에 하나를 정화하게 모델링하는 것은 매우 어렵다는 것입니다. 실제로 경향 점수나 종속변수 모델링이 100% 정확하지 않는 경우가 결국에는 더 많습니다. 둘 다 다양한 방식으로 틀리게 됩니다. 이렇게 되면 단일 모델이 나을지 doubly robust estimation이 나을지 정확하게 알 수 없습니다 [\\[1\\]](https://www.stat.cmu.edu/~ryantibs/journalclub/kang_2007.pdf) [\\[2\\]](https://arxiv.org/pdf/0804.2969.pdf) [\\[3\\]](https://www.ncbi.nlm.nih.gov/pmc/articles/PMC2798744/). 저같은 경우에 적어도 정확할 수 있는 두 개의 가능성이 있기 때문에 둘 다 사용합니다. \n", + "\n", + "## Key Ideas\n", + "\n", + "이 장에서는 doubly robust estimator 를 만드는 선형회귀와 경향 점수를 결합하는 방식을 보았습니다. 이 추정량은 하나의 모델만 정확한 것을 요구하기 때문에 그런 이름이 붙었습니다. 만약 경향 점수 모델이 맞다면 종속변수 모델이 틀렸더라도 우리는 인과 효과를 추정할 수 있습니다. 반대로 종속변수 모델이 맞다면 경향 점수 모델이 틀리더라도 인과 효과를 추정할 수 있습니다. \n", + "\n", + "## References\n", + "\n", + "저는 이 책을 Joshua Angrist, Alberto Abadie 및 Christopher Walters의 대단한 계량 경제학 수업에 대한 찬사라고 생각하고 싶습니다. 이 자료에 있는 대부분의 아이디어는 전미경제학회(American Economic Association)의 수업에서 가져왔어요. 이렇게 좋은 참고자료를 지켜보는 것이 저의 2020년의 힘든 한 해 동안, 온전한 정신을 유지하도록 도와주었어요.\n", + "\n", + "* [Cross-Section Econometrics](https://www.aeaweb.org/conference/cont-ed/2017-webcasts)\n", + "* [Mastering Mostly Harmless Econometrics](https://www.aeaweb.org/conference/cont-ed/2020-webcasts)\n", + "\n", + "\n", + "또한 Angrist의 정말 좋은 책들을 참고자료 목록에 담고 싶습니다. 이 책들은 계량경제학(Econometrics) 또는 '메트릭스(Metrics, 계량적 분석)'가 매우 유용할 뿐만 아니라 매우 재미있다는 것을 저에게 보여주었습니다.\n", + "\n", + "* [Mostly Harmless Econometrics](https://www.mostlyharmlesseconometrics.com/)\n", + "* [Mastering 'Metrics](https://www.masteringmetrics.com/)\n", + "\n", + "마지막으로 제가 참고한 자료는 Miguel Hernan과 Jamie Robins의 책입니다. 이 책들은 제가 대답해야 했던 까다로운 인과적인 질문에서 신뢰할 수 있는 동반자와 같은 존재였어요.\n", + "\n", + "* [Causal Inference Book](https://www.hsph.harvard.edu/miguel-hernan/causal-inference-book/)\n", + "\n", + "이 글에 쓰인 데이터는 Susan Athey과 Stefan Wager 이 [Estimating Treatment Effects with Causal Forests: An Application](https://arxiv.org/pdf/1902.07409.pdf) 제공하고 있습니다.\n", + "\n", + "## Contribute\n", + "\n", + "Causal Inference for the Brave and True는 인과추론, 통계학에 대한 오픈소스 자료입니다. 이 자료는 금전적으로나 지적으로 접근이 가능할 수 있도록 하는 것이 목표입니다. 그리고, 이 책은 Python 기반의 무료 소프트웨어만 사용해요.\n", + "여러분들께서 이 자료가 가치 있다고 생각하시고, 금전적으로 지원을 원하신다면 [Patreon](https://www.patreon.com/causal_inference_for_the_brave_and_true)를 방문해주세요. \n", + "만약 여러분이 금전적으로 기여하기가 쉽지 않으시다면, 오타 수정, 수정 제안, 이해하기 난해한 부분에 대한 피드백 제공 등을 통해 도움을 주실 수 있어요. 이 책의 Github 저장소 [이슈 페이지](https://github.com/matheusfacure/python-causality-handbook/issues)를 방문해주세요. 마지막으로 이 자료가 여러분의 마음에 드셨다면 도움이 될 수 있는 다른 사람들과 공유해주시고, [이 책의 Github 자료에 star](https://github.com/matheusfacure/python-causality-handbook/stargazers) 부탁드립니다!" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "celltoolbar": "Tags", + "kernelspec": { + "display_name": "Python 3.7.7 ('crypto')", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.7.7" + }, + "vscode": { + "interpreter": { + "hash": "6612ddc8508fe2bfb55c921cc5a3fb1a13f883f137f06750cc87c7c54112973a" + } + } + }, + "nbformat": 4, + "nbformat_minor": 2 +}