如何用Stata完成(shui)一篇经济学论文(十五):平行性趋势检验与安慰剂检验

    科技2025-05-14  67

    目录

    平行性趋势检验安慰剂检验

    本来打算把DID讲一讲,结果网页上一搜,讲DID的还是挺多的,另外DID相对于RD好理解得多,也没有什么需要着重解释的东西,所以就直接写写平行性趋势检验和安慰剂检验over。第一次写博客,这个专栏断断续续两个多月才完成,总体来说我还是挺满意的,哈哈哈哈。以后stata也没啥好讲的,有机会用这个博客写写数据分析的随笔(当然也要看我input怎么样)。Stata系列最后一篇,完结撒花~~

    平行性趋势检验

    时间趋势图 平行性趋势检验最简单粗暴的方法就是画时间趋势图,将控制组和对照组随着时间的趋势在同一张图中表现出来,如果事件前两组趋势平行,事件后,两组的趋势开始产生差异,说明DID的前提性假设成立。具体如何画图请参考画线性图。 这里需要注意的一点是,如果你的数据频率比较高,时间跨度大(如日度数据,持续三年),最好将原始数据以月份或者季度为单位取均值,这样图形看起来比较清晰,从而不会被误会没有进行平行性趋势检验(别问我怎么知道的)。画系数与置信区间图 这个方法更为科学令人信服,依然用我们前面说的日度数据、持续三年举例子,如果政策实施时间点为最后一年,那么我们使用季度(或者半年度)的虚拟时间变量与treatment group产生交互,形成一个具有多个交互项的回归式。 我们传统的DID模型是这样: y c t = β 0 + β 1 p o s t c + β 2 t r e a t t + δ p o s t c × t r e a t t + λ X c t + ξ c t y_{ct}=\beta_{0}+\beta_{1}post_{c}+\beta_{2}treat_{t}+\delta post_{c}\times treat_{t}+\lambda X_{ct}+\xi_{ct} yct=β0+β1postc+β2treatt+δpostc×treatt+λXct+ξct 在这里我们需要画图的DID模型变成这样: y c t = β 0 + ∑ i = 0 N β 1 i t i m e i + β 2 t r e a t t + ∑ i = 0 N δ i t i m e i × t r e a t t + λ X c t + ξ c t y_{ct}=\beta_{0}+\sum_{i=0}^N \beta_{1i}time_{i}+\beta_{2}treat_{t}+\sum_{i=0}^N \delta_{i} time_{i}\times treat_{t}+\lambda X_{ct}+\xi_{ct} yct=β0+i=0Nβ1itimei+β2treatt+i=0Nδitimei×treatt+λXct+ξct 最终我们需要画出的就是 δ i \delta_{i} δi以及它的置信区间图。结果中,如果在政策实施前, δ i \delta_{i} δi的值为0或者置信区间包括0,政策后,该值不为0,则假设成立。 如何完成这幅图,首先我们要先写出回归公式(参照第二个回归方程),这里大家就根据自己的模型去写,这里要注意的是,在回归前,我们需要把交互项先乘出来,不要直接在reg里写i.post#i.treat * inter_*表示treat和time_*的交互项 * reg y i.treat i.time_* inter_*

    然后使用coefplot画出置信区间和系数图

    coef, keep(inter_*) vertical addplot(line @b @at)

    vertical的意思是回归系数在Y轴上表示,addplot选项是把各回归系数的点用直线连接起来,addplot里的选项照抄就行。最后画出来的图是这样,我这个图的结果根本就不好,只是给大家一个图形范例。

    安慰剂检验

    相信大家都碰到300+次随机取post(或treat)进行反事实检验,将关注变量的回归系数画成分布图,这个分布图的结果通常分布在0附近,与文章本身基准回归结果存在较大差异,从而证明基准回归结果的得出不是偶然。

    ** 这是随机指定post(政策执行时间)的代码 ** forvalue i=1/LOOP_TIME{ //loop_time处填入你要进行安慰剂检验的次数 use "simdid.dta", clear //调入数据,自己去看你的数据路径 drop post //去掉原来DID中的post变量 gen random_digit=ceil(runiform(1,1028)) //我的数据时间是1028天,根据自己的数据填,通过encode来生成数字化时间变量 replace random_digit = random_digit[1] g new_post= (date>random_digit[1]) set matsize 11000 g x = new_post*treat reg y i.new_post i.treat x ,vce(cluster citycode) g _b_new_post= _b[x] //提取x的回归系数 g _se_new_post= _se[x] //提取x的标准误 keep_b_new_post _se_new_post duplicates drop _b_new_post, force save placebo`i', replace //把第i次placebo检验的系数和标准误存起来 } * 纵向合并loop_time次的系数和标准误 * use placebo1, clear forvalue i=2/LOOP_TIME{ append using placebo`i' //纵向合并1000次回归的系数及标准误 } gen tvalue= _b_new_post/ _se_new_post kdensity tvalue, xtitle("t值") ytitle("分布") tline(-17.805 , lp(dash) lc(black) ) tlabel(-17.805 , add labsize(*.75)) //-17.805是我基准回归中的系数,这里也改成你基准回归中系数 * 删除临时文件 * forvalue i=1/loop_time{ erase placebo`i'.dta } save 123.dta ** 这是随机指定treat变量的代码 ** forvalue i=1/LOOP_TIME{ //loop_time处填入你要进行安慰剂检验的次数 use "simdid.dta", clear //调入数据 drop treat //去掉原来DID中的post变量 gen random_digit1=ceil(runiform(1,285)) //生成随机数,我这里treat+control group共有285个个体 g new_treat=0 forvalue j=1/28{ //指定28个个体为treatment group replace new_treat=1 if citycode==random_digit1[`j'] } //citycode是我有285个个体(城市),依然通过encode为它们生成的数字变量) * 合并,回归,提取系数 * set matsize 11000 g x = post*new_treat reg y i.post i.new_treat x,vce(cluster citycode) g _b_new_treat = _b[x] //提取x的回归系数 g _se_new_treat = _se[x] //提取x的标准误 keep _b_new_treat _se_new_treat duplicates drop _b_new_treat, force save placebo`i', replace //把第i次placebo检验的系数和标准误存起来 } * 纵向合并loop_time次的系数和标准误 * use placebo1, clear forvalue i=2/loop_time{ append using placebo`i' //纵向合并1000次回归的系数及标准误 } gen tvalue= _b_new_treat/ _se_new_treat kdensity tvalue, xtitle("t值") ytitle("分布") tline(-15.253 , lp(dash) lc(black) ) tlabel(-15.253 , add labsize(*.75)) // 我基准回归的值为-15.253 * 删除临时文件 * forvalue i=1/loop_time{ erase placebo`i'.dta } save 123.dta,replace

    代码不是我原创,是我根据Stata如何做1000次安慰剂检验改编,可能会更适合DID。

    References https://zhuanlan.zhihu.com/p/136685666 https://zhuanlan.zhihu.com/p/53906368 coefplot官方文档

    Processed: 0.009, SQL: 8