当前位置: 首页 > news >正文

因果推断(三)双重差分法(DID)

因果推断(三)双重差分法(DID)

双重差分法是很简单的群体效应估计方法,只需要将样本数据随机分成两组,对其中一组进行干预。在一定程度上减轻了选择偏差带来的影响。

DID

因果效应计算:对照组y在干预前后的均值差( A ˉ 2 − A ˉ 1 \bar A_2 - \bar A_1 Aˉ2Aˉ1),实验组y在干预前后的均值差( B ˉ 2 − B ˉ 1 \bar B_2 - \bar B_1 Bˉ2Bˉ1),则因果效应: ( B ˉ 2 − B ˉ 1 ) − ( A ˉ 2 − A ˉ 1 ) (\bar B_2 - \bar B_1)-(\bar A_2 - \bar A_1) (Bˉ2Bˉ1)(Aˉ2Aˉ1)

假设前提:DID有一个很重要且很严格的平行趋势假设,即实验组和对照组在没有干预的情况下,结果的趋势是一样的。

准备数据

from faker import Faker
from faker.providers import BaseProvider, internet 
from random import randint
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
import math
import statsmodels.formula.api as smf
import warningswarnings.filterwarnings('ignore')# 绘图初始化
%matplotlib inline
sns.set(style="ticks")
# 自定义数据
fake = Faker('zh_CN')
class MyProvider(BaseProvider):def myCityLevel(self):cl = ["一线", "二线", "三线", "四线+"]return cl[randint(0, len(cl) - 1)]def myGender(self):g = ['F', 'M']return g[randint(0, len(g) - 1)]
fake.add_provider(MyProvider)# 构造假数据,模拟用户特征
uid=[]
cityLevel=[]
gender=[]
for i in range(10000):uid.append(i+1)cityLevel.append(fake.myCityLevel())gender.append(fake.myGender())raw_data= pd.DataFrame({'uid':uid,'cityLevel':cityLevel,'gender':gender,})raw_data['class'] = raw_data['uid'].map(lambda x: 'A' if x % 2 == 1 else 'B') # 按奇偶随机分组# 构造did数据
df = pd.DataFrame(columns=['uid','cityLevel','gender', 'class', 'sales', 'dt'])
for i,j in enumerate(range(2005,2011)):lift = 1+i*0.05df_temp = raw_data.copy()df_temp['sales'] = [int(x) for x in np.random.normal(300*lift, 60*lift, df_temp.shape[0])]df_temp['sales'] = df_temp.apply(lambda x: x.sales*0.88 if x['class']=='A' else x.sales, axis=1)if j>2007:df_temp['sales'] = df_temp.apply(lambda x: x.sales*(1+i*0.02) if x['class']=='B' else x.sales, axis=1)df_temp['dt'] = jdf=pd.concat([df,df_temp])df_did = df.groupby(['class', 'dt'])['sales'].sum().reset_index()

验证平行趋势假设

# 计算文字的y坐标
y_text = df_did.query('dt == 2007 and `class`=="B"')['sales'].values[0]
# 绘图查看干预前趋势
fig, ax = plt.subplots(figsize=(12,8))
sns.lineplot(x="dt", y="sales", hue="class", data=df_did)
ax.axvline(2007, color='r', linestyle="--", alpha=0.8)
plt.text(2007, y_text, 'treatment')
plt.show()

output_2_0

除了画图观察平行趋势,也可以通过回归拟合,参考自如何使用Python计算双重差分模型

# 方法2 回归计算
df_did['t'] = df_did['treatment'].map(lambda x: 1 if x=='干预后' else 0) # 是否干预后
df_did['g'] = df_did['class'].map(lambda x: 1 if x=='B' else 0) # 是否试验组
df_did['tg'] = df_did['t']*df_did['g'] # 交互项# 回归
est = smf.ols(formula='sales ~ t + g + tg', data=df_did).fit() 
print(est.summary()) 

image-20230104232512894

可以看到交互项tg并不显著,因此可以认为具备平行趋势

计算因果效应

# 计算因果效应
df_did['treatment'] = df_did['dt'].map(lambda x: '干预后' if x>2007 else '干预前')
df_did_cal = df_did.groupby(['class', 'treatment'])['sales'].mean()
did = (df_did_cal.loc['B', '干预后'] - df_did_cal.loc['B', '干预前']) - \(df_did_cal.loc['A', '干预后'] - df_did_cal.loc['A', '干预前'])
print(did)
175541.82000000007

总结

在实际业务中,平行趋势假设是很难满足的,因此常常会先进性PSM构造相似的样本,这样两组群体基本上就会符合平行趋势假设了,所以常见以PSM+DID进行因果推断,有兴趣的同学可以结合这两期的内容自行尝试。

共勉~

http://www.lryc.cn/news/113114.html

相关文章:

  • neo4j入门实例介绍
  • CGAL-2D和3D线性几何内核-点和向量-内核扩展
  • Ubuntu 22.04 安装docker
  • 电脑维护进阶:让你的“战友”更强大、更持久!
  • 【Leetcode】75.颜色分类
  • Pytesseract学习笔记
  • cnvd通用型证书获取姿势
  • elasticsearch的副本和分片的区别
  • Docker部署Gitlab
  • ABeam News | ABeam大中华区新人入社式,开启崭新的职场探索之旅吧!
  • 【C++】开源:sqlite3数据库配置使用
  • [Docker实现测试部署CI/CD----Jenkins集成相关服务器(3)]
  • 【Shell】基础语法(二)
  • Unity之webgl端通过vue3接入腾讯云联络中心SDK
  • 《算法竞赛·快冲300题》每日一题:“连接草坪(II)”
  • LNMP及论坛搭建(第一个访问,单节点)
  • EXCEL,多条件查询数字/文本内容的4种方法
  • 全志D1-H (MQ-Pro)驱动 OV5640 摄像头
  • 2023下半年软考初级网络管理员报名入口-报名流程-备考方法
  • QEMU源码全解析29 —— QOM介绍(18)
  • 从入门到精通——【初识网络】
  • MySQL alter命令修改表详解
  • Vulnhub: ColddWorld: Immersion靶机
  • Redis 总结【6.0版本的】
  • 状态模式(C++)
  • 承泰科技Q3再获30多个智驾项目,新增订单0.86亿!累计近11亿!
  • 以太网Ethernet通信协议
  • 内网横向移动—资源约束委派
  • Spring Boot Logback日志格式改为JSON
  • Linux 块设备操作函数