| Title: | Fast Double / Debiased Machine Learning Implemented in Rust |
|---|---|
| Description: | Double / debiased machine learning (Chernozhukov et al., 2018, <doi:10.1111/ectj.12097>) for causal inference: partially linear, interactive, instrumental variable and difference-in-differences models with cross-fitted nuisance functions, multiplier bootstrap and sensitivity analysis for omitted confounding. Estimation, including the nuisance learners (lasso, logistic regression, random forests, gradient boosting), runs in Rust through the 'dml-core' crate, in parallel. Results match the Python package 'dml-rs', which is validated against 'DoubleML'. |
| Authors: | Asad Gudzevic [aut, cre] |
| Maintainer: | Asad Gudzevic <[email protected]> |
| License: | MIT + file LICENSE |
| Version: | 0.1.0 |
| Built: | 2026-11-01 10:23:36 UTC |
| Source: | https://github.com/AsadGudzevic94/dml-rs |
Pointwise intervals, or simultaneous intervals for all treatments from the
multiplier bootstrap (joint = TRUE), as DoubleML's confint().
## S3 method for class 'dmlrs_fit' confint( object, parm, level = 0.95, joint = FALSE, method = c("normal", "Bayes", "wild"), n_boot = 500, seed = 0, ... )## S3 method for class 'dmlrs_fit' confint( object, parm, level = 0.95, joint = FALSE, method = c("normal", "Bayes", "wild"), n_boot = 500, seed = 0, ... )
object |
A fitted model. |
parm |
Treatments (names or indices); all by default. |
level |
Confidence level. |
joint |
Simultaneous intervals from the multiplier bootstrap. |
method |
Bootstrap weights: |
n_boot |
Number of bootstrap draws. |
seed |
Seed of the bootstrap. |
... |
Not used. |
A matrix with one row per treatment.
set.seed(3) n <- 400 x <- matrix(rnorm(n * 3), n) d <- cbind(d1 = x[, 1] + rnorm(n), d2 = x[, 2] + rnorm(n)) y <- 0.5 * d[, 1] - 0.2 * d[, 2] + x[, 3] + rnorm(n) fit <- dml_plr(y, d, x, ml_l = lrn_ols()) confint(fit, joint = TRUE, n_boot = 1000)set.seed(3) n <- 400 x <- matrix(rnorm(n * 3), n) d <- cbind(d1 = x[, 1] + rnorm(n), d2 = x[, 2] + rnorm(n)) y <- 0.5 * d[, 1] - 0.2 * d[, 2] + x[, 3] + rnorm(n) fit <- dml_plr(y, d, x, ml_l = lrn_ols()) confint(fit, joint = TRUE, n_boot = 1000)
The average treatment effect on the treated with two periods (Sant'Anna
and Zhao, 2020), as DoubleMLDID and DoubleMLDIDCS. With panel data,
y is the change of the outcome between the periods; with repeated
cross-sections, y is the outcome and t the period (0/1).
dml_did( y, d, x, t = NULL, ml_g = lrn_lasso_cv(), ml_m = lrn_logistic_cv(), score = c("observational", "experimental"), in_sample_normalization = TRUE, n_folds = 5, n_rep = 1, seed = 0 )dml_did( y, d, x, t = NULL, ml_g = lrn_lasso_cv(), ml_m = lrn_logistic_cv(), score = c("observational", "experimental"), in_sample_normalization = TRUE, n_folds = 5, n_rep = 1, seed = 0 )
y |
Outcome change (panel) or outcome (repeated cross-sections). |
d |
Binary treatment group indicator (0/1). |
x |
Covariates: a numeric matrix or data frame. |
t |
|
ml_g |
Learner for the outcome regressions. |
ml_m |
Classifier for the propensity score (not used by the
|
score |
|
in_sample_normalization |
Normalise the weights in sample, as DoubleML. |
n_folds |
Number of cross-fitting folds. |
n_rep |
Number of repetitions of the sample split; estimates are aggregated with the median, as in DoubleML. |
seed |
Seed of the sample splits. |
A dmlrs_fit object; see stats::coef(), confint.dmlrs_fit(), base::summary() and
sensitivity_analysis().
Local average treatment effect of a binary treatment with a binary
instrument, as DoubleMLIIVM.
dml_iivm( y, d, z, x, ml_g = lrn_lasso_cv(), ml_m = lrn_logistic_cv(), ml_r = ml_m, subgroups = c(always_takers = TRUE, never_takers = TRUE), n_folds = 5, n_rep = 1, seed = 0 )dml_iivm( y, d, z, x, ml_g = lrn_lasso_cv(), ml_m = lrn_logistic_cv(), ml_r = ml_m, subgroups = c(always_takers = TRUE, never_takers = TRUE), n_folds = 5, n_rep = 1, seed = 0 )
y |
Outcome (numeric vector). |
d |
Binary treatment (0/1). |
z |
Binary instrument (0/1). |
x |
Covariates: a numeric matrix or data frame. |
ml_g |
Learner for |
ml_m |
Classifier for |
ml_r |
Classifier for |
subgroups |
Named logical vector: whether there can be
|
n_folds |
Number of cross-fitting folds. |
n_rep |
Number of repetitions of the sample split; estimates are aggregated with the median, as in DoubleML. |
seed |
Seed of the sample splits. |
A dmlrs_fit object; see stats::coef(), confint.dmlrs_fit(), base::summary() and
sensitivity_analysis().
Average treatment effect ("ATE") or average treatment effect on the
treated ("ATTE") of a binary treatment, as DoubleMLIRM.
dml_irm( y, d, x, ml_g = lrn_lasso_cv(), ml_m = lrn_logistic_cv(), score = c("ATE", "ATTE"), clipping_threshold = 0.01, normalize_ipw = FALSE, n_folds = 5, n_rep = 1, seed = 0 )dml_irm( y, d, x, ml_g = lrn_lasso_cv(), ml_m = lrn_logistic_cv(), score = c("ATE", "ATTE"), clipping_threshold = 0.01, normalize_ipw = FALSE, n_folds = 5, n_rep = 1, seed = 0 )
y |
Outcome (numeric vector). |
d |
Binary treatment (0/1). |
x |
Covariates: a numeric matrix or data frame. |
ml_g |
Learner for |
ml_m |
Classifier for the propensity score |
score |
|
clipping_threshold |
Propensity scores are clipped to
|
normalize_ipw |
Normalise the inverse-probability weights. |
n_folds |
Number of cross-fitting folds. |
n_rep |
Number of repetitions of the sample split; estimates are aggregated with the median, as in DoubleML. |
seed |
Seed of the sample splits. |
A dmlrs_fit object; see stats::coef(), confint.dmlrs_fit(), base::summary() and
sensitivity_analysis().
set.seed(2) n <- 1000 x <- matrix(rnorm(n * 4), n) d <- rbinom(n, 1, plogis(x[, 1])) y <- d + x[, 1] + rnorm(n) dml_irm(y, d, x, ml_g = lrn_ols(), ml_m = lrn_logistic())set.seed(2) n <- 1000 x <- matrix(rnorm(n * 4), n) d <- rbinom(n, 1, plogis(x[, 1])) y <- d + x[, 1] + rnorm(n) dml_irm(y, d, x, ml_g = lrn_ols(), ml_m = lrn_logistic())
The partially linear model with an endogenous treatment and one
instrument , as DoubleMLPLIV ("partialling out" score).
dml_pliv( y, d, z, x, ml_l = lrn_lasso_cv(), ml_m = ml_l, ml_r = ml_l, n_folds = 5, n_rep = 1, seed = 0 )dml_pliv( y, d, z, x, ml_l = lrn_lasso_cv(), ml_m = ml_l, ml_r = ml_l, n_folds = 5, n_rep = 1, seed = 0 )
y |
Outcome (numeric vector). |
d |
Treatment: a numeric vector, or a matrix with one column per treatment (column names become the treatment names). |
z |
Instrument (numeric vector). |
x |
Covariates: a numeric matrix or data frame. |
ml_l |
Learner for |
ml_m |
Learner for |
ml_r |
Learner for |
n_folds |
Number of cross-fitting folds. |
n_rep |
Number of repetitions of the sample split; estimates are aggregated with the median, as in DoubleML. |
seed |
Seed of the sample splits. |
A dmlrs_fit object; see stats::coef(), confint.dmlrs_fit(), base::summary() and
sensitivity_analysis().
Double / debiased machine learning for the partially linear model
, as DoubleMLPLR. The nuisance
functions are cross-fitted in Rust.
dml_plr( y, d, x, ml_l = lrn_lasso_cv(), ml_m = ml_l, ml_g = NULL, score = c("partialling out", "IV-type"), n_folds = 5, n_rep = 1, seed = 0 )dml_plr( y, d, x, ml_l = lrn_lasso_cv(), ml_m = ml_l, ml_g = NULL, score = c("partialling out", "IV-type"), n_folds = 5, n_rep = 1, seed = 0 )
y |
Outcome (numeric vector). |
d |
Treatment: a numeric vector, or a matrix with one column per treatment (column names become the treatment names). |
x |
Covariates: a numeric matrix or data frame. |
ml_l |
Learner for |
ml_m |
Learner for |
ml_g |
Learner for |
score |
|
n_folds |
Number of cross-fitting folds. |
n_rep |
Number of repetitions of the sample split; estimates are aggregated with the median, as in DoubleML. |
seed |
Seed of the sample splits. |
A dmlrs_fit object; see stats::coef(), confint.dmlrs_fit(), base::summary() and
sensitivity_analysis().
set.seed(1) n <- 500 x <- matrix(rnorm(n * 5), n) d <- x[, 1] + rnorm(n) y <- 0.5 * d + x[, 2] + rnorm(n) fit <- dml_plr(y, d, x, ml_l = lrn_lasso_cv()) fit confint(fit)set.seed(1) n <- 500 x <- matrix(rnorm(n * 5), n) d <- x[, 1] + rnorm(n) y <- 0.5 * d + x[, 2] + rnorm(n) fit <- dml_plr(y, d, x, ml_l = lrn_lasso_cv()) fit confint(fit)
Learners for the nuisance functions of the DML models, implemented in Rust.
Parameters follow scikit-learn, and results match the learners of the
Python package dml-rs. Regressors learn conditional means; classifiers
(lrn_logistic(), lrn_logistic_cv(), and the tree ensembles) learn
probabilities of a binary variable.
lrn_ols(ridge = 0) lrn_lasso(alpha = 1, tol = 1e-04, max_iter = 1e+05) lrn_lasso_cv(n_alphas = 100, eps = 0.001, cv = 5) lrn_logistic(C = 1) lrn_logistic_cv(n_cs = 10, cv = 5) lrn_random_forest( n_estimators = 100, max_depth = NULL, min_samples_leaf = 1, max_features = NULL, random_state = 0 ) lrn_gradient_boosting( n_estimators = 100, learning_rate = 0.1, max_depth = 3, min_samples_leaf = 1, subsample = 1, random_state = 0 ) lrn_hist_gradient_boosting( max_iter = 100, learning_rate = 0.1, max_leaf_nodes = 31, min_samples_leaf = 20, l2_regularization = 0, random_state = 0 ) lrn_regression_forest(n_estimators = 2000, min_node_size = 5, random_state = 0)lrn_ols(ridge = 0) lrn_lasso(alpha = 1, tol = 1e-04, max_iter = 1e+05) lrn_lasso_cv(n_alphas = 100, eps = 0.001, cv = 5) lrn_logistic(C = 1) lrn_logistic_cv(n_cs = 10, cv = 5) lrn_random_forest( n_estimators = 100, max_depth = NULL, min_samples_leaf = 1, max_features = NULL, random_state = 0 ) lrn_gradient_boosting( n_estimators = 100, learning_rate = 0.1, max_depth = 3, min_samples_leaf = 1, subsample = 1, random_state = 0 ) lrn_hist_gradient_boosting( max_iter = 100, learning_rate = 0.1, max_leaf_nodes = 31, min_samples_leaf = 20, l2_regularization = 0, random_state = 0 ) lrn_regression_forest(n_estimators = 2000, min_node_size = 5, random_state = 0)
ridge, alpha, C
|
Penalties (see above). |
tol, max_iter
|
Convergence tolerance and maximum iterations (sweeps of
coordinate descent, or boosting iterations for |
n_alphas, eps, n_cs, cv
|
Grid size, smallest-to-largest penalty ratio and number of folds of the cross-validated learners. |
n_estimators |
Number of trees. |
max_depth |
Maximum tree depth ( |
min_samples_leaf |
Minimum observations per leaf. |
max_features |
Features tried per split: |
random_state |
Seed. |
learning_rate |
Shrinkage of each tree. |
subsample |
Share of observations used for each tree. |
max_leaf_nodes |
Maximum leaves per tree ( |
l2_regularization |
L2 penalty on leaf values. |
min_node_size |
Minimum observations per leaf (grf's |
lrn_ols(): least squares with intercept, optionally ridge-penalised
(ridge is scikit-learn's Ridge(alpha)).
lrn_lasso(): lasso with penalty alpha (scikit-learn's Lasso).
lrn_lasso_cv(): lasso with the penalty chosen by cv-fold
cross-validation over n_alphas values (scikit-learn's LassoCV).
lrn_logistic(): L2-penalised logistic regression with inverse penalty C.
lrn_logistic_cv(): logistic regression with C chosen by stratified
cross-validation (log loss) over n_cs values from 1e-4 to 1e4.
lrn_random_forest(): random forest (regressor or classifier).
lrn_gradient_boosting(): gradient boosting with the trees of
scikit-learn's GradientBoosting*.
lrn_hist_gradient_boosting(): histogram gradient boosting, identical to
scikit-learn's HistGradientBoosting*; the learner for large data.
lrn_regression_forest(): honest regression forest (R's
grf::regression_forest), regression only.
A learner specification (class dmlrs_learner).
lrn_lasso_cv() lrn_random_forest(n_estimators = 200, min_samples_leaf = 5)lrn_lasso_cv() lrn_random_forest(n_estimators = 200, min_samples_leaf = 5)
Bounds on the effect and robustness values when the confounding is as
strong as cf_y (share of the residual outcome variance) and cf_d
(share of the residual Riesz representer variance), with correlation
rho (Chernozhukov et al., 2022), as DoubleML's sensitivity_analysis().
Available for PLR, IRM and DID fits.
sensitivity_analysis( object, cf_y = 0.03, cf_d = 0.03, rho = 1, level = 0.95, null_hypothesis = 0 )sensitivity_analysis( object, cf_y = 0.03, cf_d = 0.03, rho = 1, level = 0.95, null_hypothesis = 0 )
object |
A fitted model. |
cf_y, cf_d
|
Confounding strengths. |
rho |
Correlation of the confounding in the outcome and treatment. |
level |
Confidence level of the bounds. |
null_hypothesis |
Value of the effect under the null hypothesis. |
A data frame with one row per treatment: the bounds on the effect
(theta_lower, theta_upper), their confidence bounds (ci_lower,
ci_upper) and the robustness values rv and rva (in percent).
set.seed(4) n <- 500 x <- matrix(rnorm(n * 3), n) d <- x[, 1] + rnorm(n) y <- 0.5 * d + x[, 2] + rnorm(n) sensitivity_analysis(dml_plr(y, d, x, ml_l = lrn_ols()))set.seed(4) n <- 500 x <- matrix(rnorm(n * 3), n) d <- x[, 1] + rnorm(n) y <- 0.5 * d + x[, 2] + rnorm(n) sensitivity_analysis(dml_plr(y, d, x, ml_l = lrn_ols()))