rdd-analysis
|
它会碰到什么
这一栏是扫描器报的事实,不是结论。命中多不等于有毒(安全工具、规则库、示例脚本本来就会包含危险写法),命中少也不等于干净。它和你手上的凭据、文件、网络有什么关系,需要你自己看。
技能内容
Regression Discontinuity Design (RDD) Skill
This skill covers sharp and fuzzy RDD: identification assumptions, bandwidth selection, local polynomial estimation, validity tests, and reporting standards for academic papers.
Core Logic
RDD exploits a known threshold in a continuous "running variable" (X) that determines treatment assignment. Units just above and below the cutoff (c) are comparable on all dimensions except treatment.
Sharp RDD: Treatment perfectly determined by crossing cutoff
- T_i = 1 if X_i ≥ c, T_i = 0 if X_i < c
- Estimand: Average treatment effect at the cutoff (τ_SRD)
Fuzzy RDD: Crossing cutoff increases probability of treatment (like an instrument)
- Use when there's non-compliance around the cutoff
- Estimand: LATE at the cutoff (τ_FRD = reduced form / first stage)
RDD Assumptions
- Continuity of conditional expectation: E[Y(0)|X] and E[Y(1)|X] are continuous at X = c
- Means: units cannot precisely manipulate running variable to select into treatment
- No other discontinuities: Nothing else changes discontinuously at the cutoff
- Bandwidth continuity: Observations near cutoff are locally valid comparisons
Complete RDD Workflow
Step 1: Visualize the Discontinuity
Always plot the raw data with binned means before any regression.
# Python
import matplotlib.pyplot as plt
import numpy as np
# Bin the running variable
df['bin'] = pd.cut(df['running_var'], bins=50)
bin_means = df.groupby('bin')[['running_var', 'y']].mean().reset_index()
plt.figure(figsize=(10, 6))
plt.scatter(bin_means['running_var'], bin_means['y'], s=30, color='steelblue')
plt.axvline(x=cutoff, color='red', linestyle='--', label='Cutoff')
plt.xlabel('Running Variable'); plt.ylabel('Outcome')
plt.title('RDD: Binned Scatter Plot')
plt.legend(); plt.show()
# R (rdplot from rdrobust)
library(rdrobust)
rdplot(y = df$y, x = df$running_var, c = cutoff,
title = "RDD Binned Scatter", x.label = "Running Variable",
y.label = "Outcome")
rdplot y running_var, c(cutoff) graph_options(title("RDD Visualization"))
Step 2: Bandwidth Selection
Default: Use Imbens-Kalyanaraman (IK) or Calonico-Cattaneo-Titiunik (CCT) optimal bandwidth.
from rdrobust import rdrobust
result = rdrobust(df['y'], df['running_var'], c=cutoff)
print(result.summary())
rdbwselect(y = df$y, x = df$running_var, c = cutoff)
rdbwselect y running_var, c(cutoff) all
Step 3: Main RDD Estimate
# Python (rdrobust) — triangular kernel, local linear
result = rdrobust(y=df['y'], x=df['running_var'], c=cutoff,
kernel='triangular', p=1)
print(result.summary())
# R
main_rdd <- rdrobust(y = df$y, x = df$running_var, c = cutoff,
kernel = "triangular", p = 1)
summary(main_rdd)
rdrobust y running_var, c(cutoff) kernel(triangular) p(1)
Step 4: Validity Tests (All Required)
4a. Density/Manipulation Test (McCrary Test)
H₀: No discontinuity in density of running variable at cutoff
from rdrobust import rddensity
density_test = rddensity(df['running_var'], c=cutoff)
print(density_test.summary())
library(rddensity)
rdd_density <- rddensity(df$running_var, c = cutoff)
summary(rdd_density)
rdplotdensity(rdd_density, df$running_var)
rddensity running_var, c(cutoff)
Interpretation: p > 0.05 → no bunching; manipulation unlikely ✓
4b. Covariate Balance (Placebo Outcome Tests)
Run RDD on pre-determined covariates — should find no discontinuity.
for (cov in c("age", "income_pre", "gender")) {
res <- rdrobust(y = df[[cov]], x = df$running_var, c = cutoff)
cat(cov, ": coef =", res$coef[1], ", p =", res$pv[3], "\n")
}
4c. Placebo Cutoff Tests
Run RDD at fake cutoffs above and below actual cutoff — should find no effects.
for (fake_c in c(cutoff - 5, cutoff + 5)) {
df_sub <- df[df$running_var < cutoff, ] # Use only control side
res <- rdrobust(df_sub$y, df_sub$running_var, c = fake_c)
cat("Placebo c =", fake_c, ": coef =", res$coef[1], "\n")
}
4d. Bandwidth Sensitivity
Report estimates at 50%, 75%, 125%, 150% of optimal bandwidth.
bw_opt <- rdbwselect(df$y, df$running_var, c = cutoff)$bws[1,1]
for (mult in c(0.5, 0.75, 1, 1.25, 1.5)) {
res <- rdrobust(df$y, df$running_var, c = cutoff, h = bw_opt * mult)
cat("BW =", round(bw_opt*mult,2), ": coef =", round(res$coef[1],3),
", p =", round(res$pv[3],3), "\n")
}
Fuzzy RDD
# R — fuzzy RDD (uses crossing as instrument for actual treatment)
fuzzy_rdd <- rdrobust(y = df$y, x = df$running_var, c = cutoff,
fuzzy = df$actual_treatment)
summary(fuzzy_rdd)
rdrobust y running_var, c(cutoff) fuzzy(actual_treatment)
Reporting Standards
Report in this order:
- Binned scatter plot showing discontinuity visually
- Main estimate with optimal CCT bandwidth, triangular kernel, local linear
- Sensitivity table: estimates across bandwidth multiples and polynomial orders
- Validity tests: density test (McCrary), covariate balance, placebo cutoffs
- Sample size: N total, N within bandwidth (left and right)
Key sentence template for papers:
> "We estimate the RDD using a local linear regression with a triangular kernel and the CCT optimal bandwidth (h = [X]). The point estimate at the cutoff is [β] (SE = [se], p = [p])."
See references/rdd-reference.md for geographic RDD, kink designs, donut-hole robustness, discrete running variable RDD, and multi-cutoff/multi-score RDD.
Common Pitfalls
- Using global polynomial regression: High-order global polynomials (e.g., 5th degree) overfit and produce misleading results — always use local linear or local quadratic
- Not showing the binned scatter plot: The visual discontinuity is crucial for credibility — always include it
- Ignoring manipulation: A failed McCrary test means your RDD is fundamentally compromised — address the sorting concern
- Reporting only one bandwidth: Show sensitivity across 50%–150% of optimal bandwidth to demonstrate robustness
- Using RDD far from cutoff: RDD estimates are valid only at the cutoff — do not extrapolate to units far from the threshold
Related Skills & Commands
- did-analysis: If treatment doesn't have a sharp threshold, consider DID instead
- iv-estimation: Fuzzy RDD is essentially an IV design at the cutoff
- stats: Summarize data around the cutoff for the "Data" section
- /diagnose: Run RDD validity tests (density, covariate balance, placebo cutoffs)
- /robustness: Bandwidth sensitivity, polynomial order, kernel type
- /plot: Create publication-quality RDD binned scatter plots
想直接用这个技能?
本站把开放许可(MIT / Apache 等)的技能按仓库打包整理到网盘,点一下转存到你自己的网盘,不用一个个从 GitHub 拉。许可未声明的技能只给原始仓库链接,不打包。
它属于哪个仓库
skills/67-econfin-workflow-toolkit/rdd-analysis/SKILL.md同一个仓库里的其他技能
- Full-empirical-analysis-skill
- Full-empirical-analysis-skill-R
- Full-empirical-analysis-skill-Stata
- auto-empirical-research-skills
- StatsPAI_skill
- Full-empirical-analysis-skill
- Full-empirical-analysis-skill-Stata
- Full-empirical-analysis-skill-R
- academic-paper-composer
- academic-paper-strategist
- medical-imaging-review
- paper-slide-deck