



| DGP ID | synth_placebo_tilted |
| Version | 1.4.0 |
| Status | experimental |
| Difficulty | ★★★★☆ (4/5) |
| Stress Profile | overlap: moderatenoise: gaussianlinearity: lineareffect: constanttarget: both |
Intent: The “Spurious Correlation Trap.” This DGP induces strong (but manageable) linear confounding where treated units have naturally higher outcomes than control units (\(p(X)\) aligns with \(\mu_0(X)\)).
The Scientific Question: “Can the estimator distinguish Selection Bias from Treatment Effect?” A naive comparison suggests a strong positive effect. The estimator must vigorously adjust for covariates to recover the true zero. This tests resistance to “Bias Leakage.”
Covariates: \(X_1, X_2, X_3, X_4, X_5 \sim \mathcal{N}(0, 1^2)\) independently.
Outcome (control): \[\mu_0(X) = 1 + X_1 + 0.5 X_2\]
Propensity (tilted): \[p(X) = \text{expit}(0.6 X_1 + 0.8 X_2)\]
Treatment effect (sharp null): \[\tau(X) \equiv 0\]
Noise: \[\varepsilon \sim \mathcal{N}(0, 0.5^2)\] (Shared noise \(Y_1 \equiv Y_0\))




We validate only the oracle estimator to keep builds fast.
| mean_bias | rmse |
|---|---|
| 0 | 0 |
R/dgp-synth-placebo-tilted.R (v1.4.0)cs_dgp_registry() entry for synth_placebo_tiltedtrue_att = 0, true_qst = 0cs_get_oracle_qst("synth_placebo_tilted", version = "1.4.0")Source code for: dgp_synth_placebo_tilted_v140
function (n, seed = NULL, include_truth = TRUE, oracle_only = FALSE)
{
if (!is.null(seed)) {
cs_set_rng(seed)
}
X1 <- stats::rnorm(n, mean = 0, sd = 1)
X2 <- stats::rnorm(n, mean = 0, sd = 1)
X3 <- stats::rnorm(n, mean = 0, sd = 1)
X4 <- stats::rnorm(n, mean = 0, sd = 1)
X5 <- stats::rnorm(n, mean = 0, sd = 1)
mu0 <- 1 + X1 + 0.5 * X2
tau <- rep(0, n)
p <- stats::plogis(0.6 * X1 + 0.8 * X2)
w <- stats::rbinom(n, size = 1L, prob = p)
eps <- stats::rnorm(n, mean = 0, sd = 0.5)
y0 <- mu0 + eps
y1 <- y0
if (isTRUE(oracle_only)) {
return(list(df = tibble::tibble(w = w, y0 = y0, y1 = y1)))
}
y <- ifelse(w == 1L, y1, y0)
true_att <- cs_true_att(structural_te = tau, w = w)
true_qst <- if (isTRUE(include_truth))
cs_get_oracle_qst("synth_placebo_tilted", version = "1.4.0")
else NULL
out <- list(df = tibble::tibble(y = y, w = w, y0 = y0, y1 = y1,
p = p, structural_te = tau, X1 = X1, X2 = X2, X3 = X3,
X4 = X4, X5 = X5), true_att = true_att, true_qst = true_qst,
meta = list(dgp_id = "synth_placebo_tilted", version = "1.4.0",
type = "synthetic", params = list(n = n, seed = seed),
structural_te = tau))
cs_check_dgp_synthetic(out)
out
}
<bytecode: 0x55e18b30d470>
<environment: namespace:CausalStress>