Skip to main content

did-had

A Python implementation of the Heterogeneous Adoption Design (HAD) estimator for difference-in-differences analysis from de Chaisemartin et al. (2025). Computes heterogeneity-robust DID estimators, in heterogeneous adoption designs where all groups start receiving heterogeneous treatment doses at the same date and no group remains fully untreated. In such designs, all groups experience their first treatment change at the same date (there are no stayers), so _stat and _dyn cannot be used.

PyPI version Python 3.8+ License: MIT

Overview

The did-had package implements the HAD estimator for settings where:

  • All groups receive treatment but with different intensities (no pure control group)
  • Treatment adoption occurs at the same time for all groups, but doses vary
  • Some groups have treatment doses close to zero, serving as "quasi-untreated" groups

This is a Python port of the official Stata package did_had, producing numerically identical results.

Installation

pip install nprobust
pip install did-had

Quick Start

import pandas as pd
from did_had import DidHad

# Load your panel data
df = pd.read_stata("tutorial_data.dta")

# Create and fit the model
model = DidHad(kernel="tri")
results = model.fit(
    df=df,
    outcome="y",        # outcome variable
    group="g",          # group identifier
    time="t",           # time period
    treatment="d",      # treatment dose
    effects=5,          # post-treatment periods
    placebo=4           # pre-treatment placebos
)

# View results
print(results)

# Get ATT
print(f"Average Treatment Effect: {results.att():.4f}")

# Save results
model.save_results("results.csv", format="csv")

Example Output

===========================================================================
DID-HAD Estimation Results
===========================================================================
Number of groups: 1,000
Number of periods: 10
Adoption period (F): 6.0
Kernel: tri
Confidence level: 95%

---------------------------------------------------------------------------
                          Effect Estimates                      QUG* Test
         --------------------------------------------------- ---------------
          Estimate       SE     LB.CI     UB.CI     N      BW    N.BW        T    p.val
Effect_1   4.28198  0.55814   2.71751   4.90538 1,000 0.36133    371  3.96182  0.20154
Effect_2   3.59260  0.66675   2.02563   4.63925 1,000 0.27104    282  3.96182  0.20154
Effect_3   4.25466  0.67544   2.71354   5.36123 1,000 0.31407    324  3.96182  0.20154
...

Features

  • Exact replication of Stata's did_had command
  • Bias-corrected inference using local polynomial regression (lprobust-style)
  • Quasi-untreated group tests to validate the estimation strategy
  • Event-study plots for visualization
  • Multiple output formats: CSV, Stata, Excel, pickle

API Reference

DidHad Class

DidHad(kernel="epa", alpha=0.05, nnmatch=3)

Parameters:

  • kernel: Kernel function - "epa" (Epanechnikov), "tri" (triangular), "uni" (uniform), "gau" (Gaussian)
  • alpha: Significance level for confidence intervals (default: 0.05 for 95% CI)
  • nnmatch: Number of nearest neighbors for variance estimation

fit() Method

results = model.fit(
    df,                      # Panel DataFrame
    outcome,                 # Outcome variable name
    group,                   # Group identifier name
    time,                    # Time period name
    treatment,               # Treatment dose name
    effects=1,               # Number of post-treatment periods
    placebo=0,               # Number of pre-treatment placebos
    dynamic=False,           # Use cumulative treatment dose
    bandwidth=None,          # Global bandwidth (or Silverman if None)
    bandwidth_effect=None,   # Effect-specific bandwidths (dict or scalar)
    bandwidth_placebo=None   # Placebo-specific bandwidths (dict or scalar)
)

DidHadResults Object

results.summary()           # Formatted summary string
results.to_dataframe()      # Full results as DataFrame
results.att()               # Average treatment effect on treated
results.effects             # DataFrame of effect estimates
results.placebos            # DataFrame of placebo estimates

Plotting

# Basic plot
model.plot()

# Customized plot
model.plot(
    figsize=(10, 6),
    title="My Event Study",
    xlabel="Periods since treatment",
    ylabel="Treatment Effect",
    show_ci=True
)

Saving Results

model.save_results("results.csv", format="csv")
model.save_results("results.dta", format="stata")
model.save_results("results.xlsx", format="excel")
model.save_results("results.pkl", format="pickle")

Comparison with Stata

This package produces numerically identical results to the official Stata did_had command when using the same bandwidths:

Estimate Python Stata Match
Effect_1 4.28198 4.28198 Yes
Effect_2 3.59260 3.59260 Yes
Effect_3 4.25466 4.25466 Yes
... ... ... ...

Requirements

  • Python >= 3.8
  • NumPy >= 1.20.0
  • Pandas >= 1.3.0
  • Matplotlib >= 3.4.0 (optional, for plotting)

References

  • de Chaisemartin, C., D'Haultfoeuille, X., Pasquier, F., & Vazquez-Bare, G. (2025). "Difference-in-Differences Estimators for Treatments Continuously Distributed at Every Period". SSRN

  • Calonico, S., Cattaneo, M. D., & Farrell, M. H. (2019). "nprobust: Nonparametric Kernel-Based Estimation and Robust Bias-Corrected Inference". Journal of Statistical Software.

License

MIT License. See LICENSE for details.

Contributing

Contributions are welcome! Please open an issue or submit a pull request on GitHub.

Metadata

Release files for did-had 0.2.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for did-had 0.2.1
File Size Uploaded
did_had-0.2.1.tar.gz 21.2 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for did-had 0.2.1
File Interpreter ABI Platform
did_had-0.2.1-py3-none-any.whl Python 3 none any Details

Total release size: 38.1 kB

Release files / did_had-0.2.1.tar.gz

Download URL did_had-0.2.1.tar.gz
Size 21.2 kB
Tags Source
SHA-256 checksum
How to use checksums
a4c373debe8f3bf4e46fff85567731c04696f6a1b99cfc5de8343af4a95b85d7
BLAKE2b-256 checksum
How to use checksums
d5caaa9416a181ed05edefdfe44b8496ff4a747375f30ccee0d42ad59d98d591
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Apr 27, 2026.

Transparency log

Release files / did_had-0.2.1-py3-none-any.whl

Download URL did_had-0.2.1-py3-none-any.whl
Size 16.9 kB
Tags Python 3
SHA-256 checksum
How to use checksums
57bda67e18c2c6265e82f46770f9bf6975d36aa1c3dda6bdc3280a1b18c9907e
BLAKE2b-256 checksum
How to use checksums
06ac8191403a5a98db3ca3b7a6cd64a5f0fac76bfe6bc1105aa084c9fa8527ac
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Apr 27, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.2.1 This release

2 release files

0.2.0

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page