πŸŽ‰ 75% of content is free forever β€” Unlock Premium from $10/mo β†’
CW
Search courses…
πŸ’Ό Servicesℹ️ Aboutβœ‰οΈ ContactView Pricing Plansfrom $10

Difference-in-Differences Estimation

StatisticsCausal Inference🟒 Free Lesson

Advertisement

Difference-in-Differences Estimation

Statistics

Comparing Changes Over Time Between Treatment and Control

Difference-in-differences estimates causal effects by comparing outcome changes over time between treated and control groups. The parallel trends assumption ensures that without treatment, both groups would have followed the same trajectory.

  • Policy Evaluation β€” Assess minimum wage effects on employment across states

  • Healthcare β€” Evaluate insurance expansions using state-by-state rollout timing

  • Business β€” Measure marketing campaign impact using geographic staggered launches

The double difference β€” in changes, not levels β€” eliminates time-invariant confounders.


Difference-in-Differences (DiD) estimates causal effects by comparing changes in outcomes over time between a treatment group and a control group.


Basic DiD Formula


Parallel Trends Assumption

Testing Parallel Trends

Pre-treatment periods can provide indirect evidence:

  • Plot pre-treatment trends for both groups

  • Test whether pre-treatment differences are stable

  • If pre-treatment trends diverge, the assumption is questionable


Regression Specification


Event Study Design

Extends DiD by estimating dynamic effects β€” how the treatment effect evolves over time.


Staggered Adoption

Many units adopt treatment at different times. Recent research shows that two-way fixed effects (TWFE) can be biased in staggered DiD.

| Method | Problem |

|--------|---------|

| TWFE | Negative weights; can give wrong sign |

| Callaway-Sant'Anna | Robust estimator for staggered DiD |

| Sun-Abraham | Interaction-weighted estimator |

| de Chaisemartin-D'HaultfΕ“uille | robust DiD with heterogeneous effects |


Difference-in-Differences with Covariates

Including covariates can improve precision but is not required for identification.


Python Implementation


import numpy as np

import pandas as pd

import statsmodels.api as sm

import matplotlib.pyplot as plt



np.random.seed(42)



# Simulate DiD data

n_units = 200

n_periods = 10

treated = np.repeat(np.random.binomial(1, 0.5, n_units), n_periods)

time = np.tile(np.arange(n_periods), n_units)

post = (time >= 5).astype(int)

treatment = treated * post



# True effect = 2.0

Y = 5 + 1.5*treated + 0.3*time + 2.0*treatment + np.random.randn(n_units*n_periods)*2



df = pd.DataFrame({'Y': Y, 'treated': treated, 'time': time, 'post': post, 'treatment': treatment})



# Basic DiD

model = sm.OLS.from_formula('Y ~ treated + post + treatment', data=df).fit()

print("Basic DiD:")

print(model.summary().tables[1])



# Event study

event_coefs = []

for k in range(-4, 6):

    if k == -1:

        continue

    df['event_k'] = ((df['time'] - 5) == k) * df['treated']

    model_k = sm.OLS.from_formula('Y ~ C(time) + C(treated) + event_k', data=df).fit()

    event_coefs.append({'k': k, 'coef': model_k.params['event_k'],

                        'se': model_k.bse['event_k']})



event_df = pd.DataFrame(event_coefs)

event_df['ci_lower'] = event_df['coef'] - 1.96*event_df['se']

event_df['ci_upper'] = event_df['coef'] + 1.96*event_df['se']



plt.figure(figsize=(8, 5))

plt.errorbar(event_df['k'], event_df['coef'], 

             yerr=1.96*event_df['se'], fmt='o-', capsize=4)

plt.axhline(y=0, color='gray', linestyle='--', alpha=0.5)

plt.axvline(x=0, color='red', linestyle='--', alpha=0.5)

plt.xlabel('Event Time (relative to treatment)')

plt.ylabel('Treatment Effect')

plt.title('Event Study Plot')

plt.show()


Worked Example


Key Takeaways


Related Topics

Need Expert Statistics Help?

Get personalized tutoring, project support, or professional consulting.

Advertisement