R/benchmarks.R
benchmark_bounds.RdConstructs the bias-adjusted bounds on the target parameter implied by benchmarking against observed covariates, together with one-sided confidence bounds that propagate the estimation uncertainty of the benchmarked gains. Both the fixed-gain and the propagated bounds are returned so the two can be compared.
the dml fit used for the benchmark. Must be fit with a single target ("ate"/"att"/"atu").
either a dml_benchmark object (from
dml_benchmark, re-used without refitting) or the
benchmark_covariates to pass to dml_benchmark.
relative-strength multipliers \(k_{Y,j}\), \(k_{D,j}\) of the
latent-vs-observed gains. Either a single number or a vector with one entry
per benchmark covariate (in the order of benchmark). Default 1
(a latent confounder as strong as the observed covariate).
optional fixed squared alignment \(\rho^2\) to use in place of
the benchmarked \(\hat\rho_j\). NULL (default) uses covariate
\(j\)'s estimated (signed) alignment and, in the propagated CI, its
sampling uncertainty. A value in \([0, 1]\).
confidence level for the one-sided bounds. Default 0.95
(critical value \(\Phi^{-1}(level)\)).
how to combine cross-fitting repetitions,
"median" (default) or "mean". Each repetition's bound and its
influence-function SE are combined with the same rule as
confidence_bounds, so the reported SE folds in the
across-repetition spread of the estimate.
logical. Should repetitions with a missing benchmark gain be
dropped before the repetitions are combined? Default is TRUE. With
FALSE, a single failed repetition makes the combined gain
NA.
an object of class dml_benchmark_bounds.
number of digits to print.
ignored.
An object of class dml_benchmark_bounds (a data frame, one row
per benchmark covariate) with the bias factor BF, the point bounds
theta.minus/theta.plus, the fixed-gain confidence bounds
lwr.fixed/upr.fixed (\(=\)confidence_bounds), the
uncertainty-propagated confidence bounds lwr/upr, and the
propagated bound SEs se.minus/se.plus. Covariates whose implied
\(k_D \hat G_{D,j} \ge 1\) (cf.d reaches 1, so the bound diverges)
return -Inf/Inf bounds with a warning.
Chernozhukov, V., Cinelli, C., Newey, W., Sharma, A., and Syrgkanis, V. (2026). "Long Story Short: Omitted Variable Bias in Causal Machine Learning." Review of Economics and Statistics (Appendix E).
Wang, J., Sant'Anna, P. H. C., Chernozhukov, V., and Cinelli, C. (2026). "Omitted Variable Bias in Difference-in-Differences Designs." Working Paper. (Benchmarking for the conditional ATT/ATU.)
data("pension")
set.seed(3); idx <- sample(nrow(pension), 2000)
y <- pension$net_tfa[idx]
d <- pension$e401[idx]
x <- model.matrix(~ -1 + age + inc + educ + fsize + marr + twoearn + pira + hown,
data = pension[idx, ])
fit <- dml(y, d, x, model = "plm", cf.folds = 2, cf.seed = 3, verbose = FALSE)
# bounds implied by a latent variable as strong as income
bench <- dml_benchmark(fit, benchmark_covariates = "inc")
#>
#> === Computing benchmarks using covariate: inc ===
#>
benchmark_bounds(fit, bench, kY = 1, kD = 1)
#> Covariate benchmark bounds (kY = 1, kD = 1, rho2 = benchmarked; 95% one-sided)
#> theta.s = 12966.1442, S = 118534.2640
#>
#> BF theta.minus theta.plus lwr.fixed upr.fixed lwr upr
#> inc 0.027 9768.652 16163.64 4468.396 22025.71 3890.724 21788.42
#>
#> [theta.minus, theta.plus] point estimates of the bounds
#> [lwr.fixed, upr.fixed] confidence bounds treating benchmark as fixed
#> [lwr, upr] confidence bounds accounting for benchmark uncertainty