目录
Propensity Score Matching
Inverse Propensity Weighting
Propensity Score Matching
另一种控制倾向得分的常用方法是匹配估计法。这种方法搜索具有相似可观测特征的单位对,并比较接受干预与未接受干预的单位的结果。如果您有数据科学背景,您可以将匹配视为一种简单的 K 最近邻(KNN)算法,其中 K=1 。首先,使用倾向得分作为唯一特征,在接受治疗的单位上拟合一个 KNN 模型,并用它来推算对照组的 Y1。然后,在未治疗单位上拟合一个 KNN 模型,用它来推算治疗单位的 Y0。在这两种情况下,推算值都只是匹配单位的结果,而匹配是基于倾向得分的:
from sklearn.neighbors import KNeighborsRegressorT = "intervention"X = "propensity_score"Y = "engagement_score"treated = data_ps.query(f"{T}==1")untreated = data_ps.query(f"{T}==0")mt0 = KNeighborsRegressor(n_neighbors=1).fit(untreated[[X]],untreated[Y])mt1 = KNeighborsRegressor(n_neighbors=1).fit(treated[[X]], treated[Y])predicted = pd.concat([# find matches for the treated looking at the untreated knn modeltreated.assign(match=mt0.predict(treated[[X]])),# find matches for the untreated looking at the treated knn modeluntreated.assign(match=mt1.predict(untreated[[X]]))])predicted.head()
一旦你有了一个匹配的每个单位,你可以估计的ATE:
其中是治疗组不同于i的单位i的匹配值:
np.mean((predicted[Y] - predicted["match"])*predicted[T]+ (predicted["match"] - predicted[Y])*(1-predicted[T]))0.28777443474045966
老实说,我不是这个估计器的忠实粉丝,第一,因为它有偏差;第二,因为它的方差很难推导;第三,因为我在数据科学方面的经验让我对 KNN 产生了怀疑,主要是因为它在处理高维 X 时效率很低。我在这里教授这种方法,主要是因为它非常有名,你可能会在这里或那里看到它。
Inverse Propensity Weighting
还有一种被广泛使用的倾向得分利用方法,我认为它更可取--反倾向加权法(IPW)。这种方法根据干预的反概率对数据重新加权,可以使干预在重新加权的数据中看起来像是随机分配的。为此,我们通过 对样本进行重新加权,以创建一个伪人群,近似于如果每个人都接受了 t 治疗会发生的情况:
再说一遍,证明这一点并不复杂,但这不是重点。因此,让我们坚持直觉。假设你想知道 Y1 的期望值,即如果所有经理都参加了培训,平均参与度会是多少。为了得到这个期望值,你需要将所有接受干预的经理人按照接受干预的反概率进行排序。这样,那些接受干预的概率很低,但还是接受了培训的人的权重就会很高。从本质上讲,你是在提高罕见干预案例的权重。
这很有道理,对吗?如果一个接受干预的个体接受治疗的概率很低,那么这个个体看起来就很像未接受干预的个体。这一定很有趣!如果未接受治疗的个体接受了治疗,,那么这个看起来像未接受治疗的个体很可能对未接受治疗的个体会发生的情况有很大的参考价值。对照组也是如此。如果对照组看起来很像治疗组,那么它很可能是 的良好估计值,所以你要给它更大的权重。
以下是管理培训数据的处理过程,权重表示为每个点的大小:
请注意,当 较低时,接受过培训的经理人(T = 1)的权重较高。你给予了那些看起来像未接受过培训的经理人很高的权重。相反,当 较高或 较低时,未接受培训的经理人的权重较高。在这种情况下,您就会高度重视与已治疗者相似的未治疗者。
如果您可以使用倾向得分来恢复平均潜在结果,这也意味着您可以使用倾向得分来恢复 ATE:
这两种期望都可以用非常简单的代码从数据中估计出来:
weight_t = 1/data_ps.query("intervention==1")["propensity_score"]weight_nt = 1/(1-data_ps.query("intervention==0")["propensity_score"])t1 = data_ps.query("intervention==1")["engagement_score"]t0 = data_ps.query("intervention==0")["engagement_score"]y1 = sum(t1*weight_t)/len(data_ps)y0 = sum(t0*weight_nt)/len(data_ps)print("E[Y1]:", y1)print("E[Y0]:", y0)print("ATE", y1 - y0)E[Y1]: 0.11656317232946772E[Y0]: -0.1494155364781444ATE 0.2659787088076121
此外,这个结果看起来与使用 OLS 得到的结果非常相似,这可以很好地检查您是否做错了什么。还值得注意的是,ATE 表达式可以简化如下:
果然,它产生的结果与以前完全相同:
np.mean(data_ps["engagement_score"]* (data_ps["intervention"] - data_ps["propensity_score"])/ (data_ps["propensity_score"]*(1-data_ps["propensity_score"])))0.26597870880761226