Causal Design / Assignment Mechanisms
RCTs and Quasi-Experimental Designs
RCTs create exchangeability through controlled randomization; quasi-experiments search for as-if random assignment in rules, thresholds, lotteries, timing shocks, or policy boundaries.
Mechanism Lab
Animation: how assignment mechanisms create causal evidence
The animation places units into baseline blocks, randomizes treatment, estimates the mean contrast, routes noncompliance through Z to D, and maps quasi-experimental rules as assignment mechanisms.
Step 1 / 5
Eligible sample
Define the sample and baseline blocks before assigning treatment.
i=1,...,N; blocks bAnimation Control
Reduced-motion users receive the same step states without continuous motion.
01 / Intuition
Core Intuition
Good causal design first answers why units receive treatment, then estimates how large the effect is. If the assignment mechanism is credible, a simple contrast can carry strong interpretation.
The strength of an RCT is that the researcher controls assignment Z or D, making treated and control groups have the same potential-outcome distribution in expectation.
A quasi-experiment is not a license to run arbitrary regressions without randomization. It treats an external rule as a natural assignment mechanism and builds diagnostics around that rule.
02 / Math
From random assignment to quasi-experimental identification
01 / Complete random experiment
Choose N1 treated units out of N and leave N0 in control. The potential-outcome table is fixed before assignment; randomness comes only from D.
sum_i D_i = N_1, N_0=N-N_1
Y_i^obs = D_i Y_i(1) + (1-D_i)Y_i(0)02 / Exchangeability
Randomization makes assignment independent of potential outcomes, so observed treated and control means are unbiased for their potential-outcome population means.
D independent (Y(1),Y(0))
E[bar Y_1^obs] = bar Y(1), E[bar Y_0^obs] = bar Y(0)03 / Unbiased difference in means
The difference-in-means estimator has expectation equal to the finite-population ATE.
tau_hat = (1/N_1) sum_{D_i=1} Y_i^obs - (1/N_0) sum_{D_i=0} Y_i^obs
E_D[tau_hat] = (1/N) sum_i {Y_i(1)-Y_i(0)}04 / Neyman variance
Under complete randomization, variance depends on both potential-outcome variances and treatment-effect heterogeneity. Because S_tau^2 is not observed, the usual estimator is conservative.
Var(tau_hat) = S_1^2/N_1 + S_0^2/N_0 - S_tau^2/N
V_hat = s_1^2/N_1 + s_0^2/N_005 / Randomization inference
Under a sharp null, all missing potential outcomes are known, so one can enumerate or simulate the assignment distribution of a statistic.
H_0: Y_i(1)-Y_i(0)=tau_0 for all i
p = Pr_D(|T(D)| >= |T(D_obs)| | H_0)06 / Blocked randomization
Randomize within baseline risk groups, schools, or regions, then aggregate block-specific effects by block size. This often reduces variance by comparing like with like.
tau_hat_blocked = sum_b (N_b/N) tau_hat_b07 / Noncompliance and ITT/LATE
When the randomized variable is an offer or encouragement Z and actual participation D is imperfect, report ITT first. With relevance, exclusion, and monotonicity, Z identifies complier LATE.
ITT_Y = E[Y|Z=1]-E[Y|Z=0]
ITT_D = E[D|Z=1]-E[D|Z=0]
LATE = ITT_Y / ITT_D08 / Quasi-experimental designs
The issue is not model complexity. The issue is whether a rule, boundary, or timing shock creates as-if random variation locally or within a defensible window.
assignment rule -> as-if random variation -> diagnostic checks -> causal estimand03 / Code
Python code: RCT, randomization inference, blocks, and noncompliance
The simulation demonstrates four ideas: difference-in-means for an RCT, a randomization-inference p-value, a blocked estimator, and ITT/LATE under noncompliance.
import numpy as np
import pandas as pd
rng = np.random.default_rng(123)
n = 800
school = rng.integers(0, 8, size=n)
baseline = rng.normal(0, 1, size=n) + 0.25 * school
# Fixed potential outcomes.
y0 = 50 + 5 * baseline + rng.normal(0, 4, size=n)
tau = 3.0 + 1.2 * (baseline < 0)
y1 = y0 + tau
true_ate = np.mean(tau)
# Complete random assignment.
n1 = n // 2
d = np.zeros(n, dtype=int)
d[rng.choice(n, size=n1, replace=False)] = 1
y = d * y1 + (1 - d) * y0
def diff_in_means(outcome, treat):
return outcome[treat == 1].mean() - outcome[treat == 0].mean()
tau_hat = diff_in_means(y, d)
se_neyman = np.sqrt(y[d == 1].var(ddof=1) / d.sum() + y[d == 0].var(ddof=1) / (n - d.sum()))
# Randomization inference under the sharp null of no effect.
observed_t = diff_in_means(y, d)
null_stats = []
for _ in range(5000):
d_perm = np.zeros(n, dtype=int)
d_perm[rng.choice(n, size=n1, replace=False)] = 1
null_stats.append(diff_in_means(y, d_perm))
p_value = np.mean(np.abs(null_stats) >= abs(observed_t))
# Blocked estimate: compare within school, then aggregate.
df = pd.DataFrame({"Y": y, "D": d, "school": school})
blocked = (
df.groupby("school")
.apply(lambda g: pd.Series({
"n": len(g),
"tau_b": diff_in_means(g["Y"].to_numpy(), g["D"].to_numpy())
}))
.reset_index()
)
tau_blocked = np.average(blocked["tau_b"], weights=blocked["n"])
# Noncompliance: randomized offer Z, actual take-up D.
z = np.zeros(n, dtype=int)
z[rng.choice(n, size=n1, replace=False)] = 1
complier = rng.binomial(1, 0.72, size=n)
always_taker = rng.binomial(1, 0.08, size=n)
d_actual = np.maximum(always_taker, z * complier)
y_nc = y0 + d_actual * tau + rng.normal(0, 2, size=n)
itt_y = diff_in_means(y_nc, z)
itt_d = diff_in_means(d_actual, z)
late = itt_y / itt_d
print({
"true_ate": round(true_ate, 3),
"rct_tau_hat": round(tau_hat, 3),
"neyman_se": round(se_neyman, 3),
"randomization_p": round(p_value, 4),
"blocked_tau_hat": round(tau_blocked, 3),
"itt_y": round(itt_y, 3),
"itt_d": round(itt_d, 3),
"late_wald": round(late, 3),
})04 / Case
Case: lottery offers and quasi-experimental extensions for an education bootcamp
- Question: does a summer data bootcamp improve later project scores? If applicants exceed seats, a lottery offer can serve as randomized encouragement.
- The primary analysis reports ITT: whether being offered a seat raises average outcomes. This matches the policy effect of offering seats or invitations.
- If some offered students do not attend and some non-offered students find another route in, actual participation D is not fully randomized. With defensible exclusion and monotonicity, offer Z can estimate complier LATE.
- Without a lottery, assignment may come from a cutoff, regional pilot, grade cohort, or policy timing. That becomes quasi-experimental, and the rule itself must justify local as-if random variation.
- A credible report includes the experiment flow, preregistration or sample flow, baseline balance, attrition, noncompliance, spillovers, multiple testing, randomization inference or clustered standard errors, and all deviations from the original design.
05 / Risks
Common Pitfalls
References
- Fisher (1935), The Design of Experimentshttps://archive.org/details/designofexperime00fish
- Neyman (1990 translation), On the Application of Probability Theory to Agricultural Experimentshttps://doi.org/10.1214/ss/1177012031
- Duflo, Glennerster, and Kremer (2007), Using Randomization in Development Economics Researchhttps://doi.org/10.1016/S1573-4471(07)04061-2
- Gerber and Green, Field Experimentshttps://wwnorton.com/books/Field-Experiments/