Skip to main content

Modern difference-in-differences estimators.

Project description

moderndid logo moderndid logo

Ruff Project Status: Active – The project has reached a stable, usable state and is being actively developed. Build Status Code Coverage Documentation Last commit Commit activity Python version

moderndid is a unified Python implementation of modern difference-in-differences (DiD) methodologies, bringing together the fragmented landscape of DiD estimators into a single, coherent framework. This package consolidates methods from leading econometric research and various R packages into one comprehensive Python library with a consistent API.

[!WARNING] This package is currently in active development with core estimators and some sensitivity analysis implemented. The API is subject to change.

Installation

uv pip install moderndid

Or install from source:

uv pip install git+https://github.com/jordandeklerk/moderndid.git

Features

  • Multiple DiD estimators — Staggered adoption, doubly robust, continuous treatment, triple difference, and sensitivity analysis
  • Fast computationPolars for data wrangling, NumPy vectorization, and Numba JIT compilation for performance-critical paths
  • Native plots — Built on plotnine with full customization support
  • Robust inference — Analytical standard errors, bootstrap (weighted and multiplier), and simultaneous confidence bands
  • Documentationhttps://moderndid.readthedocs.io/en/latest/index.html

Consistent API

All estimators share a unified interface, making it easy to switch between methods:

# Staggered DiD
result = did.att_gt(data, yname="y", tname="t", idname="id", gname="g", ...)

# Triple DiD
result = did.ddd(data, yname="y", tname="t", idname="id", gname="g", pname="p", ...)

# Continuous DiD
result = did.cont_did(data, yname="y", tname="t", idname="id", gname="g", dname="dose", ...)

# Doubly robust 2-period DiD
result = did.drdid(data, yname="y", tname="t", idname="id", treatname="treat", ...)

Example Datasets

Several classic datasets from the DiD literature are included for learning and experimentation:

did.load_mpdta()  # County teen employment (staggered adoption)
did.load_nsw()    # NSW job training program (2-period panel)
did.load_ehec()   # Medicaid expansion (sensitivity analysis)
did.load_engel()  # Household expenditure (continuous treatment)

Quick Start

This example uses county-level teen employment data to estimate the effect of minimum wage increases. States adopted higher minimum wages at different times (2004, 2006, or 2007), making this a staggered adoption design.

import moderndid as did

# County teen employment data
data = did.load_mpdta()

# Estimate group-time average treatment effects
result = did.att_gt(
    data=data,
    yname="lemp",
    tname="year",
    idname="countyreal",
    gname="first.treat",
    est_method="dr",
)
print(result)

The output shows treatment effects for each group (defined by when they were first treated) at each time period:

Reference: Callaway and Sant'Anna (2021)

Group-Time Average Treatment Effects:
  Group   Time   ATT(g,t)   Std. Error    [95% Simult.  Conf. Band]
   2004   2004    -0.0105       0.0232    [ -0.0743,   0.0533]
   2004   2005    -0.0704       0.0319    [ -0.1582,   0.0173]
   2004   2006    -0.1373       0.0356    [ -0.2352,  -0.0394] *
   2004   2007    -0.1008       0.0331    [ -0.1918,  -0.0098] *
   2006   2004     0.0065       0.0241    [ -0.0597,   0.0727]
   2006   2005    -0.0028       0.0202    [ -0.0582,   0.0527]
   2006   2006    -0.0046       0.0179    [ -0.0538,   0.0446]
   2006   2007    -0.0412       0.0211    [ -0.0992,   0.0167]
   2007   2004     0.0305       0.0145    [ -0.0095,   0.0705]
   2007   2005    -0.0027       0.0173    [ -0.0502,   0.0448]
   2007   2006    -0.0311       0.0190    [ -0.0833,   0.0211]
   2007   2007    -0.0261       0.0168    [ -0.0721,   0.0200]
---
Signif. codes: '*' confidence band does not cover 0

P-value for pre-test of parallel trends assumption:  0.1681

Control Group:  Never Treated,
Anticipation Periods:  0
Estimation Method:  Doubly Robust

These group-time effects can be aggregated into an event study to see how effects evolve relative to treatment:

event_study = did.aggte(result, type="dynamic")
print(event_study)
==============================================================================
Aggregate Treatment Effects (Event Study)
==============================================================================

Call:
  aggte(MP, type='dynamic')

Overall summary of ATT's based on event-study/dynamic aggregation:

      ATT      Std. Error     [95% Conf. Interval]
  -0.0772          0.0214     [-0.1191, -0.0353] *


Dynamic Effects:

    Event time   Estimate   Std. Error   [95% Simult. Conf. Band]
            -3     0.0305       0.0151   [-0.0084,  0.0694]
            -2    -0.0006       0.0132   [-0.0346,  0.0335]
            -1    -0.0245       0.0139   [-0.0602,  0.0113]
             0    -0.0199       0.0120   [-0.0508,  0.0109]
             1    -0.0510       0.0172   [-0.0951, -0.0068] *
             2    -0.1373       0.0371   [-0.2326, -0.0419] *
             3    -0.1008       0.0352   [-0.1912, -0.0104] *

------------------------------------------------------------------------------
Signif. codes: '*' confidence band does not cover 0

Control Group: Never Treated
Anticipation Periods: 0
Estimation Method: Doubly Robust
==============================================================================

We can also use built-in plotting functionality to plot the event study results:

did.plot_event_study(event_study)
Event study plot

Available Methods

Each core module includes a dedicated walkthrough covering methodology background, API usage, and guidance on interpreting results.

Core Implementations

Module Description Reference
moderndid.did Staggered DiD with group-time effects Callaway & Sant'Anna (2021)
moderndid.drdid Doubly robust 2-period estimators Sant'Anna & Zhao (2020)
moderndid.didhonest Sensitivity analysis for parallel trends Rambachan & Roth (2023)
moderndid.didcont Continuous/multi-valued treatments Callaway et al. (2024)
moderndid.didtriple Triple difference-in-differences Ortiz-Villavicencio & Sant'Anna (2025)

Planned Development

Module Description Reference
moderndid.didinter Intertemporal DiD with non-absorbing treatment Chaisemartin & D'Haultfœuille (2024)
moderndid.didml Machine learning approaches to DiD Hatamyar et al. (2023)
moderndid.drdidweak Robust to weak overlap Ma et al. (2023)
moderndid.didcomp Compositional changes in repeated cross-sections Sant'Anna & Xu (2025)
moderndid.didimpute Imputation-based estimators Borusyak, Jaravel, & Spiess (2024)
moderndid.didbacon Goodman-Bacon decomposition Goodman-Bacon (2019)
moderndid.didlocal Local projections DiD Dube et al. (2025)
moderndid.did2s Two-stage DiD Gardner (2021)
moderndid.etwfe Extended two-way fixed effects Wooldridge (2021), Wooldridge (2023)
moderndid.functional Specification tests Roth & Sant'Anna (2023)

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

moderndid-0.0.2.tar.gz (576.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

moderndid-0.0.2-py3-none-any.whl (714.1 kB view details)

Uploaded Python 3

File details

Details for the file moderndid-0.0.2.tar.gz.

File metadata

  • Download URL: moderndid-0.0.2.tar.gz
  • Upload date:
  • Size: 576.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for moderndid-0.0.2.tar.gz
Algorithm Hash digest
SHA256 8eca295109e52d15a2e6e9691624d1723225a262605193d9a3bb572256eca3f1
MD5 7757830e5741df1c05c75a62dcf5dca9
BLAKE2b-256 039e04a98af3500377d527ab4c35cd174bc7e6bb59dbcab8339f3a482687723c

See more details on using hashes here.

Provenance

The following attestation bundles were made for moderndid-0.0.2.tar.gz:

Publisher: publish.yml on jordandeklerk/moderndid

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file moderndid-0.0.2-py3-none-any.whl.

File metadata

  • Download URL: moderndid-0.0.2-py3-none-any.whl
  • Upload date:
  • Size: 714.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for moderndid-0.0.2-py3-none-any.whl
Algorithm Hash digest
SHA256 f341b72e70cc7c353a33d6e4aae70ca8429d6ed6a05664a8763a7bb68b5670f3
MD5 f37cd5278b034339f7470aebe7835914
BLAKE2b-256 5ca663e064d2cfce26056119ed5460233ebffb980ba8a6084b78127b78f36bc7

See more details on using hashes here.

Provenance

The following attestation bundles were made for moderndid-0.0.2-py3-none-any.whl:

Publisher: publish.yml on jordandeklerk/moderndid

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page