8.9 The \(2 \times 2\) Difference-in-Differences Estimate

Now that we’ve disscussed the difference-in-differences framework (mostly canonical DiD), we would like to look at various ways of estimating DiD. As we’ve seen, (a canonical) DiD estimation can simply be done non-parametrically by using the appropriate differences in means. Another way to do it is by using the regression framework, which provides several advantages including but not limited to: \(i)\) estimation of standard errors; \(ii)\) ease of accounting for necessary covariates; and \(iii)\) feasible estimation of DiD with multiple treatment groups with staggered treatment.

Let’s begin with the canonical DiD framework using the regression format. I’m going to set it up as the following:

\[\begin{equation} \label{eq:DiD_reg} Y_{it} = \alpha + \tau Post_{it} \times D_{i} + \sigma Post_{it} + \eta D_{i} + \epsilon_{it} \end{equation}\]

Let’s rewrite the DiD estimator from before as:

\(\tau_{did} = \underbrace{E[Y_{11} - Y_{10} | D = 1]}_{first\; difference} - \underbrace{E[Y_{01} - Y_{00} | D = 0]}_{second\; difference}\)

We’d want to see whether estimation of \(\tau\) in the regression above uncovers the DiD estimate. Let’s look at the following conditional expectations.

1). expected outcome for treated group post treatment: \(E(Y | D = 1, Post = 1) = \alpha + \tau + \sigma + \eta\)

2). expected outcome for treated group pre treatment: \(E(Y | D = 1, Post = 0) = \alpha + \eta\)

3). expected outcome for control group post treatment: \(E(Y | D = 0, Post = 1) = \alpha + \sigma\)

4). expected outcome for control group pre treatment: \(E(Y | D = 0, Post = 0) = \alpha\)

If you do the math, the first difference is given as \(\tau + \sigma\) and the second difference is \(\sigma\). The DiD – the difference between the first and the second difference – is \(\tau\). Hence, the estimation of \(\tau\), in the regression framework above, is the DiD estimate.

Let’s apply this to our ACA-Medicaid example.

# lets create the post, treat, and the interaction between the post and treat (labeled as did)
dat_canonical  <- dat_canonical  %>% 
                      mutate(post = ifelse(year >= 2014, 1, 0), 
                             treat = ifelse(expand == 1, 1, 0), 
                             did = post * treat)

reg_did  <- lm(sahieunins138 ~ did + post + treat, data = dat_canonical)
summary(reg_did)
## 
## Call:
## lm(formula = sahieunins138 ~ did + post + treat, data = dat_canonical)
## 
## Residuals:
##      Min       1Q   Median       3Q      Max 
## -25.0767  -5.0184  -0.7184   4.7586  27.0540 
## 
## Coefficients:
##             Estimate Std. Error t value Pr(>|t|)    
## (Intercept)  41.1460     0.1931  213.08   <2e-16 ***
## did          -5.7538     0.4172  -13.79   <2e-16 ***
## post         -4.8046     0.2732  -17.59   <2e-16 ***
## treat        -7.6693     0.2946  -26.04   <2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 7.464 on 5224 degrees of freedom
## Multiple R-squared:  0.4322, Adjusted R-squared:  0.4319 
## F-statistic:  1326 on 3 and 5224 DF,  p-value: < 2.2e-16
did  <- naive - naive_pre
print(did)
## [1] -5.7538

Note that the difference in mean did and the regression coefficient on the interaction between \(Post \times treat\) are the same. Plus, we get the standard errors as well. Of course, the standard errors are not adjusted for clustering. The errors of observations within a cluster (the ground at which the treatment is implemented, in our case state) will be correlated, so we need to account for it. The way to do it is to cluster the standard error at the state level. This can be done using the fixest library and feols command.

reg_did_cluster  <- feols(sahieunins138 ~ did + post + treat, data = dat_canonical, cluster = ~state.abb)
summary(reg_did_cluster)
## OLS estimation, Dep. Var.: sahieunins138
## Observations: 5,228
## Standard-errors: Clustered (state.abb) 
##             Estimate Std. Error   t value   Pr(>|t|)    
## (Intercept) 41.14598   1.871204  21.98904  < 2.2e-16 ***
## did         -5.75380   1.320435  -4.35750 0.00008033 ***
## post        -4.80456   0.280312 -17.14003  < 2.2e-16 ***
## treat       -7.66925   2.502144  -3.06507 0.00375138 ** 
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## RMSE: 7.46094   Adj. R2: 0.431902

Note that the did coefficient remains unchanged. However, the standard error is inflated after clustering the errors at the state level.