# What dummy variables to set for US state-and-year Differences-in-Differences model

As a sort of personal experiment, I'm trying to run a differences-in-differences (DiD) model on US state-level firearms restrictions and violent crime, to see if changes in the former impact the latter. It is inspired largely by a model shown in Mastering 'Metrics (by Angrist and Pischke), on state-level minimum legal drinking age laws and fatalities among young people. I'm more interested in the experience coding up the model than what the result is. I'm using Python 3 for this - primarily the pandas and statsmodels packages.

The regression model is essentially:

Violent_Crime ~ Intercept + Gun_Control_Index + State_FE + Year_FE + State * Year_FE + Error


Where State_FE represent state fixed effects, Year_FE represents year fixed effects (for all but one state/year), and State*Year_FE is an interaction of the state and year fixed effects.

According to Angrist & Pischke, the same trends assumption of DiD models can be relaxed due to the State*Year interaction, which controls for differing trends:

"In models that control for state-specific trends, evidence for [variable of interest] effects comes from sharp deviations from otherwise smooth trends, even where the trends are not common." (Mastering 'Metrics, p. 197)

My problem is that with a sample of 50 states observed over 16 years ($$N \times T$$ = 800) the state, year, and interaction variables put my number of columns well over 800, wiping out the degrees of freedom and making the model impossible.

An example of what my dataset looks like is the following:

Before breaking into dummy columns:

    year    state   violent_crime_100k  murder_manslaughter_100k    agg_assault_100k    property_crime_total_100k   gun_control_index   state_year
0   2001    ALABAMA 438.182717  8.480811    274.115937  3876.849667 0.082707    ALABAMA 2001
2   2001    ARIZONA 540.327562  7.537263    337.085257  5537.514278 0.097744    ARIZONA 2001
3   2001    ARKANSAS    452.369802  5.492267    332.838782  3677.814731 0.097744    ARKANSAS 2001
4   2001    CALIFORNIA  615.214311  6.375637    393.309766  3277.959026 0.646617    CALIFORNIA 2001


After breaking into dummies:

    violent_crime_100k  murder_manslaughter_100k    agg_assault_100k    property_crime_total_100k   gun_control_index   state_ALABAMA   state_ALASKA    state_ARIZONA   state_ARKANSAS  state_CALIFORNIA    ... state_year_WYOMING 2007 state_year_WYOMING 2008 state_year_WYOMING 2009 state_year_WYOMING 2010 state_year_WYOMING 2011 state_year_WYOMING 2012 state_year_WYOMING 2013 state_year_WYOMING 2014 state_year_WYOMING 2015 state_year_WYOMING 2016
0   438.182717  8.480811    274.115937  3876.849667 0.082707    1   0   0   0   0   ... 0   0   0   0   0   0   0   0   0   0
1   589.460726  6.155012    423.117592  3655.129965 0.052632    0   1   0   0   0   ... 0   0   0   0   0   0   0   0   0   0
2   540.327562  7.537263    337.085257  5537.514278 0.097744    0   0   1   0   0   ... 0   0   0   0   0   0   0   0   0   0
3   452.369802  5.492267    332.838782  3677.814731 0.097744    0   0   0   1   0   ... 0   0   0   0   0   0   0   0   0   0
4   615.214311  6.375637    393.309766  3277.959026 0.646617    0   0   0   0   1   ... 0   0   0   0   0   0   0   0   0   0


The actual model data frame will have the various crime columns separated for use as dependent variables, but the remaining columns are set. Of course, in Python statsmodels this gets a failed result, because there are more columns than rows. Here are some screenshots of the statsmodels output:

What do I have wrong here? I assume I screwed up the dummy variables. My input actually has dummies for all 16 years, all 50 states, and the 16*50 interactions, but even if it was 15 years, 49 states, 15*49 interactions, and the variable of interest, we'd be at 800 columns.

• Welcome. I think what you want is a state-specific linear time trend. Just curious but do you observe any entities within states? Commented May 20, 2021 at 0:07
• @ThomasBilach No entities observed within states - the only entities are the states themselves. So should I just use the state*year interaction variables, and skip the state and year fixed effects? Commented May 20, 2021 at 2:14

Incorporating state-specific time trends is not equivalent to including state-year effects. The former gives each state its own unique time trend. In practice this amounts to multiplying each state dummy with a continuous linear (quadratic) time index. The latter multiplies each state effect with a separate year indicator which, as you correctly noted, chews up all your degrees of freedom.

The authors you cite recommend the former approach. In particular, they recommend including state-specific linear time trends, though higher-order trends may also be used. Note that this is not a state-year effect; appending each state-year dummy to your data frame is not appropriate, not to mention inefficient.

The data frame needs one continuous time trend variable: $$t = 1, 2, 3, ..., 16$$. It should exhibit the same pattern within each state. I reproduced an abridged version of your data frame below using fake data. The purpose is to illustrate the pattern of the linear time trend variable. See the variable time appended at the end of your data frame.

    year  state    violent  gun_control  time
0   2001  ALABAMA  228.23   0.07         1
1   2002  ALABAMA  287.64   0.05         2
2   2003  ALABAMA  340.76   0.08         3
3   2004  ALABAMA  372.35   0.09         4
4   2005  ALABAMA  318.28   0.07         5
... ...   ...      ...      ...          ...
15  2016  ALABAMA  214.29   0.06         16
16  2001  ARIZONA  228.23   0.07         1
17  2002  ARIZONA  227.64   0.06         2
18  2003  ARIZONA  312.76   0.07         3
19  2004  ARIZONA  262.42   0.08         4
20  2005  ARIZONA  228.28   0.07         5
... ...   ...      ...      ...          ...
31  2016  ARIZONA  251.38   0.07         16


To include state-specific linear time trends, simply multiply each state effect with time. To be clear, your model should include state fixed effects, year fixed effects, the policy variable(s), and the interaction of each state dummy with a continuous time trend variable. The result is 50 additional parameters including the linear time trend variable, which is a lot less than the 800 state-year effects you were estimating.

The statsmodels module supports R-style formulas. The C() operator is useful when working with categorical variables. I'm not sure what your final model looks like, but here is something to get you going.

smf.ols(formula = 'crime ~ time * C(state) + C(state) + C(year) + treatment + covariates', data = df)

• Thank you so much! I was very confused with the state trends. When you pointed out it was state linear trends I figured it out in the shower. This is a huge help. I'll probably stick with the R-style formulas, including the C() method for categories. With this and some work on the clustered standard errors done, the model is running well. I can't emphasize enough how big a help this was! Commented May 20, 2021 at 19:45
• No problem. Don't work harder than you have to. Simply multiply the continuous linear time trend variable with the state (unit) dummies—all of them. If the coefficient on your policy variable is unaffected by the inclusion of these trends, then this is good news for you. Sometimes it may completely absorb your treatment effect, which is disappointing. Including state-specific linear and quadratic time trends may be appropriate as well. Going beyond a quadratic term is overkill in my estimation, so don't overdo it. Commented May 21, 2021 at 4:40