contdid

Difference-in-Differences with a Continuous Treatment

https://github.com/bcallaway11/contdid

Science Score: 54.0%

This score indicates how likely this project is to be science-related based on various indicators:

  • CITATION.cff file
    Found CITATION.cff file
  • codemeta.json file
    Found codemeta.json file
  • .zenodo.json file
    Found .zenodo.json file
  • DOI references
  • Academic publication links
    Links to: arxiv.org
  • Academic email domains
  • Institutional organization owner
  • JOSS paper metadata
  • Scientific vocabulary similarity
    Low similarity (18.1%) to scientific vocabulary
Last synced: 6 months ago · JSON representation ·

Repository

Difference-in-Differences with a Continuous Treatment

Basic Info
Statistics
  • Stars: 32
  • Watchers: 1
  • Forks: 3
  • Open Issues: 3
  • Releases: 0
Created over 1 year ago · Last pushed 8 months ago
Metadata Files
Readme Changelog Citation

README.Rmd

---
output: github_document
references:
  - id: callaway-goodman-santanna-2025
    title: "Difference-in-Differences with a Continuous Treatment"
    author:
      - family: Callaway
        given: Brantly
      - family: Goodman-Bacon
        given: Andrew
      - family: Sant'Anna
        given: Pedro H. C.
    issued:
      year: 2025
    type: unpublished
    note: "Working paper"
  - id: chen-christensen-kankanala-2025
    title: "Adaptive Estimation and Uniform Confidence Bands for Nonparametric Structural Functions and Elasticities"
    author:
      - family: Chen
        given: Xiaohong
      - family: Christensen
        given: Timothy
      - family: Kankanala
        given: Sid
    issued:
      year: 2025
    container-title: "Review of Economic Studies"
    volume: 92
    issue: 1
    page: 162–196
    type: article-journal

---





```{r, include = FALSE}
knitr::opts_chunk$set(
  collapse = TRUE,
  comment = "#>",
  fig.path = "man/figures/README-",
  out.width = "100%"
)
```

# contdid




An R package for difference-in-differences with a continuous treatment.

## Installation

You can install the development version of contdid from [GitHub](https://github.com/bcallaway11/contdid) with:

```{r, eval=FALSE}
# install.packages("devtools")
devtools::install_github("bcallaway11/contdid")

library(contdid)
```

## Package Status: Alpha Version

This is an **alpha version** of the `contdid` package. The core features are implemented and functional, but the package remains under active development. The API may change, and additional functionality is planned.

We welcome feedback and encourage users to report bugs or other issues via the [GitHub Issues page](https://github.com/bcallaway11/contdid/issues).

### ✅ Currently Supported

- ☑️ Continuous treatments
- ☑️ Staggered treatment adoption (i.e., more than two periods and variation in timing across units)
- ☑️ Aggregations into dose-specific ATT's or ACRT's
- ☑️ Aggregations into ATT or ACRT versions of event studies
- ☑️ User-specified flexible parametric models for treatment effects as a function of the dose

### 🚫 Not Yet Supported

- ❌ Discrete treatments

  - This is straightforward and could be implemented by users directly, but we don't have it in the package yet.

- ⚠️ Data-driven models for treatment effects as a function of the dose

  - We have this working for cases without staggered adoption, but it is not yet implemented for staggered adoption.  We plan to add this in the future.

- ❌ Repeated cross-sections data
- ❌ Unbalanced panel data
- ❌ Doses that vary over time

  - Not sure if we will ever support this, or maybe only in limited contexts._

- ❌ Including covariates


```{r, echo=FALSE, warning=FALSE, message=FALSE}
devtools::load_all("~/Dropbox/BMisc")
devtools::load_all("~/Dropbox/ptetools")
devtools::load_all("~/Dropbox/contdid")
```

## Conceptual Setup

Below, we give several examples of how to estimate causal effect parameters using the `contdid` package.

At a high level, the interface is basically the same as for the `did` package and for packages that rely on the `ptetools` backend, with only a few pieces of additional information being required.  First, the name of the continuous treatment variable should be passed through the `dname` argument.

The `cont_did` function expects the continuous treatment variable to behave in certain ways:

1. It needs to be time-invariant.

2. It should be set to its time-invariant value in pre-treatment periods.  This is just a convention of the package, but, in particular, you should not have the treatment variable coded as being 0 in pre-treatment periods.

3. For units that don't participate in the treatment in any time period, the treatment variable just needs to be time-invariant.  In some applications, e.g., the continuous treatment variable may be defined for units that don't actually participate in the treatment.  In other applications, it may not be defined for units that do not participate in the treatment.  The function behaves the same way in either case.

Next, the other important parameters are `target_parameter`, `aggregation`, and `treatment_type`:

* `target_parameter` can either be "level" or "slope".  If "level", then the function will calculate `ATT` parameters.  If set to be "slope", then the function will calculate `ACRT` parameters---these are causal response parameters that are derivatives of the `ATT` parameters.  Our paper [Callaway, Goodman-Bacon, and Sant'Anna (2024)](https://arxiv.org/abs/2107.02637) points out some complications for interpreting these derivative type parameters under the most commonly invoked version of the parallel trends assumption.

* `aggregation` can either by "eventstudy" or "dose".  For "eventstudy", depending on the value of the `target_parameter` argument, the function will provide either the average `ATT` across different event times or the average `ACRT` across different event times.  For "dose", the function will average across all time periods and report average affects across different values of the continuous treatment.  For the "dose" aggregation, results are calculated for both `ATT` and `ACRT` and can be displayed by providing different arguments to plotting functions (see example below).

* `treatment_type` can either be "continuous" or "discrete".  Currently only "continuous" is supported.  In this case, the code proceeds as if the treatment really is continuous.  The estimate are computed nonparametrically using B-splines.  The user can control the number of knots and the degree of the B-splines using the `num_knots` and `degree` arguments.  The defaults are `num_knots=0` and `degree=1` which amounts to estimating `ATT(d)` by estimating a linear model in the continuous treatment among treated units and subtracting the average outcome among the comparison units.

## Examples

With a continuous treatment, the underlying building blocks are treatment effects that are local to a particular timing group `g` in a particular time period `t` that experienced a particular value of the treatment `d`.  These treatment affects are relatively high-dimensional, and most applications are likely to involve aggregating/combining these underlying parameters.  We focus on aggregations that (i) average across timing-groups and time periods to given average treatment effect parameters as a function of the dose `d` or (ii) averages across doses and partially across timing group and time periods in order to give event studies.

For the results below, we will simulate some data, where the continuous treatment `D` has no effect on the outcome.
```{r}
# Simulate data
set.seed(1234)
df <- simulate_contdid_data(
  n = 5000,
  num_time_periods = 4,
  num_groups = 4,
  dose_linear_effect = 0,
  dose_quadratic_effect = 0
)
head(df)
```

### Case 1: Dose Aggregation

The following code can be used to estimate the `ATT(d)` and `ACRT(d)` parameters for the continuous treatment `D` using the `cont_did` function.  The `aggregation` argument is set to "dose" and the `target_parameter` argument is set to "level" for `ATT(d)` and "slope" for `ACRT(d)`.

```{r, warning=FALSE, message=FALSE}
cd_res <- cont_did(
  yname = "Y",
  tname = "time_period",
  idname = "id",
  dname = "D",
  data = df,
  gname = "G",
  target_parameter = "slope",
  aggregation = "dose",
  treatment_type = "continuous",
  control_group = "notyettreated",
  biters = 100,
  cband = TRUE,
  num_knots = 1,
  degree = 3,
)

summary(cd_res)
ggcont_did(cd_res, type = "att")
ggcont_did(cd_res, type = "acrt")
```


### Case 2: Event Study Aggregations

Next, we consider event study aggregations.  The first is an event study aggregation for `ATT`.  The second is an event study aggregation for `ACRT`.

**Event study aggregation for `ATT`:**

Notice that the target parameter is set `level` to target ATT, and the `aggregation` argument is set to `eventstudy`.

```{r, warning=FALSE, message=FALSE}
cd_res_es_level <- cont_did(
  yname = "Y",
  tname = "time_period",
  idname = "id",
  dname = "D",
  data = df,
  gname = "G",
  target_parameter = "level",
  aggregation = "eventstudy",
  treatment_type = "continuous",
  control_group = "notyettreated",
  biters = 100,
  cband = TRUE,
  num_knots = 1,
  degree = 3,
)

summary(cd_res_es_level)
ggcont_did(cd_res_es_level)
```

**Event study aggregation for `ACRT`:**

Relative to the previous code, notice that the target parameter is set `slope` to target ACRT.

```{r, warning=FALSE, message=FALSE}
cd_res_es_slope <- cont_did(
  yname = "Y",
  tname = "time_period",
  idname = "id",
  dname = "D",
  data = df,
  gname = "G",
  target_parameter = "slope",
  aggregation = "eventstudy",
  treatment_type = "continuous",
  control_group = "notyettreated",
  biters = 100,
  cband = TRUE,
  num_knots = 1,
  degree = 3,
)

summary(cd_res_es_slope)
ggcont_did(cd_res_es_slope)
```

### Case 3: Data-Driven Nonparametric Model for Treatment Effects

In most applications, it is hard to know the correct functional form for the treatment effects as a function of the dose.  In @callaway-goodman-santanna-2025, the approach we emphasize comes from @chen-christensen-kankanala-2025, and the `contdid` package uses their [`npiv` package](https://github.com/JeffreyRacine/npiv) to implement this approach.  Code-wise, the only thing to change is to set the argument `dose_est_method="cck"`.  [Note that we currently only support this option for the case with two periods and no staggered adoption.  With more periods, you can average the pre- and post-treatment periods to reduce it to a two period case and then run the code below; in fact, this is what we did in the application in our paper.]

```{r, warning=FALSE, message=FALSE, cache=TRUE}
# simulate data with only two periods
# add quadratic effect to see how well we can detect it
# (note code will not "know" that the effect is quadratic)
df2 <- simulate_contdid_data(
  n = 5000,
  num_time_periods = 2,
  num_groups = 2,
  dose_linear_effect = 0,
  dose_quadratic_effect = 1
)
df2$D[df2$G == 0] <- 0
head(df2)

cd_res_cck <- cont_did(
  yname = "Y",
  tname = "time_period",
  idname = "id",
  dname = "D",
  data = df2,
  gname = "G",
  target_parameter = "level",
  aggregation = "dose",
  treatment_type = "continuous",
  dose_est_method = "cck",
  control_group = "notyettreated",
  biters = 100,
  cband = TRUE,
)

summary(cd_res_cck)
ggcont_did(cd_res_cck) +
  stat_function(
    fun = function(x) x^2,
    aes(color = "Truth"),
    linetype = "dashed",
    size = 1
  ) +
  scale_color_manual(values = c("Truth" = "red")) +
  labs(color = "")
```

## References

Owner

  • Login: bcallaway11
  • Kind: user
  • Location: Athens, GA
  • Company: University of Georgia

Brantly Callaway, Department of Economics, University of Georgia

Citation (CITATION.cff)

# --------------------------------------------
# CITATION file created with {cffr} R package
# See also: https://docs.ropensci.org/cffr/
# --------------------------------------------
 
cff-version: 1.2.0
message: 'To cite package "contdid" in publications use:'
type: software
license: GPL-3.0-only
title: 'contdid: Difference-in-Differences with a Continuous Treatment'
version: 0.1.0
abstract: Provides methods for difference-in-differences with a continuous treatment
  and staggered treatment adoption. Includes estimation of treatment effects and causal
  responses as a function of the dose, event studies indexed by length of exposure
  to the treatment, and aggregation into overall average effects. Uniform inference
  procedures are included, along with both parametric and nonparametric models for
  treatment effects. The methods are based on Callaway, Goodman-Bacon, and Sant'Anna
  (2025) <https://doi.org/10.48550/arXiv.2107.02637>.
authors:
- family-names: Callaway
  given-names: Brantly
  email: brantly.callaway@uga.edu
- family-names: Goodman-Bacon
  given-names: Andrew
  email: andrew@goodman-bacon.com
- family-names: Sant'Anna
  given-names: Pedro H. C.
  email: pedro.h.santanna@emory.edu
preferred-citation:
  type: manual
  title: Difference-in-Differences with a Continuous Treatment
  authors:
  - family-names: Callaway
    given-names: Brantly
    email: brantly.callaway@uga.edu
  - family-names: Goodman-Bacon
    given-names: Andrew
    email: andrew@goodman-bacon.com
  - family-names: Sant'Anna
    given-names: Pedro H. C.
    email: pedro.h.santanna@emory.edu
  year: '2025'
  notes: R package version 0.1.0
  url: https://bcallaway11.github.io/contdid/
repository-code: https://github.com/bcallaway11/contdid
url: https://bcallaway11.github.io/contdid/
contact:
- family-names: Callaway
  given-names: Brantly
  email: brantly.callaway@uga.edu
references:
- type: software
  title: 'R: A Language and Environment for Statistical Computing'
  notes: Depends
  url: https://www.R-project.org/
  authors:
  - name: R Core Team
  institution:
    name: R Foundation for Statistical Computing
    address: Vienna, Austria
  year: '2025'
  version: '>= 4.1.0'
- type: software
  title: MASS
  abstract: 'MASS: Support Functions and Datasets for Venables and Ripley''s MASS'
  notes: Imports
  url: http://www.stats.ox.ac.uk/pub/MASS4/
  repository: https://CRAN.R-project.org/package=MASS
  authors:
  - family-names: Ripley
    given-names: Brian
    email: Brian.Ripley@R-project.org
  - family-names: Venables
    given-names: Bill
  year: '2025'
  doi: 10.32614/CRAN.package.MASS

GitHub Events

Total
  • Issues event: 6
  • Watch event: 22
  • Issue comment event: 8
  • Push event: 13
  • Pull request event: 2
  • Fork event: 2
Last Year
  • Issues event: 6
  • Watch event: 22
  • Issue comment event: 8
  • Push event: 13
  • Pull request event: 2
  • Fork event: 2

Issues and Pull Requests

Last synced: 6 months ago

All Time
  • Total issues: 6
  • Total pull requests: 2
  • Average time to close issues: 3 days
  • Average time to close pull requests: 9 minutes
  • Total issue authors: 5
  • Total pull request authors: 1
  • Average comments per issue: 2.67
  • Average comments per pull request: 0.0
  • Merged pull requests: 2
  • Bot issues: 0
  • Bot pull requests: 0
Past Year
  • Issues: 6
  • Pull requests: 2
  • Average time to close issues: 3 days
  • Average time to close pull requests: 9 minutes
  • Issue authors: 5
  • Pull request authors: 1
  • Average comments per issue: 2.67
  • Average comments per pull request: 0.0
  • Merged pull requests: 2
  • Bot issues: 0
  • Bot pull requests: 0
Top Authors
Issue Authors
  • skuchukh (2)
  • EddieLUO97 (1)
  • btleyden (1)
  • economistrosa (1)
  • ser1c (1)
Pull Request Authors
  • pedrohcgs (2)
Top Labels
Issue Labels
Pull Request Labels

Packages

  • Total packages: 1
  • Total downloads:
    • cran 168 last-month
  • Total dependent packages: 0
  • Total dependent repositories: 0
  • Total versions: 1
  • Total maintainers: 1
cran.r-project.org: contdid

Difference-in-Differences with a Continuous Treatment

  • Versions: 1
  • Dependent Packages: 0
  • Dependent Repositories: 0
  • Downloads: 168 Last month
Rankings
Stargazers count: 12.9%
Forks count: 17.3%
Dependent packages count: 26.1%
Dependent repos count: 32.2%
Average: 35.0%
Downloads: 86.4%
Maintainers (1)
Last synced: 6 months ago

Dependencies

.github/workflows/check-package.yml actions
  • actions/checkout v4 composite
  • actions/upload-artifact v4 composite
  • r-lib/actions/setup-r v2 composite
.github/workflows/revdep-check-test.yml actions
  • actions/checkout v4 composite
  • actions/upload-artifact v4 composite
  • r-lib/actions/setup-r v2 composite
.github/workflows/update-citation.yml actions
  • actions/checkout v4 composite
  • r-lib/actions/setup-r v2 composite
DESCRIPTION cran
  • R >= 4.1.0 depends
  • BMisc >= 1.4.8 imports
  • MASS * imports
  • checkmate * imports
  • ggplot2 * imports
  • npiv * imports
  • ptetools * imports
  • sandwich * imports
  • splines2 * imports
  • testthat >= 3.0.0 suggests
  • tidyr * suggests