didintrjl

library(didintrjl)

Introduction

The didintrjl package is an R wrapper for the Julia package DiDInt.jl, which implements intersection difference-in-differences (DID-INT); a method developed by Karim & Webb (2025). DID-INT allows for unbiased estimation of the average treatment effect on the treated (ATT) when the common causal covariates (CCC) assumption is violated; that is, when the effects of covariates on the outcome of interest may vary by state, time, or both. It supports common or staggered adoption.

Because didintrjl interfaces with Julia via JuliaConnectoR, the examples below require a working Julia installation with DiDInt.jl available (see the README for installation details). They are evaluated only when juliaSetupOk() returns TRUE and the DiDInt.jl package can be found.

The two functions are didint(), which estimates ATT, and didint_plot(), which produces parallel trends or event study plots.

1. Estimation

didint() returns an object of class DiDIntObj with three S3 methods: print(), summary(), and coef(). Each accepts a level argument of either "agg" or "sub" to distinguish aggregate from sub-aggregate results. In a staggered adoption setting with several treatment times, level = "sub" returns results for the distinct treatment times, whereas level = "agg" returns the aggregated results.

# Load the example data
df <- read.csv(system.file("extdata", "merit.csv", package = "didintrjl"))

# Estimate the ATT
res <- didint("coll", "state", "year", df, verbose = FALSE,
              treated_states = c(71, 58, 64, 59, 85, 57, 72, 61, 34, 88),
              treatment_times = c(1991, 1993, 1996, 1997, 1997, 1998,
                                  1998, 1999, 2000, 2000))

summary(res)
#> 
#>   Model Specification: Two-way DID-INT
#>   Weighting: both
#>   Aggregation: cohort
#>   Period Length: 1 year
#>   First Period: 1989
#>   Last Period: 2000
#>   Permutations: 999
#> 
#> Aggregate Results:
#>         ATT Std. Error     p-value RI p-value Jackknife SE Jackknife p-value
#>  0.04582252 0.01159691 0.007526681  0.1471471   0.01520398        0.00404305
#> 
#> Subaggregate Results:
#> Treatment Time              ATT         SE    p-value   RI p-val      JK SE   JK p-val     Weight
#> -------------------------------------------------------------------------------------------------------------- 
#> 1991-01-01               0.0529     0.0221     0.0172     0.5335         NA         NA     0.2018
#> 1993-01-01               0.0236     0.0166     0.1554     0.6747         NA         NA     0.1915
#> 1996-01-01               0.0564     0.0242     0.0208     0.4795         NA         NA     0.0757
#> 1997-01-01               0.0711     0.0230     0.0023     0.2122     0.0257     0.0080     0.3211
#> 1998-01-01               0.0485     0.0329     0.1427     0.4955     0.0838     0.5650     0.1086
#> 1999-01-01               0.0120     0.0150     0.4235     0.8979         NA         NA     0.0355
#> 2000-01-01              -0.0331     0.0320     0.3081     0.6927     0.0966     0.7336     0.0658

# Aggregate and sub-aggregate results can also be accessed directly
res$agg
#>          att         se        pval   ri_pval  jknife_se jknife_pval
#> 1 0.04582252 0.01159691 0.007526681 0.1471471 0.01520398  0.00404305
res$sub
#>        group         att         se        pval   ri_pval  jknife_se
#> 1 1991-01-01  0.05290996 0.02211803 0.017190246 0.5335335         NA
#> 2 1993-01-01  0.02359277 0.01657012 0.155433859 0.6746747         NA
#> 3 1996-01-01  0.05643511 0.02422739 0.020797631 0.4794795         NA
#> 4 1997-01-01  0.07111675 0.02296333 0.002287606 0.2122122 0.02574683
#> 5 1998-01-01  0.04854361 0.03290810 0.142653420 0.4954955 0.08378975
#> 6 1999-01-01  0.01204398 0.01497416 0.423539176 0.8978979         NA
#> 7 2000-01-01 -0.03306235 0.03203587 0.308102279 0.6926927 0.09660284
#>   jknife_pval    weights
#> 1          NA 0.20179564
#> 2          NA 0.19153484
#> 3          NA 0.07567336
#> 4 0.008012064 0.32107738
#> 5 0.564954173 0.10859342
#> 6          NA 0.03548525
#> 7 0.733597087 0.06584010

2. Plotting

didint_plot() returns an object of class DiDIntPlotObj with one S3 method: plot(). It can produce either an event study plot (event = TRUE) or a parallel trends plot (the default). The object also stores the underlying plotting data in DiDIntPlotObj$data, so you can build your own customized plots if you wish.

2.1 Event Study Plot

res_event <- didint_plot("coll", "state", "year", df, event = TRUE,
                         treated_states = c(71, 58, 64, 59, 85, 57,
                                            72, 61, 34, 88),
                         treatment_times = c(1991, 1993, 1996, 1997, 1997,
                                             1998, 1998, 1999, 2000, 2000),
                         covariates = c("asian", "black", "male"))

plot(res_event)

References

You can access citations by calling citation("didintrjl").

Karim, S. and Webb, M. D. 2025. Good Controls Gone Bad: Difference-in-Differences with Covariates. arXiv preprint arXiv:2412.14447. https://arxiv.org/abs/2412.14447