从观察数据(非AB实验数据)尝试获得因果效应的方法,我们之前学习了一种方法PSM。大致思想是从观察数据里找到各方面比较相似的两批人,观察他们在接受/不接受某种影响的结果差异,近似认为差异就是这种影响带来的。如从高中生中找到上大学/不上大学的人,进一步找到家庭、智商、性别等比较相似的两批人,对比工作后的收入差异,可以近似认为这个差异就是上大学的因果效应。
除非你有奇异博士的能力,可以浏览不同平行时空的结果
但如果我们的干预变量是连续变量呢?如想衡量健身时长对寿命的影响,如果我们需要控制的混淆变量非常多呢?如混淆变量超过50个,倾向得分模型准确性会下降,匹配质量也会下降。这个时候本次的主角DML就出来救场了!
1.DML基本思想和原理
基本原理
DML全称为Double Machine Learning,中文名为双重机器学习。不管用什么方法评估因果效应遇到的最大难题其实都是一致的:即如何尽可能地降低或消除混淆变量对因果效应估计的影响。
混淆变量的含义其实很简单,就是会同时影响干预变量和结果变量。举个例子,夏天天气热->可口可乐销量上升,夏天天气热->溺水事故数上升,如果我们去考察可口可乐销量对溺水事故数的因果效应时,如果不控制天气这个因素,则会错误地得到1个荒谬的结论:可口可乐销量上升->溺水事故数上升。但其实基于我们的生活常识,这两者完全没有因果效应。这个过程中捣蛋的就是混淆变量。这个例子里我们尚可以基于已有的常识判断结果不对,而在更多的因果效应推断中都是未知的影响链路,因此控制混淆变量对于正确地估计因果效应更为重要。
可口可乐躺枪
AB实验简单粗暴且有效地通过随机化干预消除了混淆变量;PSM是通过匹配相似的个体达到降低混淆变量对因果效应估计的影响;DML则是把混淆变量放入方程中。基于某个数学定理(Frisch-Waugh-Lovell(FWL)定理)通过残差正交化消除混淆变量对因果效应估计的影响。
方法步骤
简单来说就是,分别对结果变量和干预变量做2次拟合,对2次拟合得到的残差再做1次拟合就可以得到因果效应。
1.基于机器学习模型使用
拟合
,得到
,计算可得残差
2.基于机器学习模型使用
拟合
,得到
,计算可得残差
3.用机器学习模型拟合
和
,得到参数
,即认为是T和Y之间的真正因果效应值。
2.DML实现
2.1自定义实现
0.生成数据
from causalml.dataset import synthetic_data
# 使用synthetic_data生成数据
y, X, treat, _, _, _ = synthetic_data(mode=1, n=10000, p=8, sigma=1.0)
model参数控制数据生成的结构类型,不同模式对应不同的因果效应(CATE)与特征关系:
mode=1:线性关系,处理效应(Treatment Effect)恒定
mode=2:非线性关系,处理效应随特征变化
mode=3:包含交互项的非线性关系
mode=4:异质性处理效应(HTE),效应大小依赖特征
mode=5:复杂非线性关系,含高阶项和交互作用
2.n(样本数量)
3.p(特征维度),每个样本的特征数量(即特征向量的维度)
4.sigma(噪声标准差),添加到结果变量 y的高斯噪声的标准差,控制数据噪声水平,值越大,数据噪声越强,模型拟合难度越高
1.计算y的残差
from sklearn.ensemble import RandomForestRegressor
# 计算y的残差
rf_y = RandomForestRegressor()
rf_y.fit(X, y)
y_res = y - rf_y.predict(X)
2.计算t的残差
# 计算treat的残差
rf_t = RandomForestRegressor()
rf_t.fit(X, treat)
treat_res = treat - rf_t.predict(X)
3.拟合2个残差计算因果效应
最终得到ATE=0.4565,AUUC=0.5852。
from causalml.metrics import auuc_score, plot_gain
from sklearn.linear_model import LinearRegression
# 计算因果效果
lr = LinearRegression(fit_intercept=False).fit(treat_res.reshape(-1, 1), y_res.reshape(-1, 1))
theta = lr.coef_[0, 0] # 回归系数θ
# 计算ITE:θ * 个体处理残差
ite_estimates = theta * treat_res
# 使用dataframe组织计算AUUC的必要数据
df = pd.DataFrame({
'y': y,
'treat': treat,
'self_lr_dml': ite_estimates
})
# 计算AUUC值
auuc = auuc_score(df, outcome_col='y', treatment_col='treat', normalize=True, tmle=False)
print(auuc)
# 绘制gain曲线
plot_gain(df, outcome_col='y', treatment_col='treat', normalize=True, random_seed=10, n=100, figsize=(8, 8))
auuc= 0.585222.2 调包实现半自动
实现上调用econml.dml.DML,但在计算计算残差和残差拟合时可以自定义机器学习模型。
LR是在最终2个残差回归阶段使用线性回归模型,得到的ATE=0.4817,AUUC=0.4864
RF是在最终2个残差回归阶段使用随机森林模型,得到的ATE=0.4457,AUUC=0.5281
# dml + 线性
lr_dml = DML(model_y=RandomForestRegressor(),
model_t=RandomForestRegressor(),
model_final=LinearRegression(fit_intercept=False))
lr_dml.fit(y, treat, X=X)
print('lr_dml: {}'.format(lr_dml.ate(X)))
# dml + 非线性
rf_dml = DML(model_y=RandomForestRegressor(),
model_t=RandomForestRegressor(),
model_final=RandomForestRegressor())
rf_dml.fit(y, treat, X=X)
print('rf_dml: {}'.format(rf_dml.ate(X)))
lr_dml,auuc=0.486423
rf_dml,auuc=0.528143全自动
直接使用因果森林DML,最终CF得到的ATE=0.4679,AUUC=0.7144
# 因果森林DML
cf_dml = CausalForestDML()
cf_dml.fit(y, treat, X=X)
print('CausalForestDML: {}'.format(cf_dml.ate(X)))
cf_dml,auuc=0.714414
下课!点赞!