
cdid estimates group time average treatment effects
ATT(g,t) with chained difference in differences (chained DiD). It builds
upon the did
package and extends it to panels in which some outcomes may be
missing, by using the outcome changes between the dates at which each
unit is observed.
CRAN package page · Author website
The current CRAN release is 0.1.1. This repository contains version 1.2.0.1, which is being prepared for the next CRAN update.
Install directly from GitHub in a normal R session:
# Run once if remotes is not installed:
install.packages("remotes")
remotes::install_github("dvbn/cdid")
library(cdid)You need R 4.1.0 or later and the official CRAN
packages did 2.5.1 or later and DRDID 1.4.0 or
later. remotes installs missing required
dependencies and offers updates when needed. Allow updates to
dependencies below these minimum versions. You do not need GitHub
versions of did or DRDID.
Installing from GitHub compiles cdid’s C code, so the
usual tools for building R packages from source must be available:
make,
including tools needed by dependencies.No Docker, Homebrew installation of R, special project library or validation scripts are required. A standard CRAN installation of R is suitable.
cdid 1.2.0.1 has been tested with did 2.5.1
and DRDID 1.4.0 under R 4.5.2. R 4.5.2 is a tested version,
not an installation requirement. Later versions of these dependencies
are accepted but have not been comprehensively tested; compatibility and
identical results are not guaranteed. The optional pinned
validation setup reproduces the tested dependency versions for
checks of this revision; historical outputs retain their recorded
dependency versions.
If an error reports outdated did or DRDID,
update them with install.packages(c("did", "DRDID")) and
restart R before trying again. Modified forks of these packages may have
different interfaces even when their version numbers exceed the minimum.
An abrupt “R session aborted” can also come from
incompatible local R installations and compiled packages. In that case,
check which
R version RStudio uses and reinstall affected dependencies with that
R installation. For help, include sessionInfo() and
installation output in an issue.
A short hands-on vignette covers an incomplete panel, estimation,
diagnostics, aggregation and plotting. To include it when installing
from GitHub, use
remotes::install_github("dvbn/cdid", build_vignettes = TRUE)
with knitr, rmarkdown and Pandoc available.
Open it with vignette("cdid", package = "cdid"). The full user
guide and practical
notebook provide more examples.
A treatment cohort is the set of units first treated in the same
period. For cohort g and period t, ATT(g,t) is the average effect of the
treatment in period t on the units of cohort g. Callaway and
Sant’Anna (2021, Journal of Econometrics) define these
effects for staggered adoption, estimate each one by comparing the
cohort with units never treated or not yet treated, and aggregate them
into summaries such as event studies. The did package
implements their estimators, which adjust for covariates by outcome
regression (OR), inverse probability weighting (IPW) or a doubly robust
(DR) combination of the two.
cdid extends this framework to incomplete panels with
the chained DiD of (Bellégo, Benatia
and Dortet-Bernadet (2025, Journal of Econometrics), arXiv). did
handles an unbalanced panel either by keeping only the units observed at
every date or, with allow_unbalanced_panel = TRUE, through
repeated cross section (RCS) estimators that compare outcome levels.
Chained DiD instead uses the changes of each unit between the dates at
which it is observed, and combines all available short DiD comparisons
into the effects. The targets remain the ATT(g,t) of the cohorts of the
original study population, including their units with missing outcomes,
and the assumptions concern the missing changes rather than the missing
levels, as explained below.
Two adjustments are chosen separately. The treatment adjustment,
chosen with est_method, makes each cohort comparable with
its controls by IPW, OR or DR, as in did (Treatment
adjustment). The adjustment for missing outcomes applies when
attrition or other missingness depends on measured covariates related to
the changes. With selection = "conditional_mtar",
selection_est_method chooses observation weighting, which
weights each observed change by the inverse of its estimated probability
of being observed at both dates ("ipw"), change imputation,
which predicts the changes with a regression fitted to the observed
changes ("imputation"), or the augmented correction, which
combines the two ("dr") and works with treatment IPW, OR or
DR (Handling
missing outcomes). Treatment DR with the augmented correction is
doubly robust in both layers: for the treatment, either the propensity
model or the outcome regression may be misspecified, and for the missing
outcomes, either the observation model or the imputation model, provided
the other model of the layer and the remaining assumptions are correct
(Which
models must be correct).
For treatment OR and DR, outcome_pooling = "separate" is
the default: each distinct comparison has its own outcome coefficients.
Explicit "pooled" shares slopes per calendar step across
comparisons, with local intercepts, preserving the earlier
specification. This choice is independent of the observation and
imputation pooling settings (Treatment
adjustment).
cdid also lets you choose between two parallel trends
assumptions. PT-post, the default, assumes parallel trends from each
cohort’s reference period onward. PT-all, which did 2.5.1
(the tested version) does not offer, adds the same assumption from a
chosen common start date up to each reference period, so that each of
those earlier dates can also serve as a baseline. As in Bellégo, Benatia
and Dortet-Bernadet (2025), short comparisons between observed dates are
combined by the generalized method of moments (GMM), and the system is
overidentified when several comparisons inform the same effect. Under
PT-post this system already combines the comparisons that PT-post makes
valid; PT-all adds to the same system the earlier restrictions that only
its stronger assumption justifies. Valid restrictions can make more
effects available or improve precision, but neither gain is guaranteed,
and false restrictions can bias the estimates (Parallel
trends). How cells before treatment are reported is a separate
choice, base_period, which changes neither assumption. A
future release will incorporate additional efficiency options.
cdid imports did and keeps familiar
function names and upstream argument order: att_gt(),
aggte(), ggdid(), tidy(),
glance() and conditional_did_pretest(). Most
upstream defaults are retained, including treatment DR for
att_gt(). Panel data select chained mode by default, and
allow_unbalanced_panel = NULL resolves according to the
mode. The migration
page explains these differences and the added chained arguments.
mode = "ordinary" and used automatically for repeated cross
sections, passes the call unchanged to did.Let us illustrate how Chained DiD works with changes within the same unit. Write the outcome of unit i at date t as \(Y_{it} = \alpha_i + u_{it}\), where \(\alpha_i\) is a fixed individual effect and \(u_{it}\) holds everything that varies over time: trends, the treatment effect and noise. The change between two observed dates, \(Y_{it} - Y_{is} = u_{it} - u_{is}\), contains no \(\alpha_i\). Suppose that treated units with low \(\alpha_i\), that is with persistently low outcomes, are more likely to leave the panel, while controls leave at random. The treated units still observed at later dates then have a higher mean \(\alpha_i\), so comparing their outcome levels with earlier ones adds this change in composition to the treatment effect. Thus, if attrition depends only on \(\alpha_i\) and \(\alpha_i\) is unrelated to \(u_{it} - u_{is}\), the treated units that remain still have the mean change of their cohort.
This is the main advantage of chained DiD for incomplete panels: whether an outcome is observed may depend on the unobservable individual effect, as long as that effect is unrelated to the changes, and the observed levels need not remain representative of the population. For RCS comparisons, changing composition must not distort the relevant conditional level comparisons. Representative samples at each date are one sufficient condition. Assuming missing completely at random (MCAR) guarantees this, but is stronger than necessary. Attrition related to persistent differences between units can violate that condition.
Chained DiD has its own assumptions. Within a cohort, the units observed in a given pair must be representative of that cohort with respect to the mean outcome change over that pair, possibly conditional on covariates with an appropriate adjustment. This equates population expectations of changes. It does not require every unit to have the same change, exact equality of realized sample means, or equality of the full distributions. Parallel trends, no anticipation and overlap must also hold. Handling missing outcomes, Parallel trends and Treatment adjustment state these assumptions. Neither approach is always better in every design: when the sample at each date represents the population, comparisons of levels can be valid too. Identify effects when the observed units change composition works through a design in which the changes identify the effects and comparisons of levels do not.
In practice, unless you can rule out that attrition or other missingness is related to persistent unobserved differences between units, chained DiD is the safer choice, provided its assumptions about changes hold. When observation plausibly depends on such stable differences in outcomes, comparisons of observed levels mix the change in composition with the effects, whereas the changes do not contain the persistent component. Removing the fixed effect does not by itself make the missing changes ignorable, however: if the persistent component is related to trends or to heterogeneous treatment effects, observation that depends on it also selects the changes, and the assumption about changes can fail.
Chained DiD can also be more precise than RCS comparisons when both are valid. Differencing removes the persistent unit component \(\alpha_i\), whose variation otherwise adds noise to comparisons of levels, while the transitory noise of each short change accumulates along a chain. Bellégo, Benatia and Dortet-Bernadet (2025, Section 2.1.3 and Proposition 1) analyze this trade-off under their outcome model with outcomes missing completely at random: the gain in precision depends on how persistent the outcomes are, how much units differ and how far apart the compared dates are, so neither approach is more precise in every design. How to compare precision explains how to compare them on matched targets.
Bellégo, C., Benatia, D. and Dortet-Bernadet, V. (2025). The Chained Difference-in-Differences. Journal of Econometrics, 248, article 105783. https://doi.org/10.1016/j.jeconom.2024.105783. arXiv version: https://arxiv.org/abs/2301.01085
Callaway, B. and Sant’Anna, P. H. C. (2021). Difference-in-Differences with Multiple Time Periods. Journal of Econometrics, 225(2), pages 200 to 230. https://doi.org/10.1016/j.jeconom.2020.12.001
Chained IPW (est_method = "ipw") and observation
weighting for missing outcomes follow Bellégo, Benatia and
Dortet-Bernadet. The package extends these papers with chained OR and
DR, which carry the OR and DR approaches over to chained comparisons
through regressions of the controls’ outcome changes, fitted separately
by comparison by default or pooled with
outcome_pooling = "pooled", and with change imputation and
PT-all. The augmented
correction for missing outcomes, which combines an observation model
with a change imputation model and can be used with treatment IPW, OR or
DR, is a further extension; an accompanying paper is about to be
released. The methods pages in the reading path state the assumptions
each extension needs.
Each page of the guide ends with links to the previous and next steps and a collapsible list of all steps.
For the input requirements and a practical check of your observation patterns, start with Prepare your panel and unit table and Investigate missingness and data structure. The latter shows counts across study units, selected-pair support and the diagnostics available from a fitted result. Observed missingness patterns alone cannot establish the required representativeness of mean changes.
For hands-on exploration, use the editable Quarto source or download the standalone HTML with results. Download the HTML file and open it in a browser to read the tables and plots without running R. One editable configuration controls the synthetic panel, and the sections walk through estimation, missingness, selection models, aggregation, inference and diagnostics. The notebook instructions explain how to run the code or open its rendered HTML with tables and plots.
| Step | Page | Description |
|---|---|---|
| 1 | Get started | Main functions on a balanced panel: estimation, summaries, aggregation, plots and export. |
| 2 | Moving from did | What stays familiar, how incomplete panels are treated, and why balanced results can differ and which to use. |
| 3 | Incomplete panels | Which changes an observation pattern supplies and how chaining combines them, with a rotating panel example. |
| 4 | Identify effects when the observed units change composition | When changes within units identify effects that comparisons of observed levels do not. |
| 5 | How to compare precision | Matched targets and assumptions, covariance, and what standard errors can show. |
| 6 | Prepare your panel and unit table | Identifiers, missing outcomes kept as NA, the unit
table, and changing covariates or weights. |
| 7 | Treatment adjustment | How IPW, OR and DR make a cohort comparable with its controls. |
| 8 | Choose IPW, OR or DR in an incomplete panel | The three treatment adjustments compared on one incomplete panel. |
| 9 | Handling missing outcomes | The study population, the assumption about missing outcomes and the three ways to adjust for them. |
| 10 | Sampling information for the observation model | Advanced: fitting the observation model on part of the unit table. |
| 11 | Choose an observation model | Date or pair logits, and how many slopes they share. |
| 12 | Impute actual changes | Observation weighting, change imputation and the augmented correction compared on one panel. |
| 13 | Parallel trends | PT-post, PT-all and the separate reporting choice
base_period. |
| 14 | Add PT-all restrictions | What true and false PT-all restrictions change on one incomplete panel. |
| 15 | GMM weighting and covariance regularization | How comparisons are combined and what covariance regularization does. |
| 16 | Robustness | Which models must be correct for each combination of treatment adjustment and missing outcome handling. |
| 17 | Inference | Intervals, bands, clustering, aggregation and pretrend tests. |
| 18 | Options | Every argument with its default, accepted values and when it is active. |
| 19 | Results | The contents of each result, the uncertainty rules, pretrend tests and export. |
| 20 | Diagnose errors and unavailable results | Refused requests, failed fits, unavailable effects and surprising results. |
This guide describes version 1.2.0.1. Numerical code output shown on the article pages comes from recorded runs, and each page states the version actually used. Analytical population values are labeled separately.
| Term | Meaning |
|---|---|
| Study population | The population whose treatment effects the analysis describes. |
| Unit table | One row per study unit, supplied through the frame
argument, including units with one or no observed outcomes. Without
frame, the units present in data form it. |
| Treatment cohort | Units first treated in the same period. gname holds
that period, and 0 marks units never treated. |
| Units observed at both dates | The units whose outcomes are observed at both dates of a comparison. Only they contribute that change. |
| Treatment adjustment | How each cohort is made comparable with its controls: IPW, OR or DR,
chosen with est_method. |
| Handling missing outcomes | The assumption made about missing outcomes and the way the package
adjusts for them, chosen with the arguments that begin with
selection and with imputation_pooling. |
| PT-post and PT-all | Parallel trends from each cohort’s reference period onward, and the same assumption with additional restrictions from a common start date. |
More efficient estimators will be implemented in later releases.
Python and Stata versions are planned. They will have separate repositories and documentation.
Use Issues for questions about using the package or choosing a method and for reproducible bugs. Include the package version and reproducible example.
See Contributing to suggest a change.
Have spare Codex subscription capacity and want to support cdid? Use your own account to complete a scoped contributor task, then return your code, checks or findings for review. We provide public instructions and a reusable skill. You choose your time and usage budget and keep your credentials private. Contributions without coding agents are equally welcome. See Contributing to get started.
If cdid is useful to your work, you can buy me a coffee.