参考:
核心论文:
V. Chernozhukov, D. Chetverikov, M. Demirer, E. Duflo, C. Hansen, and a. W. Newey. Double Machine Learning for Treatment and Causal Parameters. ArXiv e-prints
Hetergeneous Treatment Effect旨在量化实验对不同人群的差异影响,进而通过人群定向/数值策略的方式进行差异化实验,或者对实验进行调整。Double Machine Learning把Treatment作为特征,通过估计特征对目标的影响来计算实验的差异效果。
Machine Learning擅长给出精准的预测,而经济学更注重特征对目标影响的无偏估计。DML把经济学的方法和机器学习相结合,在经济学框架下用任意的ML模型给出特征对目标影响的无偏估计,有知乎大佬的一个总结:
HTE问题可以用以下的notation进行简单的抽象
最直接的方法就是用X和T一起对Y建模,直接估计θ(x)。
但这样估计出的θ(x)往往是有偏的,偏差部分来自于对样本的过拟合,部分来自于g(X)估计的偏差,假定θ0是参数的真实值,则偏差如下:
【因果推断/uplift建模】Double Machine Learning(DML)
参考:AB实验人群定向HTE模型4 - Double Machine Learning
训练的过程:
步骤一. 用任意ML模型拟合Y和T得到残差Y ,T
步骤二. 对Y,T用任意ML模型拟合θ
θ(X)的拟合可以是参数模型也可以是非参数模型,参数模型可以直接拟合。而非参数模型因为只接受输入和输出所以需要再做如下变换,模型Target变为Y/T, 样本权重为T^2
这个Cross-fitting步骤非常重要,DML保证估计无偏很重要的一步就是Cross-fitting,用来降低overfitting带来的估计偏差。先把总样本分成两份:样本1,样本2。
先用样本1估计残差,样本2估计θ1,再用样本2估计残差,样本1估计θ2,取平均得到最终的估计。当然也可以进一步使用K-Fold来增加估计的稳健性。
Jonas在他的博客里比较了不使用DML,使用DML但是不用Cross-fitting,以及使用Cross-fitting的估计效果如下:
直观角度上,这里对回归比较熟悉的朋友可以知道,线性回归是拟合Y在特征空间X的最佳投影(既误差最小化),所以残差是垂直样本空间X的,既最大限度消除了(独立)X的相关性!如下图所示。
关于残差正交化可得到无偏差因果效应的数学原理:https://zhuanlan.zhihu.com/p/41993542
因果推断—原理与方法(深度好文)
【因果推断/uplift建模】Double Machine Learning(DML)
来简单看看DML中ATE的计算过程:
- 两个平行模型:M1(Y~X) 和 M2(T~X)
- Y i ~ = α + β 1 T i ~ + ϵ i \tilde{Y_i} = \alpha + \beta_1 \tilde{T_i} + \epsilon_i Yi~=α+β1Ti~+ϵi
CATE的计算过程:
- 仍然两个平行模型M1(Y~X) 和 M2(T~X)
- Y i ~ = α + β 1 T i ~ + β 2 X i T i ~ + ϵ i \tilde{Y_i} = \alpha + \beta_1 \tilde{T_i} + \pmb{\beta}_2 \pmb{X_i} \tilde{T_i} + \epsilon_i Yi~=α+β1Ti~+βββ2XiXiXiTi~+ϵi
具体到因果推断的例子上,我们只关心Treatment T 对 outcome Y的影响,因此我们可以首先使用X回归T,得到一个T的残差(实际T - 预测T),然后使用X回归Y,得到一个Y的残差(实际Y - 预测Y),最后使用T的残差回归Y的残差,估计的参数即我们想要的ATE。
( Y − ( Y ∼ X ) ) ∼ ( T − ( T ∼ X ) ) (Y - (Y \sim X)) \sim (T - (T \sim X)) (Y−(Y∼X))∼(T−(T∼X))
Y i − E [ Y i ∣ X i ] = τ ⋅ ( T i − E [ T i ∣ X i ] ) + ϵ Y_i - E[Y_i | X_i] = \tau \cdot (T_i - E[T_i | X_i]) + \epsilon Yi−E[Yi∣Xi]=τ⋅(Ti−E[Ti∣Xi])+ϵ
于是乎,具体的DML方法也就出来了,其核心思想即分别用机器学习算法基于X预测T和Y,然后使用T的残差回归Y的残差:
Y i − M ^ y ( X i ) = τ ⋅ ( T i − M ^ t ( X i ) ) + ϵ Y_i - \hat{M}_y(X_i) = \tau \cdot (T_i - \hat{M}_t(X_i)) + \epsilon Yi−M^y(Xi)=τ⋅(Ti−M^t(Xi))+ϵ
其中, M ^ y ( X i ) \hat{M}_y(X_i) M^y(Xi) 建模 E [ Y ∣ X ] E[Y|X] E[Y∣X] , M ^ t ( X i ) \hat{M}_t(X_i) M^t(Xi) 建模 E [ T ∣ X ] E[T|X] E[T∣X]。
那么问题来了,为什么说DML能去偏呢?
其关键在于 M ^ t ( X i ) \hat{M}_t(X_i) M^t(Xi),它对Treatment实施了去偏。
【划重点】T的残差可以看作将X对T的作用从T中去除后剩下的量,此时T的残差独立于X。
而 M ^ y ( X i ) \hat{M}_y(X_i) M^y(Xi)的作用在于去除Y的方差,即将X引起的Y的方差从Y中去除。
最后,我们再对残差建模lr,即得到ATE。
【因果推断/uplift建模】Double Machine Learning(DML)
同样地,我们首先基于X使用ML获得T的残差和Y的残差,之后使用lr拟合残差,不同的是,这次我们把X和T的交互项加进来,即
Y i − M y ( X i ) = τ ( X i ) ⋅ ( T i − M t ( X i ) ) + ϵ i Y_i - {M}_y(X_i) = \tau(X_i) \cdot (T_i - {M}_t(X_i)) + \epsilon_i Yi−My(Xi)=τ(Xi)⋅(Ti−Mt(Xi))+ϵi
Y i ~ = α + β 1 T i ~ + β 2 X i T i ~ + ϵ i \tilde{Y_i} = \alpha + \beta_1 \tilde{T_i} + \pmb{\beta}_2 \pmb{X_i} \tilde{T_i} + \epsilon_i Yi~=α+β1Ti~+βββ2XiXiXiTi~+ϵi
然后我们就可以计算CATE的值了:
μ ^ ( ∂ S a l e s i , X i ) = M ( P r i c e = 1 , X i ) − M ( P r i c e = 0 , X i ) \hat{\mu}(\partial Sales_i, X_i) = M(Price=1, X_i) - M(Price=0, X_i) μ^(∂Salesi,Xi)=M(Price=1,Xi)−M(Price=0,Xi)
其中,M即最后的lr模型。
在处理非线性CATE时,另一种方案是我们将不再尝试估计CATE的线性近似。相反,我们将做出反事实的预测。
(这种方案在实际中使用也很多,但并没有严格的理论证明!)
其流程分为两个步骤:
第一步,依然是估计T和Y的残差:
Y ~ i = τ ( X i ) T ~ i + e i \tilde{Y}_i = \tau(X_i) \tilde{T}_i + e_i Y~i=τ(Xi)T~i+ei
第二步,基于X和T的残差使用S-learner预测Y的残差:
Y ~ i = τ ( X i , T ~ i ) + e i \tilde{Y}_i = \tau(X_i, \tilde{T}_i) + e_i Y~i=τ(Xi,T~i)+ei
最后在 M ^ y ( X i ) \hat{M}_y(X_i) M^y(Xi)预测的 Y ^ \hat{Y} Y^上加上 Y ~ i \tilde{Y}_i Y~i,即得到最后的y值。
来自:数据分析36计(29):价格需求弹性和因果推断
经济学课程里谈到价格需求弹性,描述需求数量随商品价格的变动而变化的弹性。价格一般不直接影响需求,而是被用户决策相关的中间变量所中介作用。假设 Q 为某个商品的需求的数量,P 为该商品的价格,则计算需求的价格弹性为,
通过上式可以简单知道,价格改变 1 元比价格改变 100 元,会导致更大的需求改变。比如以 5 元的价格每日可以卖 100 单位产品,如果价格需求弹性为 -3 ,那供应商将价格提升 5%(dp /P,从 5 元-> 5.25 元),需求将下降 15%(dQ/Q ,从 100->85)。那么收入将减少 1005-5.2585=53.75。
如果单价降低 5%,那么收入同理将提升 46.25。如果供应商知道了产品的价格弹性,那无须反复测试,即可清楚为提升收入到底应该是提价还是降价。
最好的方式,当然是直接进行 A/B 实验测试不同价格对用户的需求反应,但是价格这类的外生因素在同一产品同一阶段上,对不同用户展示不同的价格会直接损坏用户体验。因此从观察历史数据进行因果推断,但混杂因素(季节性、产品质量等)如何控制是因果推断的挑战。
这里采用 DML(Double Machine Learning) 方法进行因果推断,该方法主要解决两个问题:
DML 先应用机器学习算法去分别通过特征变量 X, W 拟合结果变量 Y 和处理变量 T,然后通过线性模型,使用处理变量的残差拟合出结果变量的残差。
目标是估计 ,这里的 Y 函数构成为 T 的因果作用和 X、W 的协同作用之和。
将数据分为两部分,
关于残差正交化可得到无偏差因果效应的数学原理:https://zhuanlan.zhihu.com/p/41993542
因此直接将 P,Q 进行 log-log 回归就能得到弹性系数 :
文章来源地址:因果分析工具在快手的应用
快手这篇我觉得比较有意思的是他们给出了适用例子:遗漏变量是否可量化
具体PPT见:
参考:期刊:因果推理
试图利用一个近期的或容易得到的中间指标来替代远期的或难以得到的终点指标。
抑制心律失常能降低发生心脏骤停的可能性,曾将[抑制心律失常]作为评价[治疗猝死药物]的替代指标。
因为混杂因子而造成了很多的悖论:
https://www.jianshu.com/p/871fbf457a6d
在这个框架内,单个对象在不同时间点上分别扮演了处理组和对照组两种角色。
当X_t严格外生时,有两个可选的动态因果效应估计量:
参考官方:Double Machine Learning Notebook
该案例有非常多小的案例:
其中包括了:连续数值的T,二分类01的T,多个T,多个Y
# 连续数值的T
array([ 0.41083324, 0.57893171, 1.08130798, ..., -0.43799495,
1.61941775, 1.64209826])
# 二分类01的T
array([0, 0, 0, 0, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0])
# Multi-T
array([[1.35325451, 1.15373159, 0.46373402],
[1.35325451, 1.15373159, 0.98954119],
[1.35325451, 0.87129337, 0.73716407],
...,
[1.13462273, 1.03673688, 0.46373402],
[1.0260416 , 0.95165788, 0.39877612],
[1.05779029, 0.78390154, 0.55961579]])
# Multi-Y
array([[ 9.01869549, 8.40737833, 9.26482856],
[ 8.72323127, 8.44934252, 8.98719682],
[ 8.25322765, 9.91145572, 8.83171192],
...,
[ 9.93653541, 9.51546936, 9.50599061],
[10.85591733, 9.31793838, 10.9273763 ],
[10.23652533, 11.20553036, 8.85936345]])
方法包括:
包括数据生成:
import econml
## Ignore warnings
import warnings
warnings.filterwarnings("ignore")
# Main imports
from econml.dml import DML, LinearDML, SparseLinearDML, CausalForestDML
# Helper imports
import numpy as np
from itertools import product
from sklearn.linear_model import (Lasso, LassoCV, LogisticRegression,
LogisticRegressionCV,LinearRegression,
MultiTaskElasticNet,MultiTaskElasticNetCV)
from sklearn.ensemble import RandomForestRegressor,RandomForestClassifier
from sklearn.preprocessing import PolynomialFeatures
import matplotlib.pyplot as plt
import matplotlib
from sklearn.model_selection import train_test_split
%matplotlib inline
# Treatment effect function
def exp_te(x):
return np.exp(2*x[0])
# DGP constants
np.random.seed(123)
n = 2000
n_w = 30
support_size = 5
n_x = 1
# Outcome support
support_Y = np.random.choice(np.arange(n_w), size=support_size, replace=False)
coefs_Y = np.random.uniform(0, 1, size=support_size)
epsilon_sample = lambda n: np.random.uniform(-1, 1, size=n)
# Treatment support
support_T = support_Y
coefs_T = np.random.uniform(0, 1, size=support_size)
eta_sample = lambda n: np.random.uniform(-1, 1, size=n)
# Generate controls, covariates, treatments and outcomes
W = np.random.normal(0, 1, size=(n, n_w))
X = np.random.uniform(0, 1, size=(n, n_x))
# Heterogeneous treatment effects
TE = np.array([exp_te(x_i) for x_i in X])
T = np.dot(W[:, support_T], coefs_T) + eta_sample(n)
Y = TE * T + np.dot(W[:, support_Y], coefs_Y) + epsilon_sample(n)
Y_train, Y_val, T_train, T_val, X_train, X_val, W_train, W_val = train_test_split(Y, T, X, W, test_size=.2)
# Generate test data
X_test = np.array(list(product(np.arange(0, 1, 0.01), repeat=n_x)))
模型:
# 模型
est = LinearDML(model_y=RandomForestRegressor(),
model_t=RandomForestRegressor(),
random_state=123)
est.fit(Y_train, T_train, X=X_train, W=W_train)
te_pred = est.effect(X_test)
# 模型
est1 = SparseLinearDML(model_y=RandomForestRegressor(),
model_t=RandomForestRegressor(),
featurizer=PolynomialFeatures(degree=3),
random_state=123)
est1.fit(Y_train, T_train, X=X_train, W=W_train)
te_pred1 = est1.effect(X_test)
# 模型
est2 = DML(model_y=RandomForestRegressor(),
model_t=RandomForestRegressor(),
model_final=Lasso(alpha=0.1, fit_intercept=False),
featurizer=PolynomialFeatures(degree=10),
random_state=123)
est2.fit(Y_train, T_train, X=X_train, W=W_train)
te_pred2 = est2.effect(X_test)
# 模型
est3 = CausalForestDML(model_y=RandomForestRegressor(),
model_t=RandomForestRegressor(),
criterion='mse', n_estimators=1000,
min_impurity_decrease=0.001,
random_state=123)
est3.tune(Y_train, T_train, X=X_train, W=W_train)
est3.fit(Y_train, T_train, X=X_train, W=W_train)
te_pred3 = est3.effect(X_test)
# 画图
plt.figure(figsize=(10,6))
plt.plot(X_test, te_pred, label='DML default')
plt.plot(X_test, te_pred1, label='DML polynomial degree=3')
plt.plot(X_test, te_pred2, label='DML polynomial degree=10 with Lasso')
plt.plot(X_test, te_pred3, label='ForestDML')
expected_te = np.array([exp_te(x_i) for x_i in X_test])
plt.plot(X_test, expected_te, 'b--', label='True effect')
plt.ylabel('Treatment Effect')
plt.xlabel('x')
plt.legend()
plt.show()
score={}
score["DML default"] = est.score(Y_val, T_val, X_val, W_val)
score["DML polynomial degree=3"] = est1.score(Y_val, T_val, X_val, W_val)
score["DML polynomial degree=10 with Lasso"] = est2.score(Y_val, T_val, X_val, W_val)
score["ForestDML"] = est3.score(Y_val, T_val, X_val, W_val)
mse_te={}
mse_te["DML default"] = ((expected_te - te_pred)**2).mean()
mse_te["DML polynomial degree=3"] = ((expected_te - te_pred1)**2).mean()
mse_te["DML polynomial degree=10 with Lasso"] = ((expected_te - te_pred2)**2).mean()
mse_te["ForestDML"] = ((expected_te - te_pred3)**2).mean()
print("best model selected by MSE of TE: ", min(mse_te, key=lambda x: mse_te.get(x)))
score指的是MSE,越小越好
参考:Dynamic Double Machine Learning Examples.ipynb
Dynamic DoubleML is an extension of the Double ML approach for treatments assigned sequentially over time periods. This estimator will account for treatments that can have causal effects on future outcomes.
相当于DML + 时序效应,所以一般都是面板数据才会需要
生成数据
import econml
# Main imports
from econml.dynamic.dml import DynamicDML
from econml.tests.dgp import DynamicPanelDGP, add_vlines
# Helper imports
import numpy as np
from sklearn.linear_model import Lasso, LassoCV, LogisticRegression, LogisticRegressionCV, MultiTaskLassoCV
import matplotlib.pyplot as plt
%matplotlib inline
# Define DGP parameters
np.random.seed(123)
n_panels = 5000 # number of panels
n_periods = 3 # number of time periods in each panel
n_treatments = 2 # number of treatments in each period
n_x = 100 # number of features + controls
s_x = 10 # number of controls (endogeneous variables)
s_t = 10 # treatment support size
# Generate data
dgp = DynamicPanelDGP(n_periods, n_treatments, n_x).create_instance(
s_x, random_seed=12345)
Y, T, X, W, groups = dgp.observational_data(n_panels, s_t=s_t, random_seed=12345)
true_effect = dgp.true_effect
可以看到面板数据,有三年数据,5000个样本,两个处理T
模型训练
# Train Estimator
est = DynamicDML(
model_y=LassoCV(cv=3, max_iter=1000),
model_t=MultiTaskLassoCV(cv=3, max_iter=1000),
cv=3)
est.fit(Y, T, X=None, W=W, groups=groups)
# Effect of target policy over baseline policy
# Must specify a treatment for each period
baseline_policy = np.zeros((1, n_periods * n_treatments))
target_policy = np.ones((1, n_periods * n_treatments))
eff = est.effect(T0=baseline_policy, T1=target_policy)
print(f"Effect of target policy over baseline policy: {eff[0]:0.2f}")
# Period treatment effects + interpretation
for i, theta in enumerate(est.intercept_.reshape(-1, n_treatments)):
print(f"Marginal effect of a treatments in period {i+1} on period {n_periods} outcome: {theta}")
# Period treatment effects with confidence intervals
est.summary()
conf_ints = est.intercept__interval(alpha=0.05)
画图:
# Some plotting boilerplate code
plt.figure(figsize=(15, 5))
plt.errorbar(np.arange(n_periods*n_treatments)-.04, est.intercept_, yerr=(conf_ints[1] - est.intercept_,
est.intercept_ - conf_ints[0]), fmt='o', label='DynamicDML')
plt.errorbar(np.arange(n_periods*n_treatments), true_effect.flatten(), fmt='o', alpha=.6, label='Ground truth')
for t in np.arange(1, n_periods):
plt.axvline(x=t * n_treatments - .5, linestyle='--', alpha=.4)
plt.xticks([t * n_treatments - .5 + n_treatments/2 for t in range(n_periods)],
["$\\theta_{}$".format(t) for t in range(n_periods)])
plt.gca().set_xlim([-.5, n_periods*n_treatments - .5])
plt.ylabel("Effect")
plt.legend()
plt.show()
Case Study - Long-Term Return-on-Investment at Microsoft via Short-Term Proxies.ipynb
这里有一个关于DynamicDML的非常难懂的案例,笔者自己看的时候,觉得非常费解。这里也涉及到了【4.1】里面的代替指标。
在这简单根据笔者的理解,进行一下总结,生成数据:
# imports
from econml.data.dynamic_panel_dgp import SemiSynthetic
from sklearn.linear_model import LassoCV, MultiTaskLassoCV
import numpy as np
import matplotlib.pyplot as plt
# generate historical dataset (training purpose)
np.random.seed(43)
dgp = SemiSynthetic()
dgp.create_instance()
n_periods = 4 # Y包含了几个时期,默认为4个时间段
n_units = 5000 # 样本量
n_treatments = dgp.n_treatments # 3 - 多干预
random_seed = 43
thetas = np.random.uniform(0, 2, size=(dgp.n_proxies, n_treatments)) # 误差项
panelX, panelT, panelY, panelGroups, true_effect = dgp.gen_data(
n_units, n_periods, thetas, random_seed
)
这里有四年(时期)的数据,每个时期5k样本量
DynamicDML 结果为uplift增量,Y真实值 - DynamicDML增量 = Y常规趋势
这里有点像时间序列分解中,拆分为:长期趋势,季节变动,循环波动,不规则波动
EconML’s DynamicDML estimator is an extension of Double Machine Learning approach to dynamically estimate the period effect of treatments assigned sequentially over time period. In this scenario, it could help us to adjust the cumulative revenue by subtracting the period effect of all of the investments after the target investment.
# on historical data construct adjusted outcomes
from econml.dynamic.dml import DynamicDML
panelYadj = panelY.copy()
est = DynamicDML(
model_y=LassoCV(max_iter=2000), model_t=MultiTaskLassoCV(max_iter=2000), cv=2
)
for t in range(1, n_periods): # for each target period 1...m
# learn period effect for each period treatment on target period t
est.fit(
long(panelY[:, 1 : t + 1]),
long(panelT[:, 1 : t + 1, :]), # reshape data to long format
X=None,
W=long(panelX[:, 1 : t + 1, :]),
groups=long(panelGroups[:, 1 : t + 1]),
)
# print(f'y的shape {long(panelY[:, 1 : t + 1]).shape} , t 为 {t}, x为{long(panelX[:, 1 : t + 1, :]).shape}')
# remove effect of observed treatments
T1 = wide(panelT[:, 1 : t + 1, :])
panelYadj[:, t] = panelY[:, t] - est.effect(
T0=np.zeros_like(T1), T1=T1
) # reshape data to wide format
其中,修复每一期的过程中,用数据训练的DynamicDML 也不一致;
比如第一期periods,只有5000样本,就先拿5000样本;
第二期periods是把第一期+第二期的5000样本,一共10000样本。
整个案例非常费解,是因为这些数据没有现实意义,笔者也只能按照理解,
假设这个数据是,预测银行加息、降息、新增衍生品(T1/T2/T3,都是连续值)以及人口、经济(X/W)等因素,在4年内,对5000个国家GDP(Y)的影响
第一个剔除的操作,就是把 银行加息、降息、新增衍生品的影响去掉,剩下了单独人口/经济等因素,然后来求解 调整后的GDP
# 单独训练一个Y ~ X的回归模型进行预测
# train surrogate index on historical dataset
XS = np.hstack(
[panelX[:, 1], panelYadj[:, :1]]
) # concatenate controls and surrogates from historical dataset
# 有四期,第2个时期的X / Y
# (5000, 71) + (5000, 1) => (5000, 72)
TotalYadj = np.sum(panelYadj, axis=1) # total revenue from historical dataset
adjusted_proxy_model = LassoCV().fit(
XS, TotalYadj
) # train proxy model from historical dataset
# predict new long term revenue
XSnew = np.hstack(
[panelXnew[:, 1], panelYnew[:, :1]]
) # concatenate controls and surrogates from new dataset
sindex_adj = adjusted_proxy_model.predict(XSnew)
这里还是比较费解的,因为对数据使用解释的还是不够仔细(或者我没看懂…):
如果要预测这5000个国家,接下来4年总的调整后的GDP
基于之前4年的结果训练模型,这里做的一个假设是,拿第1年作为所有4年短期代替,来预测接下来4年所有GDP,步骤:
后面还应该有【4.4.3 评估政策效应:实际Y与估计+调整Y的差异】
有基于调整Y,实际Y 关于X|W的LinearDML估计的对比,不过这块感觉没看懂,就暂时写到这。
# Train EconML model
est = LinearDML(
model_y=GradientBoostingRegressor(),
model_t=GradientBoostingRegressor(),
featurizer=PolynomialFeatures(degree=2, include_bias=False),
)
est.fit(log_Y, log_T, X=X, W=W, inference="statsmodels",cache_values = True) #
# Get treatment effect and its confidence interval 得到治疗效果及其置信区间
# cache_values = True,可以拿到其中的残差项
te_pred = est.effect(X_test,T0=0, T1=1)
te_pred_interval = est.effect_interval(X_test) # 置信区间 上限与下限
LinearDML
函数中,如果把cache_values=True
,可以得到项目中的t~x
,y~x
中的残差项,以及X,W
一些属性:
# X的特征名称
est.cate_feature_names()
# Y的特征名称
est.cate_output_names()
# T的特征名称
est.cate_treatment_names()
# 异质性处理效应
# 每个预测,在X=1下,Y(T=1)-Y(T=0) => CITE
# 有100个样本,在不同X的情况下,折扣不同的增量,可以当作X的弹性系数,这里就是收入的弹性系数,
# 加入:X=1,te_pred=-3,收入如果为1单位的情况下,销量Y减少3单位
est.effect(X_test,T0=0, T1=1).sum()
# 总体平均处理效应,mean(te_pred.sum()),上面的CATE平均
est.ate(X_test)
est.ate(np.array([[1],[2]])) # 可以做预测 # ~ 等同const_marginal_ate
est.ate_inference(np.array([[1],[2]])) # 总体平均处理效应的一些辅助信息,方差、标准差等 ~ 等同const_marginal_ate_inference
est.ate_interval(np.array([[1],[2]])) # 总体平均处理效应的置信区间
# 最终模型结果
est.summary() # 如果dlm最终模型是线性模型,那这里显示线性模型的回归系数,此时是一个二次项模型,还有截距项
est.coef_# The coefficients in the linear model of the constant marginal treatment effect. 最终模型是线性的话,就是线性回归系数
est.intercept_ # 线性模型的截距项
# 使用的模型:最终模型 / T~X模型 / Y~X模型
est.model_cate,est.models_t,est.models_y
# 模型计算过程中,前面步骤的残差
res_dict = ['y_res', 'T_res', 'X', 'W']
{res_dict[n]:i for n,i in enumerate(est.residuals_)} # y_res, T_res, X, W,需要cache_values=True
est.effect()
其中我们来看一下est.effect(np.array([[1],[2]]),T0=0, T1=1)
算的是啥,
之前笔者也有点混淆,该函数算出的是CATE(或者我这边用异质性个体平均处理效应),在X=1下,Y(T=1)-Y(T=0) => CATE
而这个结果并不是跟之前机器学习里面的,model.predict(X)
一样,而是一种增量的表现。所以,常用于价格弹性的计算。
est.ate(X_test)
>>> −0.591735583328999
再来看看:
est.effect(np.array([[1],[1]]))
>>> array([6.07165998, 6.07165998])
这里可以看到,所求CATE,其中在同一个X情况下,是相同的。
在对数据进行更精准的描述:
est.effect_inference(np.array([[1],[1]])).summary_frame(alpha=0.1, value=0, decimals=3)
就会把这个X情况下的CATE以及这个的上限、下限都给标出
est.coef_
显示est最终model_final的线性模型的系数
本来
est.coef_
>>> array([5.35603442])
est.intercept_
>>> 0.0714625152770675
看更详细的是:
est.coef__inference().summary_frame() # 系数项
est.intercept__inference().summary_frame() # 截距项
est.intercept_
来看看截距项的意义
首先,这个截距项非常重要,要计算CATE的情况下,公式如下:
Y i − M y ( X i ) = τ ( X i ) ⋅ ( T i − M t ( X i ) ) + ϵ i Y_i - {M}_y(X_i) = \tau(X_i) \cdot (T_i - {M}_t(X_i)) + \epsilon_i Yi−My(Xi)=τ(Xi)⋅(Ti−Mt(Xi))+ϵi
Y i ~ = α + β 1 T i ~ + β 2 X i T i ~ + ϵ i \tilde{Y_i} = \alpha + \beta_1 \tilde{T_i} + \pmb{\beta}_2 \pmb{X_i} \tilde{T_i} + \epsilon_i Yi~=α+β1Ti~+βββ2XiXiXiTi~+ϵi
从第二个公式可以得知截距项,其实就是CATE,是所有ATE的汇总平均
est.summary()
再来看一下,est.summary()
得到的结果:
这里来与之前的est.ate(X_test)
做个对比
est.ate(X_test)
,代表 ATE = Y(T=1)-Y(T=0) ,这里是处理效应T的维度来看的两者结合才可以做反事实预测,使用X|W|T预测Y,不过,笔者一直在找有没有能做DML反事实预测的模块,好像没找到
要么就是针对这俩模型est.models_t
或est.models_y
来进行预测?一些尝试可参考:
因果推断——借微软EconML测试用DML和deepIV进行反事实预测实验(二十五)
参考官方:Double Machine Learning Notebook
当模型fit的时候,可以打开cache_values=True
,那么就可以更换model_y,model_t,model_final的模型类型了,举例:
# 原模型
est = DML(model_y=RandomForestRegressor(),
model_t=RandomForestRegressor(),
model_final=Lasso(alpha=0.1, fit_intercept=False),
featurizer=PolynomialFeatures(degree=1, include_bias=False),
random_state=123)
est.fit(Y_train, T_train, X=X_train, W=W_train, cache_values=True)
est.summary()
# 特征新增多项式PolynomialFeatures
from econml.sklearn_extensions.linear_model import DebiasedLasso
est.featurizer = PolynomialFeatures(degree=2, include_bias=False)
est.model_final = DebiasedLasso(fit_intercept=False)
est.refit_final() # 重新训练
est.summary()
# 更换最终的model_final模型
from econml.sklearn_extensions.linear_model import StatsModelsLinearRegression
est.model_final = StatsModelsLinearRegression(fit_intercept=False)
est.refit_final()
est.summary()
# 案例2
est.model_final = Lasso(fit_intercept=False)
est.refit_final()
est.effect_inference(X).population_summary()