双向固定效应(TWFE)模型

目录

  1. 经典的2x2 DiD或双向固定效应模型(TWFE)
  2. 三重差分估计量(DDD)
  3. 通用TWFE函数形式
  4. Stata代码
  5. 添加更多时间段
  6. 更多单位,相同处理时间,不同处理效应
  7. 更多单位,差异处理时间,不同处理效应

经典的2x2 DiD或双向固定效应模型(TWFE)

未完成

让我们从经典的双向固定效应(TWFE)模型开始:

\[y_{it} = \beta_0 + \beta_1 Treat_i + \beta_2 Post_t + \beta_3 Treat_i Post_t + \epsilon_{it}\]

上述2x2模型可以用以下表格来解释:

  处理组 = 0 处理组 = 1 差异
后处理 = 0 \(\beta_0\) \(\beta_0 + \beta_1\) \(\beta_1\)
后处理 = 1 \(\beta_0 + \beta_2\) \(\beta_0 + \beta_1 + \beta_2 + \beta_3\) \(\beta_1 + \beta_3\)
差异 \(\beta_2\) \(\beta_2 + \beta_3\) \(\beta_3\)

三重差分估计量(DDD)

未完成

三重差分估计量本质上采用两个DD,一个针对目标分析单位,包含处理组和未处理组。这与另一个在前后处理期间类似的组进行比较。因此实际上有两个处理。一个是对期望组的实际处理进行测试,另一个是对安慰剂比较组应用相同的干预。

\[y_{it} = \beta_0 + \beta_1 P_{i} + \beta_2 C_{j} + \beta_3 T_t + \beta_4 (P_i T_t) + \beta_5 (C_j T_t) + \beta_6 (P_i C_j) + \beta_7 (P_i C_j T_t) + \epsilon_{it}\]

其中我们有3x3组合:P = {0,1}, T={0,1}, C={0,1}。与2x2 DD的情况一样,这里感兴趣的系数是 \(\beta_7\)。这也可以用表格形式分解。但与其创建一个大表格,结果通常表示为C = 0,或主要处理组,以及C = 1,或主要比较组。两者之间的差异归结为 \(\beta_7\)。让我们在这里看到:

主要组(\(C = 0\)):

  T = 0 T = 1 差异
P = 0 \(\beta_0\) \(\beta_0 + \beta_3\) \(\beta_3\)
P = 1 \(\beta_0 + \beta_1\) \(\beta_0 + \beta_1 + \beta_3 + \beta_4\) \(\beta_3 + \beta_4\)
差异 \(\beta_1\) \(\beta_1 + \beta_4\) \(\beta_4\)

比较组(\(C = 1\)):

  T = 0 T = 1 差异
P = 0 \(\beta_0 + \beta_2\) \(\beta_0 + \beta_2 + \beta_3 + \beta_5\) \(\beta_3 + \beta_5\)
P = 1 \(\beta_0 + \beta_1 + \beta_2 + \beta_6\) \(\beta_0 + \beta_1 + \beta_2 + \beta_3 + \beta_4 + \beta_5 + \beta_6 + \beta_7\) \(\beta_3 + \beta_4 + \beta_5 + \beta_7\)
差异 \(\beta_1 + \beta_6\) \(\beta_1 + \beta_4 + \beta_6 + \beta_7\) \(\beta_4 + \beta_7\)

让我们取两个矩阵的差异或(C = 1) - (C = 0):

  T = 0 T = 1 差异
P = 0 \(\beta_2\) \(\beta_2 + \beta_5\) \(\beta_5\)
P = 1 \(\beta_2 + \beta_6\) \(\beta_2 + \beta_5 + \beta_6 + \beta_7\) \(\beta_5 + \beta_7\)
差异 \(\beta_6\) \(\beta_6 + \beta_7\) \(\beta_7\)

最终得到主要差异 \(\beta_7\)。注意,这种表格逻辑也比为每个组合定义一长串期望要简单得多。

通用TWFE函数形式

未完成

如果我们有多个时间段和处理单位,经典的2x2 DiD可以扩展到以下通用函数形式:

\[y_{it} = \alpha_{i} + \alpha_t + \beta^{TWFE} D_{it} + \epsilon_{it}\]

Stata代码

让我们在Stata中生成一个简单的2x2示例。第一步定义面板结构。由于是2x2,我们只需要两个单位和两个时间段:

clear
local units = 2
local start = 1
local end   = 2

local time = `end' - `start' + 1
local obsv = `units' * `time'
set obs `obsv'

egen id	   = seq(), b(`time')  
egen t 	   = seq(), f(`start') t(`end') 	

sort id t
xtset id t

lab var id "面板变量"
lab var t  "时间变量"

接下来我们定义处理组和一个不添加任何变化或误差项的通用TWFE模型:

gen D = id==2 & t==2

gen btrue = cond(D==1, 2, 0) 		
	gen Y = id + 3*t + btrue*D 

根据最后一行,处理效应应该对后处理组的Y产生3个单位的影响。我们可以通过绘制数据来检查这一点:

lab de prepost 1 "前" 2 "后"
lab val t prepost

twoway ///
	(connected Y t if id==1) ///
	(connected Y t if id==2) ///
		,	///
		legend(order(1 "id=1" 2 "id=2")) ///
		xlabel(1 2, valuelabel) ylabel(4(1)10)

这给了我们:

我们可以看到,在后处理期间,蓝线和橙线之间的差异是3,在前处理期间是1,净增长为2个单位。这也等于我们指定的处理量。

我们也可以通过简单的面板回归来恢复这一点:

xtset id t
xtreg Y D t, fe

在回归中,你会看到D的系数,\(\beta^{TWFE}\) = 2,如预期的那样。另一种方法是使用reghdfe包,我们稍后也会在其他示例中调用:

reghdfe Y D, absorb(id t)

这再次给了我们D系数的相同结果。


添加更多时间段

现在我们熟悉了2x2示例,让我们添加更多时间段。每个单位10个怎么样:

clear
local units = 2
local start = 1
local end 	= 10

local time = `end' - `start' + 1
local obsv = `units' * `time'
set obs `obsv'

egen id	   = seq(), b(`time')  
egen t 	   = seq(), f(`start') t(`end') 	

sort  id t
xtset id t

lab var id "面板变量"
lab var t  "时间变量"

我们只是做一个简单的处理,其中id=2在第5个时间段增加3个单位并保持在那里:

gen D = id==2 & t>=5
lab var D "已处理"

gen btrue = cond(D==1, 3, 0) 		

gen Y = id + t +  btrue*D 
lab var Y "结果变量"

我们也可以将其可视化如下:

我们也可以运行Stata代码:

xtreg Y D t, fe
reghdfe Y D, absorb(id t)   

xtreg选项显示\(t\)平均增加1个单位,这是我们期望的。截距等于1.5,这是如果蓝线和橙线外推到\(t = 0\)点的平均值。而\(\beta^{TWFE}\) = 3,干预效应的真实值。


更多单位,相同处理时间,不同处理效应

让我们从一个非常简单的案例开始,我们有一个对照组,两个处理组。两个T组在同一时间接受处理,但处理强度不同:

clear
local units = 3
local start = 1
local end 	= 10

local time = `end' - `start' + 1
local obsv = `units' * `time'
set obs `obsv'

egen id	   = seq(), b(`time')  
egen t 	   = seq(), f(`start') t(`end') 	

lab var id "面板变量"
lab var t  "时间变量"

sort  id t
xtset id t


gen D = 0
replace D = 1 if id>=2 & t>=5
lab var D "已处理"

cap drop Y
gen Y = 0
replace Y = cond(D==1, 2, 0) if id==2
replace Y = cond(D==1, 4, 0) if id==3

lab var Y "结果变量"	

并绘制它:

twoway ///
	(connected Y t if id==1) ///
	(connected Y t if id==2) ///
	(connected Y t if id==3) ///
		,	///
		xline(4.5) ///
		xlabel(1(1)10) ///
		legend(order(1 "id=1" 2 "id=2" 3 "id=3"))	

从中我们得到:

这里我们可以看到后处理对id=2的平均效应为2,对id=3为4。这意味着ATT等于\(\beta^{TWFE}\)=3,我们也可以通过恢复系数来检查:

xtreg Y D t, fe 

虽然在这里检查平均处理效应很容易,因为它们没有时间或面板固定效应,我们基本上可以直观地看到结果是如何变化的。但如果我们添加控制变量,它会变得有点复杂。让我们一次性生成代码:

clear
local units = 3
local start = 1
local end 	= 10

local time = `end' - `start' + 1
local obsv = `units' * `time'
set obs `obsv'

egen id	   = seq(), b(`time')  
egen t 	   = seq(), f(`start') t(`end') 	

sort  id t
xtset id t

lab var id "面板变量"
lab var t  "时间变量"

gen D = 0
replace D = 1 if id>=2 & t>=5
lab var D "已处理"

cap drop Y
gen Y = 0
replace Y = id + t + cond(D==1, 0, 0) if id==1
replace Y = id + t + cond(D==1, 2, 0) if id==2
replace Y = id + t + cond(D==1, 4, 0) if id==3

lab var Y "结果变量"		

twoway ///
	(connected Y t if id==1) ///
	(connected Y t if id==2) ///
	(connected Y t if id==3) ///
		,	///
		xline(4.5) ///
		xlabel(1(1)10) ///
		legend(order(1 "id=1" 2 "id=2" 3 "id=3"))	

从之前的示例中,我们知道ATT等于\(\beta^{TWFE}\)=3,但从图表中我们不能这么清楚地看到这一点。这是因为我们需要去除面板和id时间趋势。虽然我们也可以手动进行部分剔除(但我们不会),我们可以使用我们的回归规范:

xtreg Y D t, fe 

这给出了ATT=3,这是两个处理变量的平均值。

在这里,我想补充一点,平行趋势假设在上述回归规范中得到了控制。如果没有考虑到这些,那么我们基本上会得到错误的ATT。我们可以在以下回归中看到D系数:

reg Y D				// 不控制任何效应
reg Y D i.t			// 仅时间固定效应
reg Y D i.id		// 仅面板固定效应
reg Y D i.t i.id	// 面板和时间固定效应(正确!)

更多单位,差异处理时间,不同处理效应

现在让我们进入最后一部分:具有差异时间的处理。这里我们再次生成一个虚拟数据集,但现在去除面板和时间固定效应。正如我们在上面看到的,回归隔离了面板固定效应,我们恢复了感兴趣的系数\(\beta^{TWFE}\)。

clear
local units = 3
local start = 1
local end 	= 10

local time = `end' - `start' + 1
local obsv = `units' * `time'
set obs `obsv'

egen id	   = seq(), b(`time')  
egen t 	   = seq(), f(`start') t(`end') 	

sort  id t
xtset id t

lab var id "面板变量"
lab var t  "时间变量"

gen D = 0
replace D = 1 if id==2 & t>=5
replace D = 1 if id==3 & t>=8
lab var D "已处理"

gen Y = 0
replace Y = D * 2 if id==2 & t>=5
replace Y = D * 4 if id==3 & t>=8

lab var Y "结果变量"


twoway ///
	(connected Y t if id==1) ///
	(connected Y t if id==2) ///
	(connected Y t if id==3) ///
		,	///
		xline(4.5 7.5) ///
		xlabel(1(1)10) ///
		legend(order(1 "id=1" 2 "id=2" 3 "id=3"))		

这给了我们这个图:

该图显示,组id=2在t=5时获得干预并保持处理状态,而组id=3在t=8时获得干预并保持处理状态。那么这里的ATT是什么?

与之前的示例不同,我们可以通过查看图表来推导ATT,这里并不那么简单。即使没有时间和面板固定效应,处理时间的差异确实使面板和时间的变化变得相关。不深入数学,为了恢复实际的ATT,我们需要对处理和非处理观测值的时间和面板效应进行平均。

我们可以做这些回归来查看结果:

reg Y D				// 不控制任何效应
reg Y D i.t			// 仅时间固定效应
reg Y D i.id		// 仅面板固定效应
reg Y D i.t i.id	// 面板和时间固定效应(正确!)

最后一个回归给了我们正确的ATT,即\(\beta^{TWFE}\) = 2.91。这实际上是在对面板和时间变量进行平均后,\(y_{it}\)的平均增长。

我们也可以使用标准命令来恢复这一点:

xtreg Y D i.t, fe 
reghdfe Y D, absorb(id t)   

这给了我们相同的答案\(\beta^{TWFE}\) = 2.91。

让我们思考一下这个数字。我们有两个在不同时间发生的处理,具有不同的处理效应。因此前后处理的定义不再清楚。未处理与已处理也不清楚。如果我们看区间\(5\leq t < 8\),只有id=2在变化,其他两个变量是常数。但在最后一个区间,其中\(t \geq 8\),那么只有id=3显示变化,而其他两个面板变量在这个区间是常数(即使id=2在这里被处理)。

正是这些组合在Bacon分解部分中被解开,这就是为什么仔细理解分解很重要。