【Python实战因果推断】42_合成控制2

目录

Matrix Representation

Synthetic Control as Horizontal Regression


Matrix Representation

在上文中,我向大家展示了一个用矩阵表示面板数据的图像,其中一个维度是时间段,另一个维度表示单位。合成控制明确使用了该矩阵,因此值得复习一下。假设矩阵的行是时间段,列是城市(单位)。您可以用四个区块来表示干预分配:

W=\begin{bmatrix}0_{pre,co}&0_{pre,tr}\\0_{post,co}&1_{post,tr}\end{bmatrix}

矩阵中的第一个区块(左上角)对应的是干预期之前的对照单位;第二个区块(右上角)对应的是干预期之前的被干预单位;第三个区块(左下角)包含干预期之后的对照单位;第四个区块(右下角)是干预期之后的被干预单位。除了治疗期后的干预单位块(右下角)外,其他地方的干预指标 \mathcal{W}_{ti} 均为零。

该赋值矩阵将导致以下观察到的潜在结果矩阵:

Y=\begin{bmatrix}Y(0)_{pre,co}&Y(0)_{pre,tr}\\Y(0)_{post,co}&Y(1)_{post,tr}\end{bmatrix}

请再次注意,干预后的时间段在下方,而干预后的单位在右侧。您的目标是估算 ATT=Y(1)_{post, tr}-Y(0)_{post, tr}。为此,您需要以某种方式估算缺失的潜在结果 Y(0)_{post, tr}, tr,即未观察到的结果。换句话说,您需要知道,如果没有接受干预,接受干预的单位在干预后会发生什么情况。要做到这一点,理想情况下,你可以利用你所掌握的所有其他三个区块,即 Y(0)_{pre,co}Y(0)_{pre,tr}。在向您展示合成控件如何做到这一点之前,让我们先创建一个函数,以这种矩阵格式表示数据。

下面的代码使用 .pivot() 方法重塑数据框,这样最终每个时间段(日期)一行,每个城市一列,而结果则成为矩阵的值。然后,它将矩阵划分为治疗单元和对照单元。再将其分为干预前和干预后两个阶段:

 def reshape_sc_data(df: pd.DataFrame,
 geo_col: str,
 time_col: str,
 y_col: str,
 tr_geos: str,
 tr_start: str):
 
 df_pivot = df.pivot(time_col, geo_col, y_col)
 
 y_co = df_pivot.drop(columns=tr_geos)
 y_tr = df_pivot[tr_geos]
 
 y_pre_co = y_co[df_pivot.index < tr_start]
 y_pre_tr = y_tr[df_pivot.index < tr_start]
 
 y_post_co = y_co[df_pivot.index >= tr_start]
 y_post_tr = y_tr[df_pivot.index >= tr_start]
 
 return y_pre_co, y_pre_tr, y_post_co, y_post_tr

本文中将一直使用这种四块矩阵表示法。如果你忘记了正在使用什么,只要回到这个函数就可以了。为了了解它是如何工作的,将 df_norm 传递给 reshape_sc_data,就会返回矩阵格式的 Y 值。下面是 y_pre_tr 的前五行:

 y_pre_co, y_pre_tr, y_post_co, y_post_tr = reshape_sc_data(
 df_norm,
 geo_col="city",
 time_col="date",
 y_col="app_download_pct",
 tr_geos=treated,
 tr_start=str(tr_period)
 )
 y_pre_tr.head()

Synthetic Control as Horizontal Regression

合成控制的主要理念非常简单。利用前干预期,您将找到一种方法来组合控制单元,以接近干预单元的平均干预结果。用数学术语来说,这可以理解为一个优化问题,即寻找单位权重 ωi(不要与  w_{it}=Post_{t}{}^{\star}D_{i} 混淆),这样当你用每个权重乘以其单位的结果 w_iy_i 时,就能得到类似于被处理单位的结果:

\widehat{\omega}^{sc}=\underset{\omega}{\operatorname*{argmin}}\left\|\overline{y}_{pre,tr}-Y_{pre,co}\omega_{co}\right\|^2

然后,为了估计 E[Y(0) | D=1,Post=1] 并得到 ATT 估计值,可以使用合成控制 Y_{post,co}\omega_{co} 。

如果这看起来有点晦涩难懂,那么将合成控制与我们更熟悉的工具--线性回归--进行比较,或许是一个很好的替代解释。回想一下,回归也可以用一个优化问题来表示,其目标是最小化结果与协变量线性组合 X 之间的(平方)差:

\beta^\star=\underset{\beta}{\operatorname*{argmin}}\left|\left|Y_i-X_i^{\prime}\beta\right|\right|^2

可以看出,这两个目标是一致的!这意味着,合成对照不过是一种回归,它以对照的结果为特征,试图预测受治疗单位的平均结果。其中的诀窍在于,它只使用干预前的时间段,因此回归估计值 E[Y_0|D=1]

事实上,为了证明我的观点,让我们现在就使用 OLS 建立一个合成对照。你所要做的就是把 y_pre_co 当作协变量矩阵 X,把 y_pre_tr 的列平均值当做结果 y。一旦拟合了这个模型,就可以用 .coef_ 提取权重:

 from sklearn.linear_model import LinearRegression
 model = LinearRegression(fit_intercept=False)
 model.fit(y_pre_co, y_pre_tr.mean(axis=1))
 # extract the weights
 weights_lr = model.coef_
 weights_lr.round(3)
 array([-0.65 , -0.058, -0.239, 0.971, 0.03 , -0.204, 0.007, 0.095,
 0.102, 0.106, 0.074, 0.079, 0.032, -0.5 , -0.041, -0.154,
 -0.014, 0.132, 0.115, 0.094, 0.151, -0.058, -0.353, 0.049,
 -0.476, -0.11 , 0.158, -0.002, 0.036, -0.129, -0.066, 0.024,
 -0.047, 0.089, -0.057, 0.429, 0.23 , -0.086, 0.098, 0.351,
 -0.128, 0.128, -0.205, 0.088, 0.147, 0.555, 0.229])


可以看到,每个控制城市都有一个权重。通常,回归法是在有大量单位(大 N)的情况下使用的,这样就可以把单位作为行,协变量作为列。但合成控制的设计是为了在单位相对较少,但时间跨度 Tpre 较大的情况下使用。为此,SC 实际上是将数据翻转过来,把单位当作协变量来使用。这就是合成控制也被称为水平回归的原因。

一旦估算出回归参数(或权重),就可以用它们来预测 E[Y_0|D=1] 的情况,不仅是干预前的情况,而且是整个时间范围内的情况:

 # same as y0_tr_hat = model.predict(y_post_co)
 y0_tr_hat = y_post_co.dot(weights_lr)

在这里,y0_tr_hat 可以看作是一种合成控制:是控制单元的组合,它们在没有接受治疗的情况下,接近于接受治疗单元的平均行为。

如果你把这个合成控制与观察结果相结合,你会得到这个:

请注意预测值(合成对照)是如何低于被处理单位的实际结果的。这意味着,如果不进行干预,观察到的结果要高于您估计的结果。这表明在线营销活动产生了积极的营销效果。您可以通过对比观察结果和合成对照来计算 ATT 估计值:

 att = y_post_tr.mean(axis=1) - y0_tr_hat

这一情节呈现出几个耐人寻味的方面。首先,它表明效果需要一段时间才能达到顶峰,然后逐渐下降。在市场营销中经常可以看到这种逐渐上升的现象,因为人们在看到广告后通常需要一段时间才能采取行动。此外,效果消失通常可归因于随着时间推移逐渐消失的新奇感效应。

第二个有趣之处在于干预前的 ATT 大小。在这一时期,ATT 可以简单地解释为 OLS 模型的残差(样本误差)。你可能会认为,它接近于零是件好事;毕竟,你不希望在干预(预期)之前看到效应。但事实并非如此。干预前误差低得令人难以置信,这也意味着 OLS 模型可能过度拟合。因此,样本外预测的估计值  E[Y_{0}|{D}=1,Post=1 ]可能会出现偏差。

这就是为什么简单回归不常用于建立合成控制的原因。由于列数(控制城市)相对较多,简单回归往往会出现过拟合,无法概括干预后时期的情况。因此,最初的合成控制方法并不是简单回归,而是施加了一些合理、直观的限制条件。

相关推荐

  1. Python 因果推断(下)

    2024-07-19 03:06:02       63 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-07-19 03:06:02       67 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-07-19 03:06:02       72 阅读
  3. 在Django里面运行非项目文件

    2024-07-19 03:06:02       58 阅读
  4. Python语言-面向对象

    2024-07-19 03:06:02       69 阅读

热门阅读

  1. 什么是diff算法?

    2024-07-19 03:06:02       17 阅读
  2. 让你写Vue/React更轻松的工具

    2024-07-19 03:06:02       21 阅读
  3. 关系数据库-关系数据库基础概念解析

    2024-07-19 03:06:02       17 阅读
  4. MATLAB并模拟一个质量-弹簧-阻尼系统(pid)

    2024-07-19 03:06:02       20 阅读
  5. 货币转换机器人:金融科技与云计算的融合

    2024-07-19 03:06:02       23 阅读
  6. Nginx的部署、配置和优化

    2024-07-19 03:06:02       25 阅读
  7. 【Pytorch笔记】张量

    2024-07-19 03:06:02       21 阅读
  8. 代码随想录学习 54day 图论 Bellman_ford 算法精讲

    2024-07-19 03:06:02       20 阅读