The hardware and bandwidth for this mirror is donated by dogado GmbH, the Webhosting and Full Service-Cloud Provider. Check out our Wordpress Tutorial.
If you wish to report a bug, or if you are interested in having us mirror your free-software or open-source project, please feel free to contact us at mirror[@]dogado.de.
The LRErdd package provides a set of functions for the design and analysis of Regression Discontinuity (RD) Designs as local randomized experiments within the potential outcome approach, as formalized in Li, Mattei and Mealli (2015).
The key insight underlying this approach is that, under a local randomization assumption, valid causal inference can be drawn for subpopulations of treated and control units whose realized values of the forcing variable fall in a neighborhood of the threshold and who have similar background characteristics.
The package supports the two phases of an RD study:
Design phase. A subset of functions focuses on the selection of suitable subpopulations around the threshold for which valid causal inference can be drawn. These functions provide summary statistics of pre- and post-treatment variables by treatment status, and select subpopulations where pre-treatment variables are well balanced between treatment groups, using randomization-based tests with adjustment for multiplicities. Functions for a visual inspection of the results are also provided.
Analysis phase. A second set of functions draws inference on causal effects for the selected subpopulations using randomization-based modes of inference. Specifically, the Fisher Exact p-value (FEP) and Neyman approaches are implemented for the analysis of both sharp and fuzzy RD designs.
There are two ways of working with the package:
RegressionDiscontinuityClass R6 class, which encapsulates
the whole workflow. This option is illustrated in this vignette and is
the recommended one for larger datasets and reproducible analyses.We illustrate the workflow with data from an Italian study concerning
the effects of university grants on student dropout (Li, Mattei and
Mealli, 2015). Eligibility for the grant is determined by a measure of
the economic situation of the student’s family (S, the
forcing variable) falling below a threshold of 15,000 euros, which makes
it a natural regression discontinuity design. Because not all eligible
students applied for and received the grant, the design is
fuzzy: the treatment received (W) does not
coincide with the eligibility status (Z).
data(grants)
dim(grants)
#> [1] 15984 21
head(grants[, c("S", "Z", "A", "W", "dropout", "sex", "hsgrade")])
#> S Z A W dropout sex hsgrade
#> 1 16833.09 0 1 0 0 1 81
#> 2 4002.53 1 1 1 0 1 70
#> 3 16905.84 0 1 0 0 1 70
#> 4 11836.94 1 1 1 0 1 60
#> 5 11935.00 1 1 1 0 0 70
#> 6 2015.45 1 1 1 1 0 70The dataset contains information on 15,984 students. The main
variables are the forcing variable S, the eligibility
indicator Z, the grant application indicator
A, the treatment received W, and the outcome
dropout (1 if the student dropped out). The remaining
columns are pre-treatment covariates (sex, high school type and grade,
cohort, university, and field of study).
RegressionDiscontinuityClass objectThe whole analysis is driven by an object of class
RegressionDiscontinuityClass. To create it, we need the
dataset (a data frame), the name of the forcing variable, the threshold,
whether the treatment group is below ("lower") or above
("upper") the threshold, and the vector of covariate names
used to assess balance.
# Covariates of interest
cov <- c("HSTech", "hsgrade", "Y2005")
rdo <- RegressionDiscontinuityClass$new(
data = grants,
forcing = "S",
threshold = 15000,
Z1S1 = "lower",
covariates = cov
)The full_print() method summarizes the information
stored in the object:
rdo$full_print()
#> [1] "------------------------------------"
#> [1] "Names of data frame -> S"
#> [2] "Names of data frame -> Z"
#> [3] "Names of data frame -> A"
#> [4] "Names of data frame -> W"
#> [5] "Names of data frame -> dropout"
#> [6] "Names of data frame -> sex"
#> [7] "Names of data frame -> HSHumanity"
#> [8] "Names of data frame -> HSScience"
#> [9] "Names of data frame -> HSTech"
#> [10] "Names of data frame -> HSOther"
#> [11] "Names of data frame -> hsgrade"
#> [12] "Names of data frame -> Y2004"
#> [13] "Names of data frame -> Y2005"
#> [14] "Names of data frame -> Y2006"
#> [15] "Names of data frame -> University"
#> [16] "Names of data frame -> Humanity"
#> [17] "Names of data frame -> Science"
#> [18] "Names of data frame -> Social.Science"
#> [19] "Names of data frame -> BioMed"
#> [20] "Names of data frame -> Tech"
#> [21] "Names of data frame -> Other"
#> [1] "Forcing variable -> S"
#> [1] "Threshold -> 15000"
#> [1] "Z1S1 -> lower"
#> [1] "Covariate -> HSTech" "Covariate -> hsgrade" "Covariate -> Y2005"
#> [1] "------------------------------------"The summary_statistics_mean() method reports the mean of
each selected covariate, overall and by treatment assignment status,
together with the group sizes:
The bandwidth_selection() method evaluates the influence
of a candidate bandwidth around the threshold on the balance of the
covariates. Three ways of defining the range are available through the
typerange argument:
"percentage": considering the range of the forcing
variable as 100%, the bandwidth is defined as a percentage of that
range."balunit": a symmetric bandwidth is defined by its
total width in the units of the forcing variable."unbalunit": an asymmetric bandwidth, defined by the
lower and upper bounds provided in range_value.The method returns the number of selected records with the limits of the selected range, a table with initial and bandwidth-specific p-values (raw and adjusted for multiplicity) from randomization-based balance tests, and, optionally, a histogram of the forcing variable with the threshold (black) and the selected limits (red):
rdo$bandwidth_selection(
typerange = "percentage",
range_value = 25,
num_it = 100,
plot = TRUE
)
#> $RangeInfo
#> Number of records Down limit Up limit Difference
#> 1 7584 11250.25 18749.75 7499.5
#>
#> $pvalues
#> Variable Initial Pvalue Initial Adj pvalue Bandwidth specific Pvalue
#> 1 HSTech 0.00 0.03 0.27
#> 2 hsgrade 0.00 0.03 0.96
#> 3 Y2005 0.03 0.09 0.05
#> Bandwidth specific Adj pvalue
#> 1 0.64
#> 2 1.00
#> 3 0.15
#>
#> $RangePlotThe distribution_plot() method compares the distribution
of a covariate between treatment groups in the complete dataset and
within the selected bandwidth. The covariate can be binary
(typecov = "binary") or continuous
(typecov = "conti"):
rdo$distribution_plot(
typerange = "percentage",
range_value = 25,
num_it = 100,
covariate = "sex",
typecov = "binary"
)The summary_bandwidth() method implements
randomization-based tests with multiplicity adjustment for assessing
balance in the background variables between treatment groups, for
several candidate bandwidths at once. It returns a table of adjusted
p-values by covariate and bandwidth; large p-values indicate
subpopulations where the covariates are well balanced:
rdo$summary_bandwidth(buffers = c(500, 1000, 1500), num_it = 200)
#> Names p-value[Bandwidth=500] p-value[Bandwidth=1000]
#> 1 HSTech 1.00 0.900
#> 2 hsgrade 0.58 1.000
#> 3 Y2005 1.00 0.385
#> p-value[Bandwidth=1500]
#> 1 1.000
#> 2 0.955
#> 3 0.830In practice we recommend a larger number of iterations (e.g.
num_it = 1000 or more) for the final analysis; a smaller
value is used here to keep the vignette light.
The causal_effect() method is the main function of the
package. Four modes of inference are implemented through the
method argument:
'Sharp FEP': Fisher’s exact p-value approach for sharp
RD designs within the selected subpopulations.'Sharp Neyman': Neyman approach for sharp RD
designs.'Fuzzy FEP': Fisher’s exact p-value approach for fuzzy
RD designs.'Fuzzy Neyman': Neyman approach for fuzzy RD
designs.In all cases, the user selects the bandwidths (buffers),
the outcome and its type ("binary" or
"numeric"), and the number of iterations used to
approximate the randomization distribution.
In the fuzzy design, the treatment received (W, provided
through the treatm_cov argument) does not coincide with the
assignment. The Neyman approach reports both the intention-to-treat
effect and the complier average causal effect (CACE):
rdo$causal_effect(
method = "Fuzzy Neyman",
buffers = c(500, 1000, 1500),
num_it = 100,
outcome = "dropout",
typeoutcome = "binary",
treatm_cov = "W",
plot = TRUE
)
#> $table
#> Bandwidth Estimand ACE Neyman SE L U
#> 2 500 ITT.W 0.3794 0.0289 0.3228 0.4361
#> 3 500 ITT.Y -0.0595 0.0423 -0.1425 0.0235
#> 4 500 CACE -0.1568 0.1119 -0.3761 0.0625
#> 5 1000 ITT.W 0.3932 0.0206 0.3529 0.4336
#> 6 1000 ITT.Y -0.0260 0.0302 -0.0853 0.0332
#> 7 1000 CACE -0.0662 0.0769 -0.2170 0.0846
#> 8 1500 ITT.W 0.3778 0.0165 0.3454 0.4101
#> 9 1500 ITT.Y -0.0656 0.0246 -0.1139 -0.0173
#> 10 1500 CACE -0.1736 0.0657 -0.3025 -0.0448
#>
#> $plotThe Fuzzy FEP approach tests the null hypothesis of no effect for
compliers. Noncompliance can be one-sided
(sided = "onesided") or two-sided
(sided = "twosided"). Three test statistics are used: the
IV estimate, the maximum likelihood estimate (MLE), and the posterior
median of the CACE. The num_it_fuzzy argument controls the
number of iterations used to compute the MLE/posterior mode of the
complier average causal effects:
rdo$causal_effect(
method = "Fuzzy FEP",
buffers = c(500, 1000, 1500),
num_it = 100,
outcome = "dropout",
typeoutcome = "binary",
sided = "twosided",
treatm_cov = "W",
num_it_fuzzy = 5,
plot = TRUE
)
#> $table
#> $table[[1]]
#> Bandwidth Statistic: IV estimate of CACE Statistic: MLE of CACE
#> 2 500 0.0 0
#> 3 1000 0.2 0
#> 4 1500 0.0 0
#> Statistic: Posterior median of CACE
#> 2 0.0
#> 3 0.2
#> 4 0.0
#>
#> $table[[2]]
#> CACE.IV CACE.MLE CACE.PM
#> 2 0.121401861 0.120962946 0.1085443334
#> 3 -0.076923077 -0.077347660 -0.0509405694
#> 4 -0.020833333 -0.021235691 -0.0184509592
#> 5 -0.058316374 -0.057989495 -0.0746075755
#> 6 0.040497137 0.040750630 0.0373806480
#> 7 0.083178864 0.082580819 0.0729336064
#> 8 0.024202655 0.024636647 0.0199358256
#> 9 0.001076548 0.001474292 -0.0052912478
#> 10 0.026738593 0.027119947 0.0169827540
#> 11 -0.025550824 -0.025180402 -0.0230312374
#> 12 0.039389529 0.039074604 0.0363220111
#> 13 0.021868573 0.021503205 0.0290408361
#> 14 -0.068539020 -0.068833109 -0.0694434905
#> 15 0.004873657 0.005239995 -0.0005615341
#> 16 -0.019087523 -0.018808781 -0.0175841706
#>
#> $table[[3]]
#> [,1] [,2] [,3]
#> -0.15682699 -0.1564848 -0.13780520
#> -0.06619532 -0.0658559 -0.09382708
#> -0.17363510 -0.1733321 -0.17730450
#>
#>
#> $plotNote that the Fuzzy FEP approach is computationally more demanding than the other three; for final analyses with a large number of iterations, expect longer running times.
All the functionality described above is also available through a user-friendly Shiny application. It can be launched with:
The dashboard presents two sections: the input options on the left panel, managed through a drop-down list covering all the steps of the workflow, and the results on the right, in the result window.
The steps mirror the programmatic workflow:
grants dataset included in the package, or upload a dataset
from an Excel (.xlsx) or R (.RData) file.Li, F., Mattei, A. and Mealli, F. (2015). Bayesian inference for regression discontinuity designs with application to the evaluation of Italian university grants. The Annals of Applied Statistics, 9(4), 1906–1931. doi:10.1214/15-AOAS809
sessionInfo()
#> R version 4.3.3 (2024-02-29)
#> Platform: x86_64-pc-linux-gnu (64-bit)
#> Running under: Ubuntu 24.04.4 LTS
#>
#> Matrix products: default
#> BLAS: /usr/lib/x86_64-linux-gnu/blas/libblas.so.3.12.0
#> LAPACK: /usr/lib/x86_64-linux-gnu/lapack/liblapack.so.3.12.0
#>
#> locale:
#> [1] C
#>
#> time zone: Etc/UTC
#> tzcode source: system (glibc)
#>
#> attached base packages:
#> [1] stats graphics grDevices utils datasets methods base
#>
#> other attached packages:
#> [1] LRErdd_0.1.0
#>
#> loaded via a namespace (and not attached):
#> [1] gtable_0.3.4 jsonlite_1.8.8 dplyr_1.1.4 compiler_4.3.3
#> [5] highr_0.10 gtools_3.9.5 tidyselect_1.2.0 jquerylib_0.1.4
#> [9] scales_1.3.0 yaml_2.3.8 fastmap_1.1.1 ggplot2_3.4.4
#> [13] R6_2.5.1 labeling_0.4.3 generics_0.1.3 knitr_1.45
#> [17] tibble_3.2.1 munsell_0.5.0 bslib_0.6.1 pillar_1.9.0
#> [21] RColorBrewer_1.1-3 rlang_1.1.3 utf8_1.2.4 cachem_1.0.8
#> [25] xfun_0.41 sass_0.4.8 cli_3.6.2 withr_2.5.0
#> [29] magrittr_2.0.3 digest_0.6.34 grid_4.3.3 cowplot_1.1.3
#> [33] lifecycle_1.0.4 vctrs_0.6.5 evaluate_0.23 glue_1.7.0
#> [37] farver_2.1.1 fansi_1.0.5 colorspace_2.1-0 rmarkdown_2.25
#> [41] tools_4.3.3 pkgconfig_2.0.3 htmltools_0.5.7These binaries (installable software) and packages are in development.
They may not be fully stable and should be used with caution. We make no claims about them.
Health stats visible at Monitor.