【python因果推断库14】饮酒年龄 - 贝叶斯分析

发布于:2024-09-18 ⋅ 阅读:(118) ⋅ 点赞:(0)

目录

饮酒年龄 - 贝叶斯分析

主效应模型

交互模型

将连续变量以治疗阈值为中心


饮酒年龄 - 贝叶斯分析

这个例子使用了回归断点设计来探讨最低合法饮酒年龄(在美国为21岁)对全因死亡率的因果效应。数据集来自carpenter2009effect 的一项研究。

import arviz as az
import matplotlib.pyplot as plt

import causalpy as cp
%load_ext autoreload
%autoreload 2
%config InlineBackend.figure_format = 'retina'
seed = 42
Load and process data.

df = (
    cp.load_data("drinking")
    .rename(columns={"agecell": "age"})
    .assign(treated=lambda df_: df_.age > 21)
)

主效应模型

首先,我们将考察一个简单的“主效应”模型。在这里,对于给定年龄 a(以月为单位),预期死亡率(以每千人每年的死亡数为单位)通过截距项\beta_0、处理效应 \beta_1 和年龄效应 \beta_2 来建模。

\mu(a)=\beta_0+\beta_1t(a)+\beta_2a

其中 t(a) 描述了是否已经施加了“处理”。在这个例子中,它仅仅描述了给定年龄 a 是否超过了最低合法饮酒年龄 21 岁:

t(a)=\left\{\begin{matrix}1&\text{if }a\geq21\\0&\text{if }a<21\end{matrix}\right.

为了明确,\beta_2a 描述了预期死亡率随年龄变化的线性趋势。系数 \beta_0 是这一线性趋势在 (a = 0) 时的截距。这剩下 \beta_1t(a),我们可以理解为在年龄阈值周围的线性趋势的不连续性。

 PyMC 采样器的 `random_seed` 关键字参数不是必需的。我们在这里使用它是为了使结果可复现。

result = cp.pymc_experiments.RegressionDiscontinuity(
    df,
    formula="all ~ 1 + age + treated",
    running_variable_name="age",
    model=cp.pymc_models.LinearRegression(
        sample_kwargs={"target_accept": 0.95, "random_seed": seed}
    ),
    treatment_threshold=21,
)

fig, ax = result.plot()

result.summary()
============================Regression Discontinuity============================
Formula: all ~ 1 + age + treated
Running variable: age
Threshold on running variable: 21

Results:
Discontinuity at threshold = 7
Model coefficients:
  Intercept      	106, 94% HDI [83, 128]
  treated[T.True]	7, 94% HDI [4.4, 9.5]
  age            	-0.66, 94% HDI [-1.8, 0.51]
  sigma          	2.4, 94% HDI [2, 2.9]

在这个主效应模型中,因果效应的大小等于我们对 \beta_1 的后验估计。让我们绘制参数估计(左侧)并放大处理主效应的后验分布(右侧)。

fig, ax = plt.subplots(1, 2, figsize=(10, 3))

az.plot_forest(result.idata.posterior, var_names="beta", ax=ax[0])
az.plot_posterior(
    result.idata.posterior.beta.sel(coeffs="treated[T.True]"),
    round_to=3,
    ax=ax[1],
)

ax[1].set(title="treated[T.True]");

我们可以看到这几乎完全匹配了第一个结果图中的“阈值处的不连续性”图。

它并不是完全相同,因为我们实际上是手动计算阈值处的不连续性。原因在于,在最简单的模型之外,阈值处的不连续性并不简单地等于这个参数。为了理解这一点,让我们来看一个稍微复杂一点的模型,其中我们加入了一个交互项。

交互模型

我们通过改变公式为 `all ~ 1 + age + treated + age:treated` 来添加一个交互项。这样就改变了统计模型为:

\mu(a)=\beta_0+\beta_1t(a)+\beta_2a+\beta_3t(a)\cdot a

这个模型现在更加复杂,因为它可以根据数据来允许在21岁之前与之后的死亡率趋势发生变化。如果还不清楚的话,从下一个结果图中我们会看到阈值处的不连续性不再等于 \beta_1 参数。让我们运行这个模型来看看结果。

result2 = cp.pymc_experiments.RegressionDiscontinuity(
    df,
    formula="all ~ 1 + age + treated + age:treated",
    running_variable_name="age",
    model=cp.pymc_models.LinearRegression(sample_kwargs={"random_seed": seed}),
    treatment_threshold=21,
)

fig, ax = result2.plot()

我们现在可以看到,通过添加交互项,参数估计发生了很大的变化,阈值处的估计不连续性不再简单地由 \beta_1 参数给出。为了确认这一点,我们可以检查 \beta_1 的估计值(这对应于 treated[T.True] 系数)。

az.plot_forest(result2.idata.posterior, var_names="beta", figsize=(10, 3));

我们可以看到这个估计值现在与所需的“阈值处的不连续性”值相差很大。正因为如此,CausalPy 通过计算治疗阈值稍上方与稍下方的预测结果值之差,手动计算“阈值处的不连续性”。

将连续变量以治疗阈值为中心

另一种处理方法是将连续变量以阈值为中心,使得阈值(最低合法饮酒年龄)现在位于零点。这也使得参数更加易于解释。

df["age"] = df["age"] - 21
result3 = cp.pymc_experiments.RegressionDiscontinuity(
    df,
    formula="all ~ 1 + age + treated + age:treated",
    running_variable_name="age",
    model=cp.pymc_models.LinearRegression(sample_kwargs={"random_seed": seed}),
    treatment_threshold=0,
)

fig, ax = result3.plot()

fig, ax = plt.subplots(1, 2, figsize=(10, 3))

az.plot_forest(result3.idata.posterior, var_names="beta", ax=ax[0])
az.plot_posterior(
    result3.idata.posterior.beta.sel(coeffs="treated[T.True]"),
    round_to=3,
    ax=ax[1],
)

ax[1].set(title="treated[T.True]");


网站公告

今日签到

点亮在社区的每一天
去签到