Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .readthedocs.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ version: 2

build:
os: ubuntu-22.04
apt_packages:
- pandoc
tools:
python: "3.11"
jobs:
Expand All @@ -16,7 +18,7 @@ build:
#
# Keep in sync with pyproject.toml [project.dependencies]
# and [project.optional-dependencies.docs].
- pip install "numpy>=1.20.0" "pandas>=1.3.0" "scipy>=1.7.0" "sphinx>=6.0" "sphinx-rtd-theme>=1.0"
- pip install "numpy>=1.20.0" "pandas>=1.3.0" "scipy>=1.7.0" "sphinx>=6.0" "pydata-sphinx-theme>=0.15" "sphinxext-opengraph>=0.9" "sphinx-sitemap>=2.5" "nbsphinx>=0.9" "matplotlib>=3.5"

# Build documentation in the "docs/" directory with Sphinx
sphinx:
Expand Down
27 changes: 27 additions & 0 deletions CITATION.cff
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
cff-version: 1.2.0
title: "diff-diff: Difference-in-Differences Causal Inference for Python"
message: "If you use this software, please cite it as below."
type: software
authors:
- name: "diff-diff contributors"
license: MIT
version: "2.7.1"
date-released: "2026-03-18"
url: "https://github.com/igerber/diff-diff"
repository-code: "https://github.com/igerber/diff-diff"
keywords:
- difference-in-differences
- causal-inference
- econometrics
- python
- treatment-effects
- event-study
- staggered-adoption
- parallel-trends
- synthetic-control
- panel-data
abstract: >-
A Python library for Difference-in-Differences (DiD) causal inference analysis.
Provides sklearn-like estimators for modern DiD methods including
Callaway-Sant'Anna, Synthetic DiD, Honest DiD, event studies, and parallel
trends testing. Validated against R packages (did, synthdid, fixest).
21 changes: 21 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# diff-diff

[![PyPI version](https://img.shields.io/pypi/v/diff-diff.svg)](https://pypi.org/project/diff-diff/)
[![Python versions](https://img.shields.io/pypi/pyversions/diff-diff.svg)](https://pypi.org/project/diff-diff/)
[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)
[![Downloads](https://img.shields.io/pypi/dm/diff-diff.svg)](https://pypi.org/project/diff-diff/)
[![Documentation](https://readthedocs.org/projects/diff-diff/badge/?version=stable)](https://diff-diff.readthedocs.io/en/stable/)

A Python library for Difference-in-Differences (DiD) causal inference analysis with an sklearn-like API and statsmodels-style outputs.

## Installation
Expand Down Expand Up @@ -2909,6 +2915,21 @@ The `HonestDiD` module implements sensitivity analysis methods for relaxing the

- **Cunningham, S. (2021).** *Causal Inference: The Mixtape*. Yale University Press. [https://mixtape.scunning.com/](https://mixtape.scunning.com/)

## Citing diff-diff

If you use diff-diff in your research, please cite it:

```bibtex
@software{diff_diff,
title = {diff-diff: Difference-in-Differences Causal Inference for Python},
author = {{diff-diff contributors}},
url = {https://github.com/igerber/diff-diff},
license = {MIT},
}
```

See [`CITATION.cff`](CITATION.cff) for the full citation metadata.

## License

MIT License
1 change: 1 addition & 0 deletions TODO.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ Deferred items from PR reviews that were not addressed before merge.
| R comparison tests spawn separate `Rscript` per test (slow CI) | `tests/test_methodology_twfe.py:294` | #139 | Low |
| CS R helpers hard-code `xformla = ~ 1`; no covariate-adjusted R benchmark for IRLS path | `tests/test_methodology_callaway.py` | #202 | Low |
| Context-dependent doc snippets pass via blanket NameError; no standalone validation | `tests/test_doc_snippets.py`, `docs/api/visualization.rst`, `docs/python_comparison.rst`, `docs/r_comparison.rst` | #206 | Low |
| ~1,460 `duplicate object description` Sphinx warnings — each class attribute is documented in both module API pages and autosummary stubs; fix by adding `:no-index:` to one location or restructuring API docs to avoid overlap | `docs/api/*.rst`, `docs/api/_autosummary/` | — | Low |

---

Expand Down
5 changes: 0 additions & 5 deletions docs/_static/custom.css
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,6 @@ table.docutils td, table.docutils th {
font-weight: bold;
}

/* Method/function signature styling */
.sig-name {
font-weight: bold;
}

/* Better parameter list styling */
.field-list {
margin-top: 1em;
Expand Down
21 changes: 21 additions & 0 deletions docs/_templates/layout.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{% extends "pydata_sphinx_theme/layout.html" %}
{% block extrahead %}
{{ super() }}
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "SoftwareApplication",
"name": "diff-diff",
"description": "Python library for Difference-in-Differences causal inference analysis with sklearn-like API",
"applicationCategory": "Scientific Software",
"operatingSystem": "Cross-platform",
"programmingLanguage": "Python",
"url": "https://diff-diff.readthedocs.io",
"downloadUrl": "https://pypi.org/project/diff-diff/",
"softwareVersion": "{{ release }}",
"license": "https://opensource.org/licenses/MIT",
"offers": {"@type": "Offer", "price": "0", "priceCurrency": "USD"},
"author": {"@type": "Organization", "name": "diff-diff contributors"}
}
</script>
{% endblock %}
4 changes: 4 additions & 0 deletions docs/benchmarks.rst
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
.. meta::
:description: Validation benchmarks comparing diff-diff against R packages (did, synthdid, fixest). Coefficient accuracy, standard error comparison, and performance metrics.
:keywords: difference-in-differences benchmark, DiD validation R, python econometrics accuracy, did package comparison

Benchmarks: Validation Against R Packages
=========================================

Expand Down
4 changes: 4 additions & 0 deletions docs/choosing_estimator.rst
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
.. meta::
:description: Guide to choosing the right Difference-in-Differences estimator. Covers basic DiD, TWFE, staggered adoption methods (Callaway-Sant'Anna, Sun-Abraham), Synthetic DiD, and more.
:keywords: which DiD estimator, staggered DiD estimator, difference-in-differences method selection, TWFE alternatives

Choosing an Estimator
=====================

Expand Down
73 changes: 55 additions & 18 deletions docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,6 @@

# Add repository root to sys.path so autodoc imports from checked-out source
# without needing pip install (which would require the Rust/maturin toolchain).
# Note: visualization.py lazily imports matplotlib inside functions, so it is
# not needed as a build dependency. If a future module adds a top-level
# matplotlib import, add it to the RTD dep list in .readthedocs.yaml.
sys.path.insert(0, os.path.abspath(".."))

import diff_diff
Expand All @@ -30,10 +27,13 @@
"sphinx.ext.viewcode",
"sphinx.ext.intersphinx",
"sphinx.ext.mathjax",
"sphinxext.opengraph",
"sphinx_sitemap",
"nbsphinx",
]

templates_path = ["_templates"]
exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"]
exclude_patterns = ["_build", "Thumbs.db", ".DS_Store", "llms.txt", "llms-full.txt"]

# -- Options for autodoc -----------------------------------------------------
autodoc_default_options = {
Expand Down Expand Up @@ -62,17 +62,56 @@
napoleon_attr_annotations = True

# -- Options for HTML output -------------------------------------------------
html_theme = "sphinx_rtd_theme"
html_theme = "pydata_sphinx_theme"
html_static_path = ["_static"]
html_title = "diff-diff: Difference-in-Differences Causal Inference for Python"
# Use RTD's canonical URL when available; fall back to stable for local builds.
_canonical_url = os.environ.get(
"READTHEDOCS_CANONICAL_URL",
"https://diff-diff.readthedocs.io/en/stable/",
)
html_baseurl = _canonical_url
html_extra_path = ["llms.txt", "llms-full.txt"]
sitemap_url_scheme = "{link}"

html_theme_options = {
"icon_links": [
{
"name": "GitHub",
"url": "https://github.com/igerber/diff-diff",
"icon": "fa-brands fa-github",
},
{
"name": "PyPI",
"url": "https://pypi.org/project/diff-diff/",
"icon": "fa-brands fa-python",
},
],
"navigation_depth": 4,
"collapse_navigation": False,
"sticky_navigation": True,
"includehidden": True,
"titles_only": False,
"show_toc_level": 2,
"use_edit_page_button": True,
}

html_context = {
"github_user": "igerber",
"github_repo": "diff-diff",
"github_version": "main",
"doc_path": "docs",
}

# -- Options for sphinxext-opengraph -----------------------------------------
ogp_site_url = _canonical_url
ogp_site_name = "diff-diff"
ogp_description_length = 200
ogp_type = "website"
ogp_enable_meta_description = True
ogp_social_cards = {
"line_color": "#1f77b4",
}

# -- Options for nbsphinx ---------------------------------------------------
nbsphinx_execute = "never"

# -- Options for intersphinx -------------------------------------------------
intersphinx_mapping = {
"python": ("https://docs.python.org/3", None),
Expand All @@ -83,19 +122,17 @@

# -- ReadTheDocs version-aware banner ----------------------------------------
# Shows a warning on development builds so users know they may be reading
# docs for unreleased features. Only activates on RTD (not local builds).
# docs for unreleased features. Uses PyData theme's announcement bar on RTD,
# falls back to rst_prolog for local builds.
rtd_version = os.environ.get("READTHEDOCS_VERSION", "")
rtd_version_type = os.environ.get("READTHEDOCS_VERSION_TYPE", "")

if rtd_version == "latest" or rtd_version_type == "branch":
rst_prolog = """
.. warning::

This documentation is for the **development version** of diff-diff.
It may describe features not yet available in the latest PyPI release.
For stable documentation, use the version selector (bottom-left) to switch to **stable**.

"""
html_theme_options["announcement"] = (
"This documentation is for the <strong>development version</strong> of diff-diff. "
"It may describe features not yet available in the latest PyPI release. "
'Use the version selector to switch to <a href="/en/stable/">stable</a>.'
)

# -- Custom CSS --------------------------------------------------------------
def setup(app):
Expand Down
82 changes: 82 additions & 0 deletions docs/index.rst
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
.. meta::
:description: diff-diff — Python library for Difference-in-Differences causal inference. Callaway-Sant'Anna, Synthetic DiD, Honest DiD, event studies, parallel trends. sklearn-like API, validated against R.
:keywords: difference-in-differences, python, causal inference, DiD, econometrics, treatment effects, staggered adoption, event study

diff-diff: Difference-in-Differences in Python
==============================================

Expand Down Expand Up @@ -67,6 +71,84 @@ Quick Links

api/index

.. toctree::
:maxdepth: 1
:caption: Tutorials
:hidden:

tutorials/01_basic_did
tutorials/02_staggered_did
tutorials/03_synthetic_did
tutorials/04_parallel_trends
tutorials/05_honest_did
tutorials/06_power_analysis
tutorials/07_pretrends_power
tutorials/08_triple_diff
tutorials/09_real_world_examples
tutorials/10_trop
tutorials/11_imputation_did
tutorials/12_two_stage_did
tutorials/13_stacked_did
tutorials/14_continuous_did
tutorials/15_efficient_did

What is Difference-in-Differences?
----------------------------------

Difference-in-Differences (DiD) is a quasi-experimental research design that estimates
causal treatment effects by comparing outcome changes over time between treated and
control groups. It is one of the most widely used methods in applied economics,
public policy evaluation, and social science research.

Why diff-diff?
--------------

- **Complete method coverage**: 13+ estimators from basic 2x2 DiD to cutting-edge methods like Efficient DiD (Chen et al. 2025) and TROP (Athey et al. 2025)
- **Familiar API**: sklearn-like ``fit()`` interface — if you know scikit-learn, you know diff-diff
- **Modern staggered methods**: Callaway-Sant'Anna, Sun-Abraham, Imputation DiD, Two-Stage DiD, and Stacked DiD handle heterogeneous treatment timing correctly
- **Robust inference**: Heteroskedasticity-robust, cluster-robust, wild cluster bootstrap, and multiplier bootstrap
- **Sensitivity analysis**: Honest DiD (Rambachan & Roth 2023) for robust inference under parallel trends violations
- **Validated against R**: Benchmarked against ``did``, ``synthdid``, and ``fixest`` — see :doc:`benchmarks`
- **No heavy dependencies**: Only numpy, pandas, and scipy

Supported Estimators
--------------------

.. list-table::
:header-rows: 1
:widths: 30 70

* - Estimator
- Description
* - :class:`~diff_diff.DifferenceInDifferences`
- Basic 2x2 DiD with robust/clustered standard errors
* - :class:`~diff_diff.TwoWayFixedEffects`
- Panel data with unit and time fixed effects
* - :class:`~diff_diff.MultiPeriodDiD`
- Event study with period-specific treatment effects
* - :class:`~diff_diff.CallawaySantAnna`
- Callaway & Sant'Anna (2021) for staggered adoption
* - :class:`~diff_diff.SunAbraham`
- Sun & Abraham (2021) interaction-weighted estimator
* - :class:`~diff_diff.ImputationDiD`
- Borusyak, Jaravel & Spiess (2024) imputation estimator
* - :class:`~diff_diff.TwoStageDiD`
- Gardner (2022) two-stage residualized estimator
* - :class:`~diff_diff.SyntheticDiD`
- Synthetic DiD combining DiD and synthetic control
* - :class:`~diff_diff.StackedDiD`
- Wing, Freedman & Hollingsworth (2024) stacked DiD
* - :class:`~diff_diff.EfficientDiD`
- Chen, Sant'Anna & Xie (2025) efficient DiD
* - :class:`~diff_diff.TripleDifference`
- Triple difference (DDD) estimator
* - :class:`~diff_diff.ContinuousDiD`
- Continuous treatment DiD
* - :class:`~diff_diff.TROP`
- Triply Robust Panel with factor model adjustment (Athey et al. 2025)
* - :class:`~diff_diff.BaconDecomposition`
- Goodman-Bacon decomposition diagnostics

Indices and tables
------------------

Expand Down
Loading
Loading