微信做公司網(wǎng)站怎么做廣州seo網(wǎng)站推廣平臺
因果推斷(三)雙重差分法(DID)
雙重差分法是很簡單的群體效應估計方法,只需要將樣本數(shù)據(jù)隨機分成兩組,對其中一組進行干預。在一定程度上減輕了選擇偏差帶來的影響。
因果效應計算:對照組y在干預前后的均值差( A ˉ 2 ? A ˉ 1 \bar A_2 - \bar A_1 Aˉ2??Aˉ1?),實驗組y在干預前后的均值差( B ˉ 2 ? B ˉ 1 \bar B_2 - \bar B_1 Bˉ2??Bˉ1?),則因果效應: ( B ˉ 2 ? B ˉ 1 ) ? ( A ˉ 2 ? A ˉ 1 ) (\bar B_2 - \bar B_1)-(\bar A_2 - \bar A_1) (Bˉ2??Bˉ1?)?(Aˉ2??Aˉ1?)
假設(shè)前提:DID有一個很重要且很嚴格的平行趨勢假設(shè),即實驗組和對照組在沒有干預的情況下,結(jié)果的趨勢是一樣的。
準備數(shù)據(jù)
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")
# 自定義數(shù)據(jù)
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)# 構(gòu)造假數(shù)據(jù),模擬用戶特征
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') # 按奇偶隨機分組# 構(gòu)造did數(shù)據(jù)
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()
驗證平行趨勢假設(shè)
# 計算文字的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()
除了畫圖觀察平行趨勢,也可以通過回歸擬合,參考自如何使用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())
可以看到交互項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
總結(jié)
在實際業(yè)務中,平行趨勢假設(shè)是很難滿足的,因此常常會先進性PSM構(gòu)造相似的樣本,這樣兩組群體基本上就會符合平行趨勢假設(shè)了,所以常見以PSM+DID進行因果推斷,有興趣的同學可以結(jié)合這兩期的內(nèi)容自行嘗試。
共勉~