{ "cells": [ { "cell_type": "markdown", "metadata": { "Collapsed": "false", "colab_type": "text", "id": "W3Vr9I8k5xYZ", "toc-hr-collapsed": false }, "source": [ "# Ch12 逆概率加权和边际结构模型\n", "\n", "IP Weighting and Marginal Structural Models " ] }, { "cell_type": "markdown", "metadata": { "Collapsed": "false", "toc-hr-collapsed": true }, "source": [ "## 内容摘要" ] }, { "cell_type": "markdown", "metadata": { "Collapsed": "false", "colab_type": "text", "id": "S2rrX3Lm5xYf" }, "source": [ "本书第二部分围绕因果问题“戒烟对体重增加的平均因果效应是什么?”进行组织。在本章中,我们描述如何使用IP加权从观测数据中估计这种效应。尽管在第二章中介绍了IP加权,但我们仅将其描述为非参数方法。We now describe the use of models together with IP weighting,在额外的假设下,这些模型将使我们能够处理高维问题 with many covariates and nondichotomous treatments.\n", "\n", "为了估计戒烟对体重增加的影响,我们将使用NHEFS的真实数据,该缩写词代表国家卫生和营养检查调查数据I流行病学随访研究。NHEFS是由国家卫生统计中心和国家老龄研究所与美国公共卫生局其他机构共同发起的。\n", "可以在 www.cdc.gov/nchs/nhanes/nhefs/ 上找到NHEFS的详细说明以及可公开获得的数据集和文档。\n", "在本章及以后的章节中,我们将使用NHEFS数据的一部分,该数据可从本书的网站上获得。\n", "\n", "> 我们关注的是戒烟是否会引起体重增加?" ] }, { "cell_type": "markdown", "metadata": { "Collapsed": "false", "colab_type": "text", "id": "kestfkDK5xY3" }, "source": [ "### 12.1 The causal question\n", "\n", "> 戒烟是否会引起体重增加?\n", "$\\theta = E[Y^{a=1}] - E[Y^{a=0}]$如何估计呢?\n", "\n", "Our goal is to estimate the average causal effect of smoking cessation (the treatment) A on weight gain (the outcome) Y ." ] }, { "cell_type": "markdown", "metadata": { "Collapsed": "false", "colab_type": "text", "id": "3NG_uc6t5xZ2" }, "source": [ "### 12.2 Estimating IP weights via modeling\n", "\n", "必须回答的一个关键问题是: if $A$ is a continuous variable, then IPW 方法的推广是什么?更简单的如果 $A$ 是个离散变量,如何使用一组权重 $W$ 使得加权总体中,$L$ 的分布并不影响 $A$ 的分布。" ] }, { "cell_type": "markdown", "metadata": { "Collapsed": "false", "colab_type": "text", "id": "S8ZdOh6h5xZ3" }, "source": [ "IP weighting creates a pseudo-population in which the arrow from the covariates $L$ to the treatment $A$ is removed. 也就是说\n", "\n", "$L \\rightarrow A$ for population $S$, then we create a pseudo-population $S'$ in which the distribution of $A$ is not influenced by any information about $L$ keeping everything else unchange. 这里就导致一个悖论,在视角 $S$ 下,$L$ 是 $A$ 的原因,但是换一个视角 $S'$ 他就不再是其原因了。\n", "\n", "- 一种解释方式是 effect 是 cause 的一种测量。例如测量体重环境变化了,太空中重量就测出来是以个常数,或者说测不出来。 这种解释的问题在于新的环境意味着新的因果机制,pseudo-population 的 setting 变化只是视角的变化,而不是环境或者因果机制的变化。\n", "- 另外一种解释方式是,只存在 individual-level causal effect 的因果关系不变性,在群体层次上的因果关系并存在 invariant 因果关系,群体层次上的因果关系是一种统计特性。具体来说具备不变性的是个体因果关系,而因果效应确实一个离开了特定总体就没有定义的量 which is a statistical quantity。这种解释的问题在于\n", "\n", "这里有一个问题 $A$ 是 $L$ 的原因, 那么 $A$ 一定对 $L$ 有因果效应。" ] }, { "cell_type": "markdown", "metadata": { "Collapsed": "false", "colab_type": "text", "id": "mxjyJePD5xbe" }, "source": [ "### 12.3 Stabilized IP weights\n", "\n", "Create the stabilized IP weights $SW^A = f(A) \\, / \\, f(A|L)$" ] }, { "cell_type": "markdown", "metadata": { "Collapsed": "false", "colab_type": "text", "id": "rix4qsWk5xbi" }, "source": [ "\"The effect estimate obtained in the pseudo-population created by weights $0.5 \\, / \\, f(A|L)$\n", "is equal to that obtained in the pseudo-population created by weights $1 \\, / \\, f(A|L)$.\"" ] }, { "cell_type": "markdown", "metadata": { "Collapsed": "false", "colab_type": "text", "id": "1dPCV3JQ5xc4", "toc-hr-collapsed": false }, "source": [ "### 12.4 Marginal structural models\n", "\n", "Models for the marginal mean of a counterfactual outcome are referred to as marginal structural mean models. 反事实结果的边际均值模型称为边际结构均值模型。" ] }, { "cell_type": "markdown", "metadata": { "Collapsed": "false" }, "source": [ "模型的各种变体,从离散的连续。\n", "\n", "Marginal structural mean models within a pseudo-population:\n", "\n", "$$E[Y^a] = \\beta_0 + \\beta_1 a$$ \n", "$$\\Rightarrow E[Y^a] = \\beta_0 + \\beta_1 a + \\beta_2 a^2$$ \n", "\n", "\n", "marginal structural logistic model\n", "\n", "$$logit Pr[Y^a = 1] = \\beta_0 + \\beta_1 a$$ " ] }, { "cell_type": "markdown", "metadata": { "Collapsed": "false", "colab_type": "text", "id": "qN_aHhL45xee" }, "source": [ "### 12.5 Effect modification and marginal structural models\n", "\n", "Marginal structural models do not include covariates when the target parameter is the average causal effect in the population. However, one may include covariates–which may be non-confounders–in a marginal structural model to assess effect modification." ] }, { "cell_type": "markdown", "metadata": { "Collapsed": "false", "colab_type": "text", "id": "XZoJSbE95xef" }, "source": [ "在第一部分中,我们讨论了 effect modification and confounding 是两个在逻辑上截然不同的概念。 但是,许多学生很难理解这种区别,因为经常使用相同的统计方法(分层(第4章)或回归(第15章)for confounder adjustment and detection of effect modification. 因此,使用边际结构模型来讲授这些概念可能会有一些优势, because then methods for confounder adjustment (IP weighting) are distinct from methods for detection of effect modification (adding treatment-covariate product terms to a marginal structural model).\n" ] }, { "cell_type": "markdown", "metadata": { "Collapsed": "false", "colab_type": "text", "id": "gu14xRuZ5xev" }, "source": [ "### 12.6 Censoring and missing data\n" ] }, { "cell_type": "markdown", "metadata": { "Collapsed": "true", "colab_type": "text", "id": "tAbhsGcA5xYg", "toc-hr-collapsed": true }, "source": [ "## Programs\n", "\n", "**Setup and imports**" ] }, { "cell_type": "code", "execution_count": 2, "metadata": { "Collapsed": "false", "colab": {}, "colab_type": "code", "id": "1TMm0xOW5xYh" }, "outputs": [], "source": [ "%matplotlib inline\n", "\n", "import warnings\n", "warnings.filterwarnings('ignore')\n", "\n", "from collections import OrderedDict\n", "import numpy as np\n", "import pandas as pd\n", "import statsmodels.api as sm\n", "import scipy.stats\n", "import matplotlib.pyplot as plt" ] }, { "cell_type": "code", "execution_count": 5, "metadata": { "Collapsed": "false", "colab": {}, "colab_type": "code", "id": "v7UvRwZ15xYq", "outputId": "fe462c77-2858-472d-f4bb-e0e9171110f9" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "WARNING *** OLE2 inconsistency: SSCS size is 0 but SSAT size is non-zero\n" ] }, { "data": { "text/plain": [ "(1629, 64)" ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Just a look at a couple basic details of the dataset\n", "nhefs_all = pd.read_excel('NHEFS.xls')\n", "nhefs_all.shape" ] }, { "cell_type": "code", "execution_count": 6, "metadata": { "Collapsed": "false" }, "outputs": [ { "data": { "text/plain": [ "( Variable name Description\n", " 0 active in your usual day, how active are you? in 1971...\n", " 1 age age in 1971\n", " 2 alcoholfreq how often do you drink? in 1971 0: almost ev...\n", " 3 alcoholhowmuch when you drink, how much do you drink? in 1971\n", " 4 alcoholpy have you had 1 drink past year? in 1971, 1:ev...,\n", " ['in your usual day, how active are you? in 1971, 0:very active, 1:moderately active, 2:inactive',\n", " 'age in 1971',\n", " 'how often do you drink? in 1971 0: almost every day, 1: 2-3 times/week, 2: 1-4 times/month, 3: < 12 times/year, 4: no alcohol last year, 5: unknown',\n", " 'when you drink, how much do you drink? in 1971',\n", " 'have you had 1 drink past year? in 1971, 1:ever, 0:never; 2:missing'])" ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "codebook = pd.read_excel('codebook.xls')\n", "codebook.Description = codebook.Description.apply(lambda s: s.lower())\n", "var_list = codebook.iloc[:, 1].tolist()\n", "codebook.head(), var_list[:5]" ] }, { "cell_type": "code", "execution_count": 7, "metadata": { "Collapsed": "false" }, "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", "
qsmkwt82_71
00-10.093960
102.604970
209.414486
304.990117
404.989251
\n", "
" ], "text/plain": [ " qsmk wt82_71\n", "0 0 -10.093960\n", "1 0 2.604970\n", "2 0 9.414486\n", "3 0 4.990117\n", "4 0 4.989251" ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "d = nhefs_all[['qsmk', 'wt82_71']]\n", "d.head()" ] }, { "cell_type": "markdown", "metadata": { "Collapsed": "false", "colab_type": "text", "id": "YI5bIAXS5xY5" }, "source": [ "### Program 12.1" ] }, { "cell_type": "markdown", "metadata": { "Collapsed": "false", "colab_type": "text", "id": "481A8Fe_5xY_" }, "source": [ "\"We restricted the analysis to NHEFS individuals with known sex, age, race, ...\" (pg 149, margin)" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "Collapsed": "false", "colab": {}, "colab_type": "code", "id": "HzJMyIPJ5xZA", "outputId": "2a87e24a-d82a-46b1-d7a5-d884d8801427" }, "outputs": [ { "data": { "text/plain": [ "(1566, 64)" ] }, "execution_count": 4, "metadata": { "tags": [] }, "output_type": "execute_result" } ], "source": [ "restriction_cols = [\n", " 'sex', 'age', 'race', 'wt82', 'ht', 'school', 'alcoholpy', 'smokeintensity'\n", "]\n", "missing = nhefs_all[restriction_cols].isnull().any(axis=1)\n", "nhefs = nhefs_all.loc[~missing]\n", "nhefs.shape" ] }, { "cell_type": "markdown", "metadata": { "Collapsed": "false", "colab_type": "text", "id": "Pj6no4S75xZK" }, "source": [ "We're going to add some columns to help calculate Table 12.1, and a `constant` column, which will be useful for modeling" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "Collapsed": "false", "colab": {}, "colab_type": "code", "id": "Q0PNjTSl5xZN" }, "outputs": [], "source": [ "nhefs['constant'] = 1\n", "nhefs['university'] = (nhefs.education == 5).astype('int')\n", "nhefs['inactive'] = (nhefs.active == 2).astype('int')\n", "nhefs['no_exercise'] = (nhefs.exercise == 2).astype('int')" ] }, { "cell_type": "markdown", "metadata": { "Collapsed": "false", "colab_type": "text", "id": "jSfwWuul5xZU" }, "source": [ "戒烟者和非戒烟者的平均体重增加:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "Collapsed": "false", "colab": {}, "colab_type": "code", "id": "zPa752NF5xZW", "outputId": "dd077eed-1b24-4d79-cbe9-aceb389d72ce" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Average weight gain\n", " quitters: 4.5 kg\n", " non-quitters: 2.0 kg\n" ] } ], "source": [ "ave_gain_quit = nhefs[nhefs.qsmk == 1].wt82_71.mean()\n", "ave_gain_noquit = nhefs[nhefs.qsmk == 0].wt82_71.mean()\n", "\n", "print(\"Average weight gain\")\n", "print(\" quitters: {:>0.1f} kg\".format(ave_gain_quit))\n", "print(\" non-quitters: {:>0.1f} kg\".format(ave_gain_noquit))" ] }, { "cell_type": "markdown", "metadata": { "Collapsed": "false", "colab_type": "text", "id": "nFKPIBVN5xZf" }, "source": [ "创建一个简单的线性模型以获取体重差异的置信区间。" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "Collapsed": "false", "colab": {}, "colab_type": "code", "id": "JApsbJ6Z5xZh", "outputId": "5f536ec1-5cf8-45d6-bfcc-fd39740c620e" }, "outputs": [ { "data": { "text/html": [ "\n", "\n", " \n", "\n", "\n", " \n", "\n", "\n", " \n", "\n", "
coef std err t P>|t| [0.025 0.975]
constant 1.9845 0.229 8.672 0.000 1.536 2.433
qsmk 2.5406 0.451 5.632 0.000 1.656 3.425
" ], "text/plain": [ "" ] }, "execution_count": 7, "metadata": { "tags": [] }, "output_type": "execute_result" } ], "source": [ "ols = sm.OLS(nhefs.wt82_71, nhefs[['constant', 'qsmk']])\n", "res = ols.fit()\n", "res.summary().tables[1]" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "Collapsed": "false", "colab": {}, "colab_type": "code", "id": "qfvnavEW5xZo", "outputId": "ed4a51c0-1521-4b33-d68e-e35fd4930de0" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ " estimate 95% C.I.\n", "difference 2.54 (1.7, 3.4)\n" ] } ], "source": [ "est = res.params.qsmk\n", "conf_ints = res.conf_int(alpha=0.05, cols=None)\n", "lo, hi = conf_ints[0]['qsmk'], conf_ints[1]['qsmk']\n", "\n", "print(' estimate 95% C.I.')\n", "print('difference {:>6.2f} ({:>0.1f}, {:>0.1f})'.format(est, lo, hi))" ] }, { "cell_type": "markdown", "metadata": { "Collapsed": "false", "colab_type": "text", "id": "GG8eIqMa5xZu" }, "source": [ "Create Table 12.1 in the margin of pg 149." ] }, { "cell_type": "markdown", "metadata": { "Collapsed": "false", "colab_type": "text", "id": "7rIpPfIv5xZv" }, "source": [ "As shown in Table 12.1, quitters and non-quitters also differed in their distribution of other variables such as sex, race, education, baseline weight, and intensity of smoking. If these variables are confounders, then they also need to be adjusted for in the analysis. " ] }, { "cell_type": "code", "execution_count": null, "metadata": { "Collapsed": "false", "colab": {}, "colab_type": "code", "id": "XIEF4gyK5xZw", "outputId": "c2fb3d20-9537-448b-b652-3a49805b40d0" }, "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", "
qsmk 1 0
Age, years46.242.8
Men, %54.646.6
White, %91.185.4
University education, %15.49.9
Weight, kg72.470.3
Cigarettes/day18.621.2
Years smoking26.024.1
Little or no exercise, %40.737.9
Inactive daily life, %11.28.9
" ], "text/plain": [ "" ] }, "execution_count": 9, "metadata": { "tags": [] }, "output_type": "execute_result" } ], "source": [ "summaries = OrderedDict((\n", " ('age', 'mean'),\n", " ('sex', lambda x: (100 * (x == 0)).mean()),\n", " ('race', lambda x: (100 * (x == 0)).mean()),\n", " ('university', lambda x: 100 * x.mean()),\n", " ('wt71', 'mean'),\n", " ('smokeintensity', 'mean'),\n", " ('smokeyrs', 'mean'),\n", " ('no_exercise', lambda x: 100 * x.mean()),\n", " ('inactive', lambda x: 100 * x.mean())\n", "))\n", "\n", "table = nhefs.groupby('qsmk').agg(summaries)\n", "table.sort_index(ascending=False, inplace=True)\n", "table = table.T\n", "\n", "table.index = [\n", " 'Age, years',\n", " 'Men, %',\n", " 'White, %',\n", " 'University education, %',\n", " 'Weight, kg',\n", " 'Cigarettes/day',\n", " 'Years smoking',\n", " 'Little or no exercise, %',\n", " 'Inactive daily life, %'\n", "]\n", "\n", "table.style.format(\"{:>0.1f}\")" ] }, { "cell_type": "markdown", "metadata": { "Collapsed": "false", "colab_type": "text", "id": "gkJjAU5I5xZ5" }, "source": [ "### Program 12.2" ] }, { "cell_type": "markdown", "metadata": { "Collapsed": "false", "colab_type": "text", "id": "l4XJRrJQ5xZ9" }, "source": [ "We're going to be modeling with squared terms and some categorical features. Here we'll explicitly add squared features and dummy features to the data. In later chapters we'll use Statsmodels' formula syntax." ] }, { "cell_type": "markdown", "metadata": { "Collapsed": "false", "colab_type": "text", "id": "qCIwhWGW5xZ_" }, "source": [ "Squared features:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "Collapsed": "false", "colab": {}, "colab_type": "code", "id": "FwAU3FhT5xaA" }, "outputs": [], "source": [ "for col in ['age', 'wt71', 'smokeintensity', 'smokeyrs']:\n", " nhefs['{}^2'.format(col)] = nhefs[col] * nhefs[col]" ] }, { "cell_type": "markdown", "metadata": { "Collapsed": "false", "colab_type": "text", "id": "_JF_pRQX5xaG" }, "source": [ "Dummy features:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "Collapsed": "false", "colab": {}, "colab_type": "code", "id": "VNnr5q5A5xaH" }, "outputs": [], "source": [ "edu_dummies = pd.get_dummies(nhefs.education, prefix='edu')\n", "exercise_dummies = pd.get_dummies(nhefs.exercise, prefix='exercise')\n", "active_dummies = pd.get_dummies(nhefs.active, prefix='active')\n", "\n", "nhefs = pd.concat(\n", " [nhefs, edu_dummies, exercise_dummies, active_dummies],\n", " axis=1\n", ")" ] }, { "cell_type": "markdown", "metadata": { "Collapsed": "false", "colab_type": "text", "id": "0X6_4oq75xaN" }, "source": [ "We're going to be creating a lot of IP weights from logistic regressions so a function will help reduce the work. The following function creates the denominators of the IP weights." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "Collapsed": "false", "colab": {}, "colab_type": "code", "id": "mX-jTBLe5xaP" }, "outputs": [], "source": [ "def logit_ip_f(y, X):\n", " \"\"\"\n", " Create the f(y|X) part of IP weights\n", " from logistic regression\n", " \n", " Parameters\n", " ----------\n", " y : Pandas Series\n", " X : Pandas DataFrame\n", " \n", " Returns\n", " -------\n", " Numpy array of IP weights\n", " \n", " \"\"\"\n", " model = sm.Logit(y, X)\n", " res = model.fit()\n", " weights = np.zeros(X.shape[0])\n", " weights[y == 1] = res.predict(X.loc[y == 1])\n", " weights[y == 0] = (1 - res.predict(X.loc[y == 0]))\n", " return weights" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "Collapsed": "false", "colab": {}, "colab_type": "code", "id": "ossLEwFm5xaS", "outputId": "e04f9791-7225-4c20-e9cd-a5f9530fbbb8" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Optimization terminated successfully.\n", " Current function value: 0.535408\n", " Iterations 6\n" ] } ], "source": [ "X_ip = nhefs[[\n", " 'constant',\n", " 'sex', 'race', 'age', 'age^2', 'edu_2', 'edu_3', 'edu_4', 'edu_5',\n", " 'smokeintensity', 'smokeintensity^2', 'smokeyrs', 'smokeyrs^2', \n", " 'exercise_1', 'exercise_2', 'active_1', 'active_2', 'wt71', 'wt71^2'\n", "]]\n", "\n", "denoms = logit_ip_f(nhefs.qsmk, X_ip)\n", "weights = 1 / denoms" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "Collapsed": "false", "colab": {}, "colab_type": "code", "id": "79mVEfCr5xaX", "outputId": "94d58591-b984-463d-c339-2f1693e0ed0f" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "IP weights\n", " min: 1.05 expected: 1.05\n", " max: 16.70 expected: 16.70\n", " mean: 2.00 expected: 2.00\n" ] } ], "source": [ "print('IP weights')\n", "print(' min: {:>5.2f} expected: 1.05'.format(weights.min()))\n", "print(' max: {:>5.2f} expected: 16.70'.format(weights.max()))\n", "print(' mean: {:>5.2f} expected: 2.00'.format(weights.mean()))" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "Collapsed": "false", "colab": {}, "colab_type": "code", "id": "5XRZb2DY5xae", "outputId": "ea3c0912-592e-4a76-f4ea-3af448e12c34" }, "outputs": [ { "data": { "image/png": "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\n", "text/plain": [ "
" ] }, "metadata": { "needs_background": "light", "tags": [] }, "output_type": "display_data" } ], "source": [ "fig, ax = plt.subplots(figsize=(8, 6))\n", "\n", "ax.hist(weights, bins=20);" ] }, { "cell_type": "markdown", "metadata": { "Collapsed": "false", "colab_type": "text", "id": "cPQODKAj5xak" }, "source": [ "Now, the main model" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "Collapsed": "false", "colab": {}, "colab_type": "code", "id": "ItxzfYLM5xam" }, "outputs": [], "source": [ "y = nhefs.wt82_71\n", "X = nhefs[['constant', 'qsmk']]" ] }, { "cell_type": "markdown", "metadata": { "Collapsed": "false", "colab_type": "text", "id": "DxGUOjry5xas" }, "source": [ "Weighted least squares gives the right coefficients, but the standard error is off." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "Collapsed": "false", "colab": {}, "colab_type": "code", "id": "IP-ZN6dn5xat", "outputId": "07a13ad4-8b01-4c94-c6ba-291e14656b20" }, "outputs": [ { "data": { "text/html": [ "\n", "\n", " \n", "\n", "\n", " \n", "\n", "\n", " \n", "\n", "
coef std err t P>|t| [0.025 0.975]
constant 1.7800 0.288 6.175 0.000 1.215 2.345
qsmk 3.4405 0.408 8.434 0.000 2.640 4.241
" ], "text/plain": [ "" ] }, "execution_count": 17, "metadata": { "tags": [] }, "output_type": "execute_result" } ], "source": [ "wls = sm.WLS(y, X, weights=weights) \n", "res = wls.fit()\n", "res.summary().tables[1]" ] }, { "cell_type": "markdown", "metadata": { "Collapsed": "false", "colab_type": "text", "id": "UqvNDOJJ5xay" }, "source": [ "GEE gives the right coefficients and better standard errors" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "Collapsed": "false", "colab": {}, "colab_type": "code", "id": "vx6pV6_g5xaz", "outputId": "66b51bd6-efb4-4b9c-faa0-f6b324b6f66f" }, "outputs": [ { "data": { "text/html": [ "\n", "\n", " \n", "\n", "\n", " \n", "\n", "\n", " \n", "\n", "
coef std err z P>|z| [0.025 0.975]
constant 1.7800 0.225 7.920 0.000 1.340 2.220
qsmk 3.4405 0.525 6.547 0.000 2.411 4.470
" ], "text/plain": [ "" ] }, "execution_count": 18, "metadata": { "tags": [] }, "output_type": "execute_result" } ], "source": [ "gee = sm.GEE(\n", " nhefs.wt82_71,\n", " nhefs[['constant', 'qsmk']],\n", " groups=nhefs.seqn,\n", " weights=weights\n", ")\n", "res = gee.fit()\n", "res.summary().tables[1]" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "Collapsed": "false", "colab": {}, "colab_type": "code", "id": "agP0AOsL5xa3", "outputId": "8a12a01a-fc4a-4657-81f7-c998278f70ab" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ " estimate 95% C.I.\n", "theta_1 3.44 (2.4, 4.5)\n" ] } ], "source": [ "est = res.params.qsmk\n", "conf_ints = res.conf_int(alpha=0.05, cols=None)\n", "lo, hi = conf_ints[0]['qsmk'], conf_ints[1]['qsmk']\n", "\n", "print(' estimate 95% C.I.')\n", "print('theta_1 {:>6.2f} ({:>0.1f}, {:>0.1f})'.format(est, lo, hi))" ] }, { "cell_type": "markdown", "metadata": { "Collapsed": "false", "colab_type": "text", "id": "sNbP433q5xa6" }, "source": [ "Here's a simple check that there is no association between `sex` and `qsmk`." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "Collapsed": "false", "colab": {}, "colab_type": "code", "id": "ELtHxkw35xa8", "outputId": "c733a677-c6d3-41bc-c9d3-5f0eebec1277" }, "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", "
qsmk01
sex
0763.607760763.623497
1801.748892797.200691
\n", "
" ], "text/plain": [ "qsmk 0 1\n", "sex \n", "0 763.607760 763.623497\n", "1 801.748892 797.200691" ] }, "execution_count": 20, "metadata": { "tags": [] }, "output_type": "execute_result" } ], "source": [ "pd.crosstab(nhefs.sex, nhefs.qsmk, weights, aggfunc='sum')" ] }, { "cell_type": "markdown", "metadata": { "Collapsed": "false", "colab_type": "text", "id": "n0JSRX5U5xbB" }, "source": [ "(This matches the R output, but the Stata output is different.)" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "Collapsed": "false", "colab": {}, "colab_type": "code", "id": "hzrMumIt5xbC" }, "outputs": [], "source": [ "subset_indices = (nhefs.race == 0) & (nhefs.sex == 1)\n", "subset = nhefs.loc[subset_indices]" ] }, { "cell_type": "markdown", "metadata": { "Collapsed": "false", "colab_type": "text", "id": "10bZg07_5xbG" }, "source": [ "Now a check for positivity" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "Collapsed": "false", "colab": {}, "colab_type": "code", "id": "_a-TmmCm5xbH" }, "outputs": [], "source": [ "crosstab = pd.crosstab(subset.age, subset.qsmk).sort_index()" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "Collapsed": "false", "colab": {}, "colab_type": "code", "id": "50rGRCRu5xbL", "outputId": "2c1e10f8-309a-4afb-ab29-d2a692b4b361" }, "outputs": [ { "data": { "image/png": "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\n", "text/plain": [ "
" ] }, "metadata": { "needs_background": "light", "tags": [] }, "output_type": "display_data" } ], "source": [ "fig, ax = plt.subplots(figsize=(8, 6))\n", "\n", "ax.axhline(0, c='gray')\n", "ax.plot(crosstab.index, crosstab[0], label='non-quitters')\n", "ax.plot(crosstab.index, crosstab[1], label='quitters')\n", "ax.set_xlabel('age', fontsize=14)\n", "ax.set_ylabel('count', fontsize=14)\n", "ax.legend(fontsize=12);" ] }, { "cell_type": "markdown", "metadata": { "Collapsed": "false", "colab_type": "text", "id": "zfrhqjAk5xbS" }, "source": [ "We see that there are actually a few ages with zero counts" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "Collapsed": "false", "colab": {}, "colab_type": "code", "id": "hzpYvIfS5xbW", "outputId": "a1ce4453-0399-4f75-bd6f-cf67b6f30fd8" }, "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", "
qsmk01
age
6333
6471
6532
6640
6720
6962
7021
7101
7222
7401
\n", "
" ], "text/plain": [ "qsmk 0 1\n", "age \n", "63 3 3\n", "64 7 1\n", "65 3 2\n", "66 4 0\n", "67 2 0\n", "69 6 2\n", "70 2 1\n", "71 0 1\n", "72 2 2\n", "74 0 1" ] }, "execution_count": 24, "metadata": { "tags": [] }, "output_type": "execute_result" } ], "source": [ "crosstab.iloc[-10:]" ] }, { "cell_type": "markdown", "metadata": { "Collapsed": "false", "colab_type": "text", "id": "TKYXwb6B5xbb" }, "source": [ "For a discussion on ages with zero counts, see Fine Point 12.2, pg 155." ] }, { "cell_type": "markdown", "metadata": { "Collapsed": "false", "colab_type": "text", "id": "rix4qsWk5xbi" }, "source": [ "\"The effect estimate obtained in the pseudo-population created by weights $0.5 \\, / \\, f(A|L)$\n", "is equal to that obtained in the pseudo-population created by weights $1 \\, / \\, f(A|L)$.\"" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "Collapsed": "false", "colab": {}, "colab_type": "code", "id": "Cc1SRmqa5xbk", "outputId": "333e256d-6719-4079-bbff-cd879a1518b2" }, "outputs": [ { "data": { "text/html": [ "\n", "\n", " \n", "\n", "\n", " \n", "\n", "\n", " \n", "\n", "
coef std err z P>|z| [0.025 0.975]
constant 1.7800 0.225 7.920 0.000 1.340 2.220
qsmk 3.4405 0.525 6.547 0.000 2.411 4.470
" ], "text/plain": [ "" ] }, "execution_count": 25, "metadata": { "tags": [] }, "output_type": "execute_result" } ], "source": [ "gee = sm.GEE(\n", " nhefs.wt82_71,\n", " nhefs[['constant', 'qsmk']],\n", " groups=nhefs.seqn,\n", " weights=(0.5 * weights)\n", ")\n", "res = gee.fit()\n", "res.summary().tables[1]" ] }, { "cell_type": "markdown", "metadata": { "Collapsed": "false", "colab_type": "text", "id": "IEUBU0aG5xbq" }, "source": [ "\"Second, we need to estimate Pr[A=1] for the numerator of the weights. We can obtain a nonparametric estimate by the ratio 403/1566 or, equivalently, by fitting a saturated logistic model for Pr[A=1] with an intercept and no covariates.\" pg 154" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "Collapsed": "false", "colab": {}, "colab_type": "code", "id": "oKO38NWD5xbt" }, "outputs": [], "source": [ "qsmk = (nhefs.qsmk == 1)" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "Collapsed": "false", "colab": {}, "colab_type": "code", "id": "bgHLFLPs5xbw", "outputId": "586a2e6d-6be3-4bfb-b784-1a0a7f5ecb80" }, "outputs": [ { "data": { "text/plain": [ "0.25734355044699875" ] }, "execution_count": 27, "metadata": { "tags": [] }, "output_type": "execute_result" } ], "source": [ "# option 1\n", "qsmk_mean = qsmk.mean()\n", "qsmk_mean" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "Collapsed": "false", "colab": {}, "colab_type": "code", "id": "6KyEQU6M5xb1", "outputId": "241340ee-5265-4add-825e-336c55da44e2" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Optimization terminated successfully.\n", " Current function value: 0.570260\n", " Iterations 5\n" ] }, { "data": { "text/html": [ "\n", "\n", " \n", "\n", "\n", " \n", "\n", "
coef std err z P>|z| [0.025 0.975]
constant -1.0598 0.058 -18.335 0.000 -1.173 -0.947
" ], "text/plain": [ "" ] }, "execution_count": 28, "metadata": { "tags": [] }, "output_type": "execute_result" } ], "source": [ "# option 2\n", "lgt = sm.Logit(qsmk, nhefs.constant)\n", "res = lgt.fit()\n", "res.summary().tables[1]" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "Collapsed": "false", "colab": {}, "colab_type": "code", "id": "w3rHN59b5xb4" }, "outputs": [], "source": [ "lgt_pred = res.predict()" ] }, { "cell_type": "markdown", "metadata": { "Collapsed": "false", "colab_type": "text", "id": "wtVq54Qb5xb8" }, "source": [ "Check for equivalence" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "Collapsed": "false", "colab": {}, "colab_type": "code", "id": "tKkKUP-g5xb9", "outputId": "5b13d757-220c-41bf-98f8-ce1b8356b4e0" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "equivalent: True\n" ] } ], "source": [ "equivalent = np.all(np.isclose(lgt_pred, qsmk_mean))\n", "print('equivalent: {}'.format(equivalent))" ] }, { "cell_type": "markdown", "metadata": { "Collapsed": "false", "colab_type": "text", "id": "SQq-mxqX5xcD" }, "source": [ "### Program 12.3" ] }, { "cell_type": "markdown", "metadata": { "Collapsed": "false", "colab_type": "text", "id": "GvxxebIR5xcG" }, "source": [ "Create stabilized IP weights. Shortcut: modify the IP weights already calculated." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "Collapsed": "false", "colab": {}, "colab_type": "code", "id": "nesdlHrc5xcH" }, "outputs": [], "source": [ "s_weights = np.zeros(nhefs.shape[0])\n", "s_weights[qsmk] = qsmk.mean() * weights[qsmk] # `qsmk` was defined a few cells ago\n", "s_weights[~qsmk] = (1 - qsmk).mean() * weights[~qsmk]" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "Collapsed": "false", "colab": {}, "colab_type": "code", "id": "urqAaeDO5xcS", "outputId": "c89dde16-69a9-4833-d44b-aabb5cf91b02" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Stabilized weights\n", " min mean max\n", "------------------\n", "0.33 1.00 4.30\n" ] } ], "source": [ "print('Stabilized weights')\n", "print(' min mean max')\n", "print('------------------')\n", "print('{:>04.2f} {:>04.2f} {:>04.2f}'.format(\n", " s_weights.min(),\n", " s_weights.mean(),\n", " s_weights.max()\n", "))" ] }, { "cell_type": "markdown", "metadata": { "Collapsed": "false", "colab_type": "text", "id": "weZHsmvB5xcd" }, "source": [ "Refit the model from the last section, using the new weights" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "Collapsed": "false", "colab": {}, "colab_type": "code", "id": "Puz1UrKF5xcg", "outputId": "398d879f-1a3e-4af3-c150-b9ac79f0041b" }, "outputs": [ { "data": { "text/html": [ "\n", "\n", " \n", "\n", "\n", " \n", "\n", "\n", " \n", "\n", "
coef std err z P>|z| [0.025 0.975]
constant 1.7800 0.225 7.920 0.000 1.340 2.220
qsmk 3.4405 0.525 6.547 0.000 2.411 4.470
" ], "text/plain": [ "" ] }, "execution_count": 33, "metadata": { "tags": [] }, "output_type": "execute_result" } ], "source": [ "gee = sm.GEE(\n", " nhefs.wt82_71,\n", " nhefs[['constant', 'qsmk']],\n", " groups=nhefs.seqn,\n", " weights=s_weights\n", ")\n", "res = gee.fit()\n", "res.summary().tables[1]" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "Collapsed": "false", "colab": {}, "colab_type": "code", "id": "JhW0TcYh5xck", "outputId": "329116b8-f776-4e18-d2f0-f4c031eaeb63" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ " estimate 95% C.I.\n", "theta_1 3.44 (2.4, 4.5)\n" ] } ], "source": [ "est = res.params.qsmk\n", "conf_ints = res.conf_int(alpha=0.05, cols=None)\n", "lo, hi = conf_ints[0]['qsmk'], conf_ints[1]['qsmk']\n", "\n", "print(' estimate 95% C.I.')\n", "print('theta_1 {:>6.2f} ({:>0.1f}, {:>0.1f})'.format(est, lo, hi))" ] }, { "cell_type": "markdown", "metadata": { "Collapsed": "false", "colab_type": "text", "id": "sNF5CLEZ5xct" }, "source": [ "The estimate is the same as in the previous section" ] }, { "cell_type": "markdown", "metadata": { "Collapsed": "false", "colab_type": "text", "id": "Ybob4PS75xcx" }, "source": [ "We can check again for no association between sex and qsmk in the the pseudo-population" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "Collapsed": "false", "colab": {}, "colab_type": "code", "id": "GONEMTsI5xcy", "outputId": "7bebc1f2-972f-494f-f9ed-c6a8ea090a4a" }, "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", "
qsmk01
sex
0567.098228196.513582
1595.423986205.154456
\n", "
" ], "text/plain": [ "qsmk 0 1\n", "sex \n", "0 567.098228 196.513582\n", "1 595.423986 205.154456" ] }, "execution_count": 35, "metadata": { "tags": [] }, "output_type": "execute_result" } ], "source": [ "pd.crosstab(nhefs.sex, nhefs.qsmk, s_weights, aggfunc='sum')" ] }, { "cell_type": "markdown", "metadata": { "Collapsed": "false", "colab_type": "text", "id": "hBLyoarE5xc5" }, "source": [ "### Program 12.4" ] }, { "cell_type": "markdown", "metadata": { "Collapsed": "false", "colab_type": "text", "id": "kn6VvwGs5xc6" }, "source": [ "Subset the data to subjects that smoked 25 or fewer cigarettes per day at baseline. In this case, we can either obtain the subset from the original dataset, or we can obtain it from the reduced dataset that we've been using. I'll get it from the reduced subset, since it already contains dummy features we'll need." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "Collapsed": "false", "colab": {}, "colab_type": "code", "id": "aB0JqLhl5xc8", "outputId": "2a5ba14a-a593-4c16-83d3-f7b750693e4c" }, "outputs": [ { "data": { "text/plain": [ "(1162, 64)" ] }, "execution_count": 36, "metadata": { "tags": [] }, "output_type": "execute_result" } ], "source": [ "# from original dataset\n", "\n", "intensity25 = nhefs_all.loc[\n", " (nhefs_all.smokeintensity <= 25) & ~nhefs_all.wt82.isnull()\n", "]\n", "intensity25.shape" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "Collapsed": "false", "colab": {}, "colab_type": "code", "id": "nVPkmqab5xdE", "outputId": "f4c45987-5c6f-402e-d9fa-dffd6352c4cf" }, "outputs": [ { "data": { "text/plain": [ "(1162, 83)" ] }, "execution_count": 37, "metadata": { "tags": [] }, "output_type": "execute_result" } ], "source": [ "# from reduced dataset\n", "\n", "intensity25 = nhefs.loc[nhefs.smokeintensity <= 25]\n", "intensity25.shape" ] }, { "cell_type": "markdown", "metadata": { "Collapsed": "false", "colab_type": "text", "id": "CsoJz-eg5xdJ" }, "source": [ "Create the stabilized IP weights $SW^A = f(A) \\, / \\, f(A|L)$" ] }, { "cell_type": "markdown", "metadata": { "Collapsed": "false", "colab_type": "text", "id": "vYCXmGZ-5xdK" }, "source": [ "\"we assumed that the density f(A|L) was normal (Gaussian) with mean $\\mu = E[A|L]$ and variance $\\sigma^2$. We then used a linear regression model to estimate the mean $E[A|L]$ and variance of residuals $\\sigma^2$ for all combinations of values of L.\" pg 156\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "Collapsed": "false", "colab": {}, "colab_type": "code", "id": "SkiHge0J5xdM" }, "outputs": [], "source": [ "A = intensity25.smkintensity82_71\n", "X = intensity25[[\n", " 'constant', 'sex', 'race', 'edu_2', 'edu_3', 'edu_4', 'edu_5', \n", " 'exercise_1', 'exercise_2', 'active_1', 'active_2',\n", " 'age', 'age^2', 'wt71', 'wt71^2',\n", " 'smokeintensity', 'smokeintensity^2', 'smokeyrs', 'smokeyrs^2'\n", "]]" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "Collapsed": "false", "colab": {}, "colab_type": "code", "id": "Hkc4Sxja5xdS" }, "outputs": [], "source": [ "ols = sm.OLS(A, X)\n", "res = ols.fit()" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "Collapsed": "false", "colab": {}, "colab_type": "code", "id": "k0kdPSTO5xdZ" }, "outputs": [], "source": [ "A_pred = res.predict(X) # i.e., E[A|L]" ] }, { "cell_type": "markdown", "metadata": { "Collapsed": "false", "colab_type": "text", "id": "gYb7eUFy5xdf" }, "source": [ "The denominator is the distribution, $N(\\mu, \\sigma)$, evaluated at each point of $y = A$." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "Collapsed": "false", "colab": {}, "colab_type": "code", "id": "1ejr-rZp5xdg" }, "outputs": [], "source": [ "fAL = scipy.stats.norm.pdf(\n", " A, # A\n", " A_pred, # mu = E[A|L]\n", " np.sqrt(res.mse_resid) # sigma\n", ")" ] }, { "cell_type": "markdown", "metadata": { "Collapsed": "false", "colab_type": "text", "id": "xVgtSGtH5xdm" }, "source": [ "\"We also assumed that the density f(A) in the numerator was normal.\"" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "Collapsed": "false", "colab": {}, "colab_type": "code", "id": "4PimWR-X5xdo", "outputId": "bf4ab794-2e43-4970-ba9d-5512c716f542" }, "outputs": [ { "data": { "image/png": "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\n", "text/plain": [ "
" ] }, "metadata": { "needs_background": "light", "tags": [] }, "output_type": "display_data" } ], "source": [ "fig, ax = plt.subplots(figsize=(8, 6))\n", "\n", "A.hist(bins=30, ax=ax);" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "Collapsed": "false", "colab": {}, "colab_type": "code", "id": "HxX3tTUy5xds", "outputId": "ff96fd89-2f3b-4a55-e65f-f84128dcad6e" }, "outputs": [ { "data": { "text/plain": [ "(-2.057659208261618, 10.467830908151853)" ] }, "execution_count": 43, "metadata": { "tags": [] }, "output_type": "execute_result" } ], "source": [ "A.mean(), A.std()" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "Collapsed": "false", "colab": {}, "colab_type": "code", "id": "YomIJH0W5xdw" }, "outputs": [], "source": [ "fA = scipy.stats.norm.pdf(A, A.mean(), A.std())" ] }, { "cell_type": "markdown", "metadata": { "Collapsed": "false", "colab_type": "text", "id": "-1VHCB3y5xdy" }, "source": [ "Then the stabilized IP weights are" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "Collapsed": "false", "colab": {}, "colab_type": "code", "id": "PhhTqmii5xd1" }, "outputs": [], "source": [ "sw = fA / fAL" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "Collapsed": "false", "colab": {}, "colab_type": "code", "id": "u-rvdWri5xd4", "outputId": "8fda2d78-2ea1-4695-8029-ac86562dd5ab" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Stabilized weights\n", " min mean max\n", "------------------\n", "0.19 1.00 5.10\n" ] } ], "source": [ "print('Stabilized weights')\n", "print(' min mean max')\n", "print('------------------')\n", "print('{:>04.2f} {:>04.2f} {:>04.2f}'.format(\n", " sw.min(),\n", " sw.mean(),\n", " sw.max()\n", "))" ] }, { "cell_type": "markdown", "metadata": { "Collapsed": "false", "colab_type": "text", "id": "GPJoQBsF5xd7" }, "source": [ "Now fit the marginal structural model" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "Collapsed": "false", "colab": {}, "colab_type": "code", "id": "YEbqpvtN5xd8" }, "outputs": [], "source": [ "y = intensity25.wt82_71\n", "X = pd.DataFrame(OrderedDict((\n", " ('constant', np.ones(y.shape[0])),\n", " ('A', A),\n", " ('A^2', A**2)\n", ")))\n", "\n", "model = sm.GEE(\n", " y,\n", " X,\n", " groups=intensity25.seqn,\n", " weights=sw\n", ")\n", "res = model.fit()" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "Collapsed": "false", "colab": {}, "colab_type": "code", "id": "cSj00djn5xeC", "outputId": "9352f6d4-ba8c-44f4-c0eb-131f85c3c354" }, "outputs": [ { "data": { "text/html": [ "\n", "\n", " \n", "\n", "\n", " \n", "\n", "\n", " \n", "\n", "\n", " \n", "\n", "
coef std err z P>|z| [0.025 0.975]
constant 2.0045 0.295 6.792 0.000 1.426 2.583
A -0.1090 0.032 -3.456 0.001 -0.171 -0.047
A^2 0.0027 0.002 1.115 0.265 -0.002 0.007
" ], "text/plain": [ "" ] }, "execution_count": 48, "metadata": { "tags": [] }, "output_type": "execute_result" } ], "source": [ "res.summary().tables[1]" ] }, { "cell_type": "markdown", "metadata": { "Collapsed": "false", "colab_type": "text", "id": "T9A2qnV75xeH" }, "source": [ "To get the estimate and confidence interval for \"no change\", you can read off the values in the `constant` row above (because `A` and `A^2` will be zero).\n", "\n", "Getting Statmodels to calculate the estimate and confidence interval for when smoking increases by 20 cigarettes / day will take a couple extra steps. In Chapter 11, the regression result had a `get_prediction` method. The GEE result doesn't (yet?) have that _method_, so we'll use the hidden `get_prediction` _function_." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "Collapsed": "false", "colab": {}, "colab_type": "code", "id": "0ZGG4gfc5xeI" }, "outputs": [], "source": [ "from statsmodels.regression._prediction import get_prediction" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "Collapsed": "false", "colab": {}, "colab_type": "code", "id": "lCvR9WSD5xeL", "outputId": "a6131514-35c0-4a03-be4c-9a177e5a1e22" }, "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", "
meanmean_ci_lowermean_ci_upper
02.01.42.6
10.9-1.73.5
\n", "
" ], "text/plain": [ " mean mean_ci_lower mean_ci_upper\n", "0 2.0 1.4 2.6\n", "1 0.9 -1.7 3.5" ] }, "execution_count": 50, "metadata": { "tags": [] }, "output_type": "execute_result" } ], "source": [ "pred_inputs = [\n", " [1, 0, 0], # no change in smoking intensity\n", " [1, 20, 20**2], # plus 20 cigarettes / day\n", "]\n", "pred = get_prediction(res, exog=pred_inputs)\n", "summary = pred.summary_frame().round(1)\n", "summary[[\"mean\", \"mean_ci_lower\", \"mean_ci_upper\"]]" ] }, { "cell_type": "markdown", "metadata": { "Collapsed": "false", "colab_type": "text", "id": "-qUv6qHv5xeP" }, "source": [ "We can relabel the rows and columns to make this table a little nicer" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "Collapsed": "false", "colab": {}, "colab_type": "code", "id": "NpCfUhbg5xeQ", "outputId": "ced762be-b3e6-4bda-a2b9-195a1e9fee2b" }, "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", "
estimateCI lowerCI upper
no change2.01.42.6
+20 per day0.9-1.73.5
\n", "
" ], "text/plain": [ " estimate CI lower CI upper\n", "no change 2.0 1.4 2.6\n", "+20 per day 0.9 -1.7 3.5" ] }, "execution_count": 51, "metadata": { "tags": [] }, "output_type": "execute_result" } ], "source": [ "summary = summary[[\"mean\", \"mean_ci_lower\", \"mean_ci_upper\"]]\n", "summary.index = [\"no change\", \"+20 per day\"]\n", "summary.columns = [\"estimate\", \"CI lower\", \"CI upper\"]\n", "summary" ] }, { "cell_type": "markdown", "metadata": { "Collapsed": "false", "colab_type": "text", "id": "GN0m-e-J5xeT" }, "source": [ "Note: since the `get_predictions` function wasn't attached to the GEE regression result, it might not work correctly with other versions of the GEE model." ] }, { "cell_type": "markdown", "metadata": { "Collapsed": "false", "colab_type": "text", "id": "X7xhP1Zq5xeW" }, "source": [ "### Program 12.5" ] }, { "cell_type": "markdown", "metadata": { "Collapsed": "false", "colab_type": "text", "id": "EplddnEu5xeX" }, "source": [ "\"if interested in the causal effect of quitting smoking A (1: yes, 0: no) on the risk of death D (1: yes, 0: no) by 1982, one could consider a _marginal structural logistic model_\"" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "Collapsed": "false", "colab": {}, "colab_type": "code", "id": "rx-EgONO5xeY", "outputId": "e0e5e5af-4bc8-4bb3-f303-0f152ed0f68c" }, "outputs": [ { "data": { "text/html": [ "\n", "\n", " \n", "\n", "\n", " \n", "\n", "\n", " \n", "\n", "
coef std err z P>|z| [0.025 0.975]
constant -1.4905 0.079 -18.881 0.000 -1.645 -1.336
qsmk 0.0301 0.157 0.191 0.848 -0.278 0.338
" ], "text/plain": [ "" ] }, "execution_count": 52, "metadata": { "tags": [] }, "output_type": "execute_result" } ], "source": [ "model = sm.GEE(\n", " nhefs.death,\n", " nhefs[['constant', 'qsmk']],\n", " groups=nhefs.seqn,\n", " weights=s_weights,\n", " family=sm.families.Binomial()\n", ")\n", "res = model.fit()\n", "res.summary().tables[1]" ] }, { "cell_type": "markdown", "metadata": { "Collapsed": "false", "colab_type": "text", "id": "Os6FoWkv5xeb" }, "source": [ "Odd ratio is $\\exp(\\hat{\\theta}_1)$" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "Collapsed": "false", "colab": {}, "colab_type": "code", "id": "X0p6ex9V5xeb", "outputId": "e7bcf040-3f38-4a23-9268-abc3223d52a5" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ " estimate 95% C.I.\n", "odds ratio 1.03 (0.8, 1.4)\n" ] } ], "source": [ "est = np.exp(res.params.qsmk)\n", "conf_ints = res.conf_int(alpha=0.05, cols=None)\n", "lo = np.exp(conf_ints[0]['qsmk'])\n", "hi = np.exp(conf_ints[1]['qsmk'])\n", "\n", "print(' estimate 95% C.I.')\n", "print('odds ratio {:>6.2f} ({:>0.1f}, {:>0.1f})'.format(est, lo, hi))" ] }, { "cell_type": "markdown", "metadata": { "Collapsed": "false", "colab_type": "text", "id": "0yompze_5xef" }, "source": [ "### Program 12.6" ] }, { "cell_type": "markdown", "metadata": { "Collapsed": "false", "colab_type": "text", "id": "1OMDoNfi5xeg" }, "source": [ " Create the numerator of the IP weights. Reuse the basic `weights` for the denominator." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "Collapsed": "false", "colab": {}, "colab_type": "code", "id": "8ecQsdoq5xeh", "outputId": "1a1b0611-62df-4197-f2a1-2e6632f8efbd" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Optimization terminated successfully.\n", " Current function value: 0.567819\n", " Iterations 5\n" ] } ], "source": [ "numer = logit_ip_f(nhefs.qsmk, nhefs[['constant', 'sex']])" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "Collapsed": "false", "colab": {}, "colab_type": "code", "id": "4B4afU4i5xej" }, "outputs": [], "source": [ "sw_AV = numer * weights" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "Collapsed": "false", "colab": {}, "colab_type": "code", "id": "GAP0se4f5xem", "outputId": "05d35726-5494-4603-819b-bb8c6b814c55" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Stabilized weights\n", " min mean max\n", "------------------\n", "0.29 1.00 3.80\n" ] } ], "source": [ "print('Stabilized weights')\n", "print(' min mean max')\n", "print('------------------')\n", "print('{:>04.2f} {:>04.2f} {:>04.2f}'.format(\n", " sw_AV.min(),\n", " sw_AV.mean(),\n", " sw_AV.max()\n", "))" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "Collapsed": "false", "colab": {}, "colab_type": "code", "id": "2HOn9xu65xeq", "outputId": "e60ad35f-cd75-40b1-f735-5000cc5e582e" }, "outputs": [ { "data": { "text/plain": [ "(1566, 83)" ] }, "execution_count": 57, "metadata": { "tags": [] }, "output_type": "execute_result" } ], "source": [ "nhefs.shape" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "Collapsed": "false", "colab": {}, "colab_type": "code", "id": "OoonBszO5xet", "outputId": "45be7bdb-4f3a-4667-96c3-6ce4c9b9802b" }, "outputs": [ { "data": { "text/html": [ "\n", "\n", " \n", "\n", "\n", " \n", "\n", "\n", " \n", "\n", "\n", " \n", "\n", "\n", " \n", "\n", "
coef std err z P>|z| [0.025 0.975]
constant 1.7844 0.310 5.752 0.000 1.176 2.393
qsmk 3.5220 0.658 5.353 0.000 2.232 4.811
sex -0.0087 0.449 -0.019 0.985 -0.890 0.872
qsmk_and_female -0.1595 1.047 -0.152 0.879 -2.212 1.893
" ], "text/plain": [ "" ] }, "execution_count": 58, "metadata": { "tags": [] }, "output_type": "execute_result" } ], "source": [ "nhefs['qsmk_and_female'] = nhefs.qsmk * nhefs.sex\n", "\n", "model = sm.WLS(\n", " nhefs.wt82_71,\n", " nhefs[['constant', 'qsmk', 'sex', 'qsmk_and_female']],\n", " weights=sw_AV\n", ")\n", "res = model.fit(cov_type='cluster', cov_kwds={'groups': nhefs.seqn})\n", "res.summary().tables[1]" ] }, { "cell_type": "markdown", "metadata": { "Collapsed": "false", "colab_type": "text", "id": "SXgrOVwk5xew" }, "source": [ "### Program 12.7" ] }, { "cell_type": "markdown", "metadata": { "Collapsed": "false", "colab_type": "text", "id": "k0W7xmhC5xew" }, "source": [ "We're going back to the original dataset" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "Collapsed": "false", "colab": {}, "colab_type": "code", "id": "okk5Yj4F5xex", "outputId": "7c498741-23f6-4be2-d417-244907e8b838" }, "outputs": [ { "data": { "text/plain": [ "(1629, 64)" ] }, "execution_count": 59, "metadata": { "tags": [] }, "output_type": "execute_result" } ], "source": [ "nhefs_all.shape" ] }, { "cell_type": "markdown", "metadata": { "Collapsed": "false", "colab_type": "text", "id": "dtA_wcuV5xez" }, "source": [ "We'll add features that were added to the reduced dataset that we've been using" ] }, { "cell_type": "markdown", "metadata": { "Collapsed": "false", "colab_type": "text", "id": "z_b3LGhB5xez" }, "source": [ "Add constant feature" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "Collapsed": "false", "colab": {}, "colab_type": "code", "id": "AG64cc9c5xe4" }, "outputs": [], "source": [ "nhefs_all['constant'] = 1" ] }, { "cell_type": "markdown", "metadata": { "Collapsed": "false", "colab_type": "text", "id": "3maWP6Ff5xe_" }, "source": [ "Add dummy features" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "Collapsed": "false", "colab": {}, "colab_type": "code", "id": "UcZAADB25xfA" }, "outputs": [], "source": [ "edu_dummies = pd.get_dummies(nhefs_all.education, prefix='edu')\n", "exercise_dummies = pd.get_dummies(nhefs_all.exercise, prefix='exercise')\n", "active_dummies = pd.get_dummies(nhefs_all.active, prefix='active')\n", "\n", "nhefs_all = pd.concat(\n", " [nhefs_all, edu_dummies, exercise_dummies, active_dummies],\n", " axis=1\n", ")" ] }, { "cell_type": "markdown", "metadata": { "Collapsed": "false", "colab_type": "text", "id": "SrToJKmO5xfD" }, "source": [ "Add squared features" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "Collapsed": "false", "colab": {}, "colab_type": "code", "id": "pbH7r8VZ5xfD" }, "outputs": [], "source": [ "for col in ['age', 'wt71', 'smokeintensity', 'smokeyrs']:\n", " nhefs_all['{}^2'.format(col)] = nhefs_all[col] * nhefs_all[col]" ] }, { "cell_type": "markdown", "metadata": { "Collapsed": "false", "colab_type": "text", "id": "i9skhn4h5xfF" }, "source": [ "We'll also add a feature to track censored individuals" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "Collapsed": "false", "colab": {}, "colab_type": "code", "id": "Se6bTv8b5xfG" }, "outputs": [], "source": [ "nhefs_all['censored'] = nhefs_all.wt82.isnull().astype('int')" ] }, { "cell_type": "markdown", "metadata": { "Collapsed": "false", "colab_type": "text", "id": "uZ-MSFep5xfH" }, "source": [ "Create the IP weights for treatment" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "Collapsed": "false", "colab": {}, "colab_type": "code", "id": "F-5WskL95xfI" }, "outputs": [], "source": [ "X_ip = nhefs_all[[\n", " 'constant', 'sex', 'race', 'edu_2', 'edu_3', 'edu_4', 'edu_5', \n", " 'exercise_1', 'exercise_2', 'active_1', 'active_2',\n", " 'age', 'age^2', 'wt71', 'wt71^2',\n", " 'smokeintensity', 'smokeintensity^2', 'smokeyrs', 'smokeyrs^2'\n", "]]" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "Collapsed": "false", "colab": {}, "colab_type": "code", "id": "2hanuMb45xfJ", "outputId": "ae5093ce-9c83-48c6-c93e-882807c7cb2f", "scrolled": true }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Optimization terminated successfully.\n", " Current function value: 0.542264\n", " Iterations 6\n" ] } ], "source": [ "ip_denom = logit_ip_f(nhefs_all.qsmk, X_ip)" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "Collapsed": "false", "colab": {}, "colab_type": "code", "id": "KHYrzGOa5xfL", "outputId": "d4740bfc-2718-4941-abcc-6ecd9fc967b5" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Optimization terminated successfully.\n", " Current function value: 0.575901\n", " Iterations 5\n" ] } ], "source": [ "ip_numer = logit_ip_f(nhefs_all.qsmk, nhefs_all.constant)" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "Collapsed": "false", "colab": {}, "colab_type": "code", "id": "LFDS2Ji-5xfM" }, "outputs": [], "source": [ "sw_A = ip_numer / ip_denom" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "Collapsed": "false", "colab": {}, "colab_type": "code", "id": "0D2Ke2Jl5xfO", "outputId": "747db8e1-6255-4477-ab1b-7ab4d82bfb7b" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Stabilized weights\n", " min mean max\n", "------------------\n", "0.33 1.00 4.21\n" ] } ], "source": [ "print('Stabilized weights')\n", "print(' min mean max')\n", "print('------------------')\n", "print('{:>04.2f} {:>04.2f} {:>04.2f}'.format(\n", " sw_A.min(),\n", " sw_A.mean(),\n", " sw_A.max()\n", "))" ] }, { "cell_type": "markdown", "metadata": { "Collapsed": "false", "colab_type": "text", "id": "9F-eAu7F5xfQ" }, "source": [ "Now the IP weights for censoring" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "Collapsed": "false", "colab": {}, "colab_type": "code", "id": "x-RYy7xJ5xfQ" }, "outputs": [], "source": [ "# same as previous, but with 'qsmk' added\n", "\n", "X_ip = nhefs_all[[\n", " 'constant', 'sex', 'race', 'edu_2', 'edu_3', 'edu_4', 'edu_5', \n", " 'exercise_1', 'exercise_2', 'active_1', 'active_2',\n", " 'age', 'age^2', 'wt71', 'wt71^2',\n", " 'smokeintensity', 'smokeintensity^2', 'smokeyrs', 'smokeyrs^2',\n", " 'qsmk'\n", "]]" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "Collapsed": "false", "colab": {}, "colab_type": "code", "id": "7UcdQP6-5xfT", "outputId": "bab9068a-b066-4f57-e302-cdf84bb9af2d" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Optimization terminated successfully.\n", " Current function value: 0.142836\n", " Iterations 8\n" ] } ], "source": [ "ip_denom = logit_ip_f(nhefs_all.censored, X_ip)" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "Collapsed": "false", "colab": {}, "colab_type": "code", "id": "8BGi1lpi5xfb", "outputId": "13adef71-3a02-4dd3-c612-eee5280dce14" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Optimization terminated successfully.\n", " Current function value: 0.161989\n", " Iterations 7\n" ] } ], "source": [ "ip_numer = logit_ip_f(\n", " nhefs_all.censored,\n", " nhefs_all[['constant', 'qsmk']]\n", ")" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "Collapsed": "false", "colab": {}, "colab_type": "code", "id": "Ep-9U1sK5xff" }, "outputs": [], "source": [ "sw_C = ip_numer / ip_denom\n", "sw_C[nhefs_all.censored == 1] = 1" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "Collapsed": "false", "colab": {}, "colab_type": "code", "id": "Yoq1Epg65xfk", "outputId": "e1863baa-1b2e-46c4-b291-63d26cc88331" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Stabilized weights\n", " min mean max\n", "------------------\n", "0.94 1.00 1.72\n" ] } ], "source": [ "print('Stabilized weights')\n", "print(' min mean max')\n", "print('------------------')\n", "print('{:>04.2f} {:>04.2f} {:>04.2f}'.format(\n", " sw_C.min(),\n", " sw_C.mean(),\n", " sw_C.max()\n", "))" ] }, { "cell_type": "markdown", "metadata": { "Collapsed": "false", "colab_type": "text", "id": "nsSj6SHV5xfr" }, "source": [ "Now create the combined IP weights" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "Collapsed": "false", "colab": {}, "colab_type": "code", "id": "T1pVFskw5xfs" }, "outputs": [], "source": [ "sw_AC = sw_A * sw_C" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "Collapsed": "false", "colab": {}, "colab_type": "code", "id": "fECz2aYA5xft", "outputId": "dd7799ac-b885-4812-ec42-ffb3b25b4cb6" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Stabilized weights\n", " min mean max\n", "------------------\n", "0.35 1.00 4.09\n" ] } ], "source": [ "print('Stabilized weights')\n", "print(' min mean max')\n", "print('------------------')\n", "print('{:>04.2f} {:>04.2f} {:>04.2f}'.format(\n", " sw_AC.min(),\n", " sw_AC.mean(),\n", " sw_AC.max()\n", "))" ] }, { "cell_type": "markdown", "metadata": { "Collapsed": "false", "colab_type": "text", "id": "AjMat9Ut5xfv" }, "source": [ "Now model weight gain using the combined IP weights" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "Collapsed": "false", "colab": {}, "colab_type": "code", "id": "0ze9Z_rf5xfv" }, "outputs": [], "source": [ "wls = sm.WLS(\n", " nhefs.wt82_71,\n", " nhefs[['constant', 'qsmk']],\n", " weights=sw_AC[nhefs_all.censored == 0]\n", ") \n", "res = wls.fit(cov_type='cluster', cov_kwds={'groups': nhefs.seqn})" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "Collapsed": "false", "colab": {}, "colab_type": "code", "id": "NNVvYz6l5xfx", "outputId": "9e540919-8f20-4db7-b5a9-3addfd8edb27", "scrolled": true }, "outputs": [ { "data": { "text/html": [ "\n", "\n", " \n", "\n", "\n", " \n", "\n", "\n", " \n", "\n", "
coef std err z P>|z| [0.025 0.975]
constant 1.6620 0.233 7.136 0.000 1.206 2.118
qsmk 3.4965 0.526 6.648 0.000 2.466 4.527
" ], "text/plain": [ "" ] }, "execution_count": 77, "metadata": { "tags": [] }, "output_type": "execute_result" } ], "source": [ "res.summary().tables[1]" ] }, { "cell_type": "markdown", "metadata": { "Collapsed": "true", "colab_type": "text", "id": "_fOBcWPg5xfz" }, "source": [ "## 一个类组织本章代码\n", "\n", "我们把本章主要代码工作整理成类。" ] }, { "cell_type": "code", "execution_count": 8, "metadata": { "Collapsed": "false", "colab": {}, "colab_type": "code", "id": "HPGd4e_b5xf0" }, "outputs": [], "source": [ "%matplotlib inline\n", "\n", "import warnings\n", "warnings.filterwarnings('ignore')\n", "\n", "from collections import OrderedDict\n", "import numpy as np\n", "import pandas as pd\n", "import statsmodels.api as sm\n", "import scipy.stats\n", "import matplotlib.pyplot as plt" ] }, { "cell_type": "code", "execution_count": 9, "metadata": { "Collapsed": "false", "code_folding": [ 0, 1, 6, 28, 49, 65, 83 ], "colab": {}, "colab_type": "code", "id": "ZpHVrt6D5xf3", "outputId": "b36c06cb-b4b0-4a51-a213-12ec58bb9573" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "WARNING *** OLE2 inconsistency: SSCS size is 0 but SSAT size is non-zero\n", "Optimization terminated successfully.\n", " Current function value: 0.567819\n", " Iterations 5\n", "Confounders for IP Weight is:\n", " ['constant', 'sex', 'race', 'age', 'age^2', 'edu_2', 'edu_3', 'edu_4', 'edu_5', 'smokeintensity', 'smokeintensity^2', 'smokeyrs', 'smokeyrs^2', 'exercise_1', 'exercise_2', 'active_1', 'active_2', 'wt71', 'wt71^2']\n", "\n", "Optimization terminated successfully.\n", " Current function value: 0.535408\n", " Iterations 6\n", "Marignal Structural Models 的有关变量:\n", " ['constant', 'qsmk', 'sex', 'qsmk_and_female']\n" ] }, { "data": { "text/html": [ "\n", "\n", " \n", "\n", "\n", " \n", "\n", "\n", " \n", "\n", "\n", " \n", "\n", "\n", " \n", "\n", "
coef std err z P>|z| [0.025 0.975]
constant 1.7844 0.310 5.752 0.000 1.176 2.393
qsmk 3.5220 0.658 5.353 0.000 2.232 4.811
sex -0.0087 0.449 -0.019 0.985 -0.890 0.872
qsmk_and_female -0.1595 1.047 -0.152 0.879 -2.212 1.893
" ], "text/plain": [ "" ] }, "execution_count": 9, "metadata": {}, "output_type": "execute_result" } ], "source": [ "class IPW(object):\n", " def __init__(self):\n", " self.help = \"This is a demonstration for IP Weighting!\"\n", " self.data = self.get_data()\n", " self.ipw_cols = None\n", " \n", " def get_data(self):\n", " nhefs_all = pd.read_excel('NHEFS.xls')\n", " restriction_cols = ['sex', 'age', 'race', 'wt82', 'ht', \n", " 'school', 'alcoholpy', 'smokeintensity']\n", " missing = nhefs_all[restriction_cols].isnull().any(axis=1)\n", " nhefs = nhefs_all.loc[~missing]\n", " nhefs['constant'] = 1\n", " nhefs['university'] = (nhefs.education == 5).astype('int')\n", " nhefs['inactive'] = (nhefs.active == 2).astype('int')\n", " nhefs['no_exercise'] = (nhefs.exercise == 2).astype('int') \n", " for col in ['age', 'wt71', 'smokeintensity', 'smokeyrs']:\n", " nhefs['{}^2'.format(col)] = nhefs[col] * nhefs[col] \n", " edu_dummies = pd.get_dummies(nhefs.education, prefix='edu')\n", " exercise_dummies = pd.get_dummies(nhefs.exercise, prefix='exercise')\n", " active_dummies = pd.get_dummies(nhefs.active, prefix='active')\n", "\n", " nhefs = pd.concat(\n", " [nhefs, edu_dummies, exercise_dummies, active_dummies],\n", " axis=1\n", " )\n", " return nhefs\n", "\n", " def _logit_ip_f(self, y, X):\n", " model = sm.Logit(y, X)\n", " res = model.fit()\n", " weights = np.zeros(X.shape[0])\n", " weights[y == 1] = res.predict(X.loc[y == 1])\n", " weights[y == 0] = (1 - res.predict(X.loc[y == 0]))\n", " return weights\n", " \n", " def treatment_probs(self, cols=None):\n", " if cols is None:\n", " cols = ['constant', 'sex', 'race', 'age', 'age^2', 'edu_2', 'edu_3', 'edu_4', 'edu_5',\n", " 'smokeintensity', 'smokeintensity^2', 'smokeyrs', 'smokeyrs^2', \n", " 'exercise_1', 'exercise_2', 'active_1', 'active_2', 'wt71', 'wt71^2']\n", " self.ipw_cols = cols\n", " print('Confounders for IP Weight is:\\n', cols)\n", " print()\n", " \n", " X_ip = self.data[cols] \n", " \n", " return self._logit_ip_f(self.data.qsmk, X_ip) \n", " \n", " def ipw(self):\n", " nhefs = self.data\n", " denoms = self.treatment_probs(self.ipw_cols)\n", " weights = 1 / denoms\n", " assert(weights.shape[0] == self.data.shape[0])\n", " print('Min and Max of weights:', weights.min(), weights.max())\n", " \n", " gee = sm.GEE(\n", " nhefs.wt82_71,\n", " nhefs[['constant', 'qsmk']],\n", " groups=nhefs.seqn,\n", " weights=weights\n", " )\n", " res = gee.fit()\n", " return res.summary().tables[1]\n", " \n", " def stabled_ipw(self):\n", " nhefs = self.data\n", " qsmk = (nhefs.qsmk == 1)\n", " denoms = self.treatment_probs(self.ipw_cols)\n", " weights = 1 / denoms\n", " s_weights = np.zeros(nhefs.shape[0])\n", " s_weights[qsmk] = qsmk.mean() * weights[qsmk] # `qsmk` was defined a few cells ago\n", " s_weights[~qsmk] = (1 - qsmk).mean() * weights[~qsmk]\n", " print(qsmk.mean())\n", " gee = sm.GEE(\n", " nhefs.wt82_71,\n", " nhefs[['constant', 'qsmk']],\n", " groups=nhefs.seqn,\n", " weights=s_weights\n", " )\n", " res = gee.fit()\n", " return res.summary().tables[1]\n", "\n", " def marginal_structural_models(self):\n", " nhefs = self.data\n", " numer = self._logit_ip_f(nhefs.qsmk, nhefs[['constant', 'sex']])\n", " weights = 1 / self.treatment_probs()\n", " sw_AV = numer * weights\n", " nhefs['qsmk_and_female'] = nhefs.qsmk * nhefs.sex\n", " model = sm.WLS(\n", " nhefs.wt82_71,\n", " nhefs[['constant', 'qsmk', 'sex', 'qsmk_and_female']],\n", " weights=sw_AV\n", " )\n", " res = model.fit(cov_type='cluster', cov_kwds={'groups': nhefs.seqn})\n", " print('Marignal Structural Models 的有关变量:\\n', ['constant', 'qsmk', 'sex', 'qsmk_and_female'] )\n", " return res.summary().tables[1]\n", "\n", "g = IPW()\n", "# g.data.shape\n", "# g.ipw_cols = ['constant', 'sex', 'race', 'age']\n", "# g.ipw()\n", "# g.stabled_ipw()\n", "g.marginal_structural_models()" ] }, { "cell_type": "markdown", "metadata": { "Collapsed": "false", "colab": {}, "colab_type": "code", "id": "yzpPpKRv5xf5" }, "source": [ "Table of Contents\n", "\n", "- IPW via modeling\n", "- Stablized IPW\n", "- Marginal structural models\n", "- Effect modification and marginal structural models\n", "- Censoring and missing data" ] }, { "cell_type": "code", "execution_count": 32, "metadata": { "Collapsed": "false" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "WARNING *** OLE2 inconsistency: SSCS size is 0 but SSAT size is non-zero\n" ] }, { "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", "
qsmkwt82_71
00-10.093960
102.604970
209.414486
304.990117
404.989251
\n", "
" ], "text/plain": [ " qsmk wt82_71\n", "0 0 -10.093960\n", "1 0 2.604970\n", "2 0 9.414486\n", "3 0 4.990117\n", "4 0 4.989251" ] }, "execution_count": 32, "metadata": {}, "output_type": "execute_result" } ], "source": [ "g = IPW()\n", "nhefs = g.data\n", "g.data[['qsmk', 'wt82_71']].head()" ] }, { "cell_type": "markdown", "metadata": { "Collapsed": "false" }, "source": [ "## 因果效应估计\n", "\n", "这里我们重新组织和整理本章的内容,a mini version of this chapter。四种的方法估计因果效应:\n", "\n", "- 直接计算均值的差异: 4.525079 - 1.98449 $\\approx$ 2.52\n", "- 一元线性模型 2.54 - 1.98 = 0.56\n", "- IPW 方法 3.44 - 1.78 = 1.66\n", "- Stablized IPW 3.44 - 1.78" ] }, { "cell_type": "code", "execution_count": 30, "metadata": { "Collapsed": "false" }, "outputs": [ { "data": { "text/plain": [ "qsmk\n", "0 1.984498\n", "1 4.525079\n", "Name: wt82_71, dtype: float64" ] }, "execution_count": 30, "metadata": {}, "output_type": "execute_result" } ], "source": [ "nhefs.groupby('qsmk')[\"wt82_71\"].mean()\n", "# nhefs.groupby('qsmk')[\"wt82_71\"].agg([\"mean\", \"median\"])" ] }, { "cell_type": "code", "execution_count": 10, "metadata": { "Collapsed": "false" }, "outputs": [ { "data": { "text/html": [ "\n", "\n", " \n", "\n", "\n", " \n", "\n", "\n", " \n", "\n", "
coef std err t P>|t| [0.025 0.975]
constant 1.9845 0.229 8.672 0.000 1.536 2.433
qsmk 2.5406 0.451 5.632 0.000 1.656 3.425
" ], "text/plain": [ "" ] }, "execution_count": 10, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# 用线性回顾估计因果效应的\n", "ols = sm.OLS(nhefs.wt82_71, nhefs[['constant', 'qsmk']])\n", "res = ols.fit()\n", "res.summary().tables[1]" ] }, { "cell_type": "code", "execution_count": 33, "metadata": { "Collapsed": "false" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Confounders for IP Weight is:\n", " ['constant', 'sex', 'race', 'age', 'age^2', 'edu_2', 'edu_3', 'edu_4', 'edu_5', 'smokeintensity', 'smokeintensity^2', 'smokeyrs', 'smokeyrs^2', 'exercise_1', 'exercise_2', 'active_1', 'active_2', 'wt71', 'wt71^2']\n", "\n", "Optimization terminated successfully.\n", " Current function value: 0.535408\n", " Iterations 6\n", "Min and Max of weights: 1.0537416280320455 16.700094350727504\n" ] }, { "data": { "text/html": [ "\n", "\n", " \n", "\n", "\n", " \n", "\n", "\n", " \n", "\n", "
coef std err z P>|z| [0.025 0.975]
constant 1.7800 0.225 7.920 0.000 1.340 2.220
qsmk 3.4405 0.525 6.547 0.000 2.411 4.470
" ], "text/plain": [ "" ] }, "execution_count": 33, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# IP Weight 方法\n", "g.ipw()" ] }, { "cell_type": "code", "execution_count": 34, "metadata": { "Collapsed": "false" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Confounders for IP Weight is:\n", " ['constant', 'sex', 'race', 'age', 'age^2', 'edu_2', 'edu_3', 'edu_4', 'edu_5', 'smokeintensity', 'smokeintensity^2', 'smokeyrs', 'smokeyrs^2', 'exercise_1', 'exercise_2', 'active_1', 'active_2', 'wt71', 'wt71^2']\n", "\n", "Optimization terminated successfully.\n", " Current function value: 0.535408\n", " Iterations 6\n", "0.25734355044699875\n" ] }, { "data": { "text/html": [ "\n", "\n", " \n", "\n", "\n", " \n", "\n", "\n", " \n", "\n", "
coef std err z P>|z| [0.025 0.975]
constant 1.7800 0.225 7.920 0.000 1.340 2.220
qsmk 3.4405 0.525 6.547 0.000 2.411 4.470
" ], "text/plain": [ "" ] }, "execution_count": 34, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Stablized IPW\n", "g.stabled_ipw()" ] }, { "cell_type": "code", "execution_count": 35, "metadata": { "Collapsed": "false" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Optimization terminated successfully.\n", " Current function value: 0.567819\n", " Iterations 5\n", "Confounders for IP Weight is:\n", " ['constant', 'sex', 'race', 'age', 'age^2', 'edu_2', 'edu_3', 'edu_4', 'edu_5', 'smokeintensity', 'smokeintensity^2', 'smokeyrs', 'smokeyrs^2', 'exercise_1', 'exercise_2', 'active_1', 'active_2', 'wt71', 'wt71^2']\n", "\n", "Optimization terminated successfully.\n", " Current function value: 0.535408\n", " Iterations 6\n", "Marignal Structural Models 的有关变量:\n", " ['constant', 'qsmk', 'sex', 'qsmk_and_female']\n" ] }, { "data": { "text/html": [ "\n", "\n", " \n", "\n", "\n", " \n", "\n", "\n", " \n", "\n", "\n", " \n", "\n", "\n", " \n", "\n", "
coef std err z P>|z| [0.025 0.975]
constant 1.7844 0.310 5.752 0.000 1.176 2.393
qsmk 3.5220 0.658 5.353 0.000 2.232 4.811
sex -0.0087 0.449 -0.019 0.985 -0.890 0.872
qsmk_and_female -0.1595 1.047 -0.152 0.879 -2.212 1.893
" ], "text/plain": [ "" ] }, "execution_count": 35, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# marginal_structural_models\n", "g.marginal_structural_models()" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "Collapsed": "false" }, "outputs": [], "source": [] } ], "metadata": { "anaconda-cloud": {}, "colab": { "name": "chapter12-IPW.ipynb", "provenance": [], "toc_visible": true }, "kernelspec": { "display_name": "Python 3", "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.4" }, "toc": { "base_numbering": 1, "nav_menu": {}, "number_sections": false, "sideBar": true, "skip_h1_title": false, "title_cell": "Table of Contents", "title_sidebar": "Contents", "toc_cell": false, "toc_position": {}, "toc_section_display": true, "toc_window_display": true } }, "nbformat": 4, "nbformat_minor": 4 }