你了解渐进式DID平行趋势图的几种画法吗?

导读规则:
  • 正文出现红色字体,对应Stata命令;

  • 正文中出现蓝色字体,对应往期链接;

  • do文件中:'//'符号代表作者注释内容,帮助理解;'**'代表分节,便于阅读

  • 关键词:coefplot   tvdiff

双重差分模型(Difference in Difference,DID)是评估政策经常会使用的计量方法,之前挑选的10篇精读文章里有3篇涉及到该方法,其基本原理是利用处理组和控制组在政策实施前后差异的差分来估计因果效应。如下图所示,在满足系列假设的前提下某项政策的因果效应为

。这些假设包括共同趋势假设(平行趋势)、共同区间假设、干预外生性假设以及干预不存在溢出效应等。后面三个假设是否满足一般可以直接判断或者通过文字阐述,而第一个假设主要通过图表的形式展现。政策干预的形式不同,一般可分为'一刀切'政策(2015年的固定资产加速折旧)和逐步试点推开政策(金税三期工程实施等),不同的政策对应的DID模型设定存在差异。本文重点分析后者,即渐进式DID的平行趋势图表检验方法,并结合模拟数据进行解释。

Stata中画平行趋势图的方法可以分为三种:(1)用tvdiff命令画图;(2)用coefplot命令画图;(3)提取回归系数画图。下面我们将结合Stata系统自带的模拟数据以及现实中的数据比较三种方法的差异,具体过程如下:
  • tvdiff命令画平行趋势检验图

  **tvdiff命令提供了模拟数据,数据创造过程如下: clear set obs 5 //设置5个个体 set seed 10101 gen id=_n //生成个体id expand 50 //观察值扩展50倍 drop in 1/5 //删除前五个观察值 bysort id: gen time=_n+1999 //时间从2000-2048年,共49期 gen D=rbinomial(1,0.4) gen x1=rnormal(1,7)  tsset id time forvalues i=1/6{ gen L`i'_x=L`i'.x } bys id: gen y0=5+1*x+ rnormal() bys id: gen y1=100+5*x+90*L1_x+90*L2_x+120*L3_x+100*L4_x+90*L5_x +90*L6_x + rnormal() gen A=6*x+rnormal() replace D=1 if A>=15 replace D=0 if A<15  gen y=y0+D*(y1-y0)  tsset id time
运行上述命令得到的数据是一个渐进式DID的基础数据,其中变量D随着个体(id)和time发生变化,而且仅在政策发生当年取值为1,其他年份取值为0。这和渐进式DID的基准回归模型中政策变量的设定有点区别,具体区别如下所示(其中假设样本区间是2000-2005,个体1受到政策干预时间是2002年,个体2受到政策干预时间是2003,个体3未受到政策干预)。理解第二种形式的设定是掌握渐进式DID平行趋势检验的基础。
**基准回归模型中Dit的设定,此时回归得到的Dit系数代表的是政策实施后所有期间的平均效应input id time Dit1 2000 01 2001 01 2002 11 2003 11 2004 11 2005 12 2000 02 2001 02 2002 02 2003 12 2004 12 2005 13 2000 03 2001 03 2002 03 2003 03 2004 03 2005 0end**系统自带数据中Dit的设定方式,此时回归代表的是政策实施当年的平均效应input id time Dit1 2000 01 2001 01 2002 11 2003 01 2004 01 2005 02 2000 02 2001 02 2002 02 2003 12 2004 02 2005 03 2000 03 2001 03 2002 03 2003 03 2004 03 2005 0end
通过Stata生成的模拟数据,我们可以直接运行tvdiff命令,得到平行趋势检验图:
xi: tvdiff y D x, model(fe) pre(6) post(6) vce(robust) graph save_graph(mygraph)//D代表渐进式DID的核心变量,x是控制变量,y是被解释变量//model代表回归方式,可选择fe或ols//pre(6)代表将政策向前推移6期(lead,可使用F.命令实现),而post代表将政策向后推移6期(lag,可使用L.命令实现)//pre和post括号中的选择会使样本出现缺失,期数越多损失越大
tvdiff命令提供的平行趋势检验图提供了政策实施前后6期的回归系数在5个不同置信水平下的置信区间。我们主要关注政策实施之前的回归系数是否为零,从图中来看,在1%的显著性水平下我们认为平行趋势的假设是成立,因为从t-6到t-1的置信区间均包含了零。上面的结论是我们从图形上就可以直观得到的,当然tvdiff命令也在结果窗口直接显示了平行趋势假设是否通过。但是这里面会让人产生的疑问是:我们设定了政策实施前后6期的变量,这些变量之间不存在完全共线性嘛?或者说我们不应该选择一个基准组进行比较吗?就个人理解而言,tvdiff命令是把其他不属于[t-6,t+6]期间的D当作了基准组,从图上来看t+6的系数接近于0,而t-6包含零,所以上述结论可近似成立。
tvdiff命令得到的图就是置信区间图,那它和coefplot命令有什么区别呢?一旦知道了,我们就拆开tvdiff运行的黑匣子,对图1的各种属性进行设置,毕竟tvdiff提供的图表属性选择项十分有限,无法对图表进一步美化。

图1  tvdiff命令得到的平行趋势图

我们在Stata中输入如下命令,就可查看tvdiff的ado文件了。我们发现tvdiff其实就是通过coefplot命令运行的。既然如此,我们可以不用tvdiff命令,而是直接使用coefplot命令画出平行趋势检验图,对置信区间图的各种元素属性进行设置。
  • coefplot命令画平行趋势检验图

**查看tvdiff与coefplot命令的区别  viewsource tvdiff.ado**还原tvdiff命令运行的详细过程  marksample touse  //设定回归样本  *LAGS:  local lags  forvalue i=1/6{    cap drop _D_L`i'     gen _D_L`i'=L`i'.D if `touse'    local lags '`lags' _D_L`i''  }  //构造滞后变量,对应post(6),即将政策后移,每后移一期生成新的变量会有缺失值  *LEADS:  local leads  forvalue i=6(-1)1{    cap drop _D_F`i'    gen _D_F`i'=F`i'.D if `touse'    local leads '`leads' _D_F`i''  }  //构造滞后变量,对应pre(6),即将政策前移,每前移一期生成新的变量会有缺失值  xtreg y `leads' D `lags' x  if `touse',vce(robust) fe noomitted   //进行回归,对应model(fe)  //noomitted等价于:drop if missing(_D_F6,_D_F5,_D_F4,_D_F3,_D_F2,_D_F1,_D_L1,_D_L2,_D_L3,_D_L4,_D_L5,_D_L6)  //该选择项意味着构造的所有新变量含有缺失值的样本一律被剔除,这是  tempname B C  mat `B'=e(b)  //提取回归结果中储存的系数  mat list `B'  mat `C'=`B''  //'表示转置  mat list `C'  local M=6+6+1  mat `C'=`C'[1..`M',1...]  //取C矩阵的前M行,第一列  //提取各个政策变量的系数  mat list `C'  cap drop `C'1  svmat `C'  //将矩阵生成变量  tempvar id2  gen `id2'=_n  //每个系数的编号对应id  local sum_lags  forval i=1/6{  local sum_lags `sum_lags' _D_L`i'=t+`i'  //宏的嵌套  }  local sum_leads  forval i=6(-1)1{    local sum_leads `sum_leads' _D_F`i'=t-`i'  }  local myD 'D=t'    test `leads'  if r(p)>=0.05{  di as text ''  di as result 'RESULT: 'Parallel-trend' passed'  }  //进行平行趋势检验,从这里我们可以看出平行趋势检验关注的前移(lead)政策变量的显著性  coefplot .,vertical drop(_cons) yline(0) msymbol(d) mcolor(white)  ///  title('',size(medium))  ///  levels(99 95 90 80 70) ciopts(lwidth(3 ..) lcolor(*0.2 *0.4 *0.6 *0.8 *1)) addplot(line `C'1 `id2') keep(`leads' D `lags')  ///  legend(order(1 '99' 2 '95' 3 '90' 4 '80' 5 '70') row(1))  ///  coeflabels(`sum_leads' `myD' `sum_lags')  graph export 'Parallel0.png',replace  //画图,得到和图1一样的结果

图1并不是我们在论文中看到的通常意义上的平行趋势检验图,但是通过对tvdiff命令的溯源分析,我们就能在掌握平行趋势检验基本原理的基础上,进一步修改元素属性的设置,如下:

*调整图表属性设置 coefplot,vertical drop(_cons) msymbol(d) /// title('',size(medium)) /// ylabel(,labsize(small) nogrid tl(0.5)) xlabel(,labsize(small) tl(0.5)) /// levels(95) ciopts(lwidth(*0.5) lcolor(*1) recast(rcap) lp(dash)) addplot(scatter `C'1 `id2',connect(l) msymbol(O) mcolor(cranberry*0.5) lcolor(cranberry*0.5)) keep(`leads' D `lags') /// legend(order(1 '95') row(1) region(lcolor(gs15) fcolor(gs15) margin(small)) symxsize(*2) symysize(*0.1) size(vsmall)) /// yline(0,lcolor(gs10) lwidth(0.1)) /// graphregion(color(white)) /// coeflabels(`sum_leads' `myD' `sum_lags') graph export 'parallel2.png',replace

通过运行上述命令,我们可以得到图2。但图2有一个问题就是我们并没有选择基准组,tvdiff命令运行的结果告诉我们这并没有错误。但是在现实情况中,我们经常会看到一些论文展示的平行趋势图表通常会有某一期系数为零,并将其作为比较的基准组,这是如何实现的呢?

图2  coefplot画平行趋势检验图

  • 提取回归系数画平行趋势检验图

coefplot命令的一个缺陷就是它能够显示基准组的回归系数,但是无法将基准组的回归系数设定为零。如何设定基准组并进行回归就显得比较重要。平行趋势假设的原理就是假设政策提前n年实施,比较实施年份与基准年份之间处理组和控制组是否存在显著性差异,如果这时双重差分系数不显著,我们就可以认为平行趋势满足。基于此想法,基准组选择政策实施之前的时间点都属于合理范围之内,当然选择样本区间内离政策实施最早的时间点是最为恰当的。下面本文将用个人数据对该方法进行阐述,并分别比较tvdiff命令、coefplot命令以及提取回归系数三种方法的差异:
  use 'data.dta',clear  gen D=(year-time==0)   //year表示年份,time表示政策实施时间  **tvdiff命令  tvdiff y D $X,model(fe) pre(4) post(2) vce(robust) graph save_graph(mygraph)

运行上述命令后,我们可以得到图3的结果。与之前不同的是,我们在tvdiff的语法中设定了post(2),但在最终的图表呈现中我们只看到了[t-4,t-1]期的回归系数,很重要的一个原因就是我们的样本是非平衡面板,tvdiff命令在进行回归的时候会加noomitted选择项,这会导致回归样本大幅减少,导致政策当期与滞后两期的变量出现完全共线性问题,最终回归结果也就被ommited掉了,那有没有好的方法能够缓解这一问题呢?

图3  tvdiff命令得到的平行趋势检验图

我们可以采取类似虚拟变量的设置方法检验平行趋势,该方法的好处在于避免了F.和L.命令的使用,减少回归样本的损失,实现过程如下:

  **对政策实施年份进行标准化  gen tt=year-time  //tt代表政策实施时间 replace tt=-5 if tt<=-5  //将早于政策实施时间5年的样本全部设定为5年 replace tt=2 if tt>=2  //将晚于政策实施时间2年的样本全部设定为2年 gen tt_d=tt+5  //将政策时间加5,保证tt大于0
通过coefplot命令得到平行趋势检验图的过程如下:
**coefplot命令  xtreg Y ib4.tt_d $X,fe r  //使用4作为基准组  forvalues i = 0/4{  cap drop b_`i'  gen b_`i' = _b[`i'.tt_d]  }  cap drop avg_coef  gen avg_coef = (b_4+b_3+b_2+b_1+b_0)/5  su avg_coef    //生成前五期系数均值   coefplot, baselevels ///   keep(0.tt_d 1.tt_d 2.tt_d 3.tt_d 4.tt_d 5.tt_d 6.tt_d 7.tt_d)  ///   coeflabels(0.tt_d = 't-5' ///   1.tt_d = 't-4' ///   2.tt_d = 't-3' ///   3.tt_d = 't-2' ///   4.tt_d = 't-1' ///   5.tt_d = 't' ///   6.tt_d = 't+1' ///   7.tt_d = 't+2') ///更改系数的label   vertical ///转置图形   yline(0, lwidth(vthin) lpattern(dash) lcolor(gs10)) ///加入y=0这条虚线   xline(5, lwidth(vthin) lpattern(dash) lcolor(cranberry)) ///   transform(*=@-r(mean)) ///去除前五期的系数均值   addplot(line @b @at,lp(dash) lwidth(*0.5)) ///增加点之间的连线   ciopts(lpattern(solid) lcolor(navy) recast(rcap) msize(medium)) ///CI为虚线上下封口   msymbol(O) mcolor(navy) ///plot空心格式   xlabel(,labsize(small) tl(0.8))  ylabel(,labsize(small) tl(0.8)) ///   ytitle('{bf:置信区间}',box size(small) lc(white) margin(medium) fc(white) color(navy)) xtitle('{bf:政策实施时间}',box size(small) lc(white) margin(medium) fc(white) color(navy)) ///   scheme(s1mono) plotregion(style(none))   graph export 'parallel4.png',replace
通过coefplot命令得到图4:
图4  coefplot命令得到的平行趋势检验图
通过提取回归系数的方式得到平行趋势检验图的过程如下:
**提取回归系数 xtreg Y ib0.tt_d $X,fe r gen b=. gen se=. forvalue i=1/8{ local a=`i'-1 replace b=_b[`a'.tt_d] if _n==`i' } forvalue i=1/8{ local a=`i'-1 replace se=_se[`a'.tt_d] if _n==`i' } gen b_up=b+1.96*se gen b_low=b-1.96*se gen id=_n if b~=. egen a=mean(b) if _n<=5 egen avecoef=max(a) if _n<=8 gen b_sd=b-avecoef replace b_sd=0 if _n==1 scatter b_sd id if id<=8,connect(l) lcolor(gs10) lwidth(*0.5) lp(dash) msymbol(O) mcolor(navy) || (rcap b_low b_up id if id<=8,lcolor(navy) lp(solid) lwidth(*0.5)) /// ,yline(0,lcolor(gs10) lwidth(0.1)) xline(1,lwidth(0.15) lcolor(cranberry)) ylabel(,labsize(small) tl(0.8) nogrid) ysca(r(0 0.045)) /// xlabel(1 't-5' 2 't-4' 3 't-3' 4 't-2' 5 't-1' 6 't' 7 't+1' 8 't+2',labsize(small) tl(0.8)) xsca(r(0.75 8.25)) /// xtitle('政策实施时间',box margin(medium) size(small) fcolor(white) lc(white)) /// graphregion(color(white)) /// legend(off) graph export 'parallel5.png',replace
通过提取回归系数得到图5:

图5  提取回归系数得到的平行趋势检验图

上述方法是通过因子变量的方法设定基准组的,我们也可以通过控制加入虚拟变量个数来选择基准组,实现过程如下:
  gen pre4and_more=0  replace pre4and_more=1 if tt<=-5  tab tt,g(dum)  gen post2more=0  replace post2more=1 if tt>=2  rename dum6 pre4  rename dum7 pre3  rename dum8 pre2  rename dum9 pre1  rename dum10 current  rename dum11 post1  xtreg Y pre4 pre3 pre2 pre1 current post* $X,fe r  forvalue i=1/4{    gen pre_`i'=_b[pre`i']  }  gen avg_pre = (pre_1+pre_2+pre_3+pre_4)/5  sum avg_pre  coefplot, baselevels ///  keep(pre* current post*) ///  coeflabels( pre4='t-4' pre3='t-3' pre2='t-2' pre1='t-1' current='t' post1='t+1' post2more='t+2') ///更改系数的label  vertical ///转置图形  yline(0, lwidth(vthin) lpattern(dash) lcolor(teal)) ///加入y=0这条虚线  xline(6, lwidth(vthin) lpattern(dash) lcolor(teal)) ///  ytitle('Percentage Changes', size(small)) ///加入Y轴标题,大小small  xtitle('Years relative to branch deregulation', size(small)) ///加入X轴标题,大小small  transform(*=@-r(mean)) ///去除前五期的系数均值  addplot(line @b @at) ///增加点之间的连线  ciopts(lpattern(dash) recast(rcap) msize(medium)) ///CI为虚线上下封口  msymbol(circle_hollow) ///plot空心格式  scheme(s1mono)
通过coefplot命令得到图6,图中未放入基准组:

图6  提取回归系数得到的平行趋势检验图


新手上路一枚,有解读错误的地方请大家多多指正!

 点个赞、打个赏、转个发,都是对作者莫大的鼓励

(0)

相关推荐