用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
直接命令不会经过审查 Prompt;运行前请先检查来源。
npx skills add https://github.com/brycewang-stanford/Auto-Empirical-Research-Skills --skill sensitivity-analyst命令会保持在同一行。复制前请横向滚动并检查完整内容。
想先保存到本地?可下载 SkillsMP 当前能够提供的文件。
Route empirical-research requests through the Auto-Empirical Research Skills catalog when this whole repository is installed as one skill in Codex, CodeBuddy, Claude Code, or another IDE. Use to choose and load the right vendored AERS skill for causal inference, econometrics, replication, data acquisition, manuscript writing, peer review and referee responses, citation checking, de-AIGC editing, or full empirical-paper workflows without reading the entire repository at once.
中英双语学术降 AIGC / bilingual academic de-AIGC skill. Removes AI-generated writing signatures from empirical papers in economics, management, and the social sciences — in both English and Chinese. Covers Turnitin AI, GPTZero, Originality.ai on the English side and 知网 AMLC, 万方, 维普 on the Chinese side. Uses a six-step loop (intake → audit → claim-evidence check → differentiated rewrite → five-dimension self-score → cold-reader recheck) with two pattern libraries (22 English + 17 Chinese patterns), section-by-section strategies for empirical papers, and hard protections that keep every number, coefficient, and citation intact.
Use when a research task needs reproducible Kaggle discovery, metadata inspection, bounded public-data downloads, competition or kernel discovery, model discovery, or an explicitly approved Kaggle write/delete operation through the official CLI.
基于 SOC 职业分类
正在显示 SKILL.md
| name | sensitivity-analyst |
| description | Sensitivity analysis frameworks and assumption-testing methods |
Comprehensive sensitivity analysis frameworks for causal inference and mediation studies
Use this skill when working on: unmeasured confounding assessment, E-values, tipping point analysis, measurement error sensitivity, model misspecification checks, Rosenbaum bounds, or any robustness evaluation for causal claims.
In causal inference, we can never directly test the assumption of no unmeasured confounding. Sensitivity analysis quantifies: "How strong would unmeasured confounding need to be to explain away our findings?"
For an unmeasured confounder $U$ affecting both treatment $A$ and outcome $Y$:
$$\text{Bias} = \frac{E[Y \mid A=1, U=1] - E[Y \mid A=1, U=0]}{E[Y \mid A=0, U=1] - E[Y \mid A=0, U=0]} \times \frac{P(U=1 \mid A=1) - P(U=1 \mid A=0)}{1}$$
The observed effect $\hat{\theta}$ relates to the true effect $\theta$ via:
$$\hat{\theta} = \theta \times \text{Bias Factor}$$
| Parameter | Definition | Range |
|---|---|---|
| $\gamma$ | Odds ratio for U-A association | $[1, \infty)$ |
| $\delta$ | Odds ratio for U-Y association | $[1, \infty)$ |
| $\rho$ | Correlation of U with unmeasured factors | $[-1, 1]$ |
#' Sensitivity Analysis for Unmeasured Confounding
#'
#' @param estimate Point estimate of causal effect
#' @param se Standard error of estimate
#' @param gamma_range Range of treatment-confounder association
#' @param delta_range Range of outcome-confounder association
#' @return Sensitivity analysis results
sensitivity_unmeasured <- function(estimate, se,
gamma_range = seq(1, 3, 0.25),
delta_range = seq(1, 3, 0.25)) {
# Create grid of sensitivity parameters
grid <- expand.grid(gamma = gamma_range, delta = delta_range)
# Compute bias factor for each combination
# Using Ding & VanderWeele (2016) bias formula
grid$bias_factor <- with(grid, (gamma * delta) / (gamma + delta - 1))
# Adjusted estimates
grid$adjusted_estimate <- estimate / grid$bias_factor
# Find tipping point where CI includes 0
z_crit <- qnorm(0.975)
ci_lower <- estimate - z_crit * se
# Tipping point: where adjusted CI lower bound = 0
tipping_points <- grid[grid$adjusted_estimate - z_crit * se / grid$bias_factor <= 0, ]
list(
original = list(estimate = estimate, ci = c(ci_lower, estimate + z_crit * se)),
sensitivity_grid = grid,
tipping_points = tipping_points,
minimum_bias_to_nullify = min(grid$bias_factor[grid$adjusted_estimate <= 0])
)
}
The E-value (VanderWeele & Ding, 2017) is the minimum strength of association that an unmeasured confounder would need to have with both treatment and outcome to fully explain away the observed effect.
For a risk ratio $RR$:
$$E\text{-value} = RR + \sqrt{RR \times (RR - 1)}$$
For the confidence interval limit:
$$E\text{-value}{CI} = RR{lower} + \sqrt{RR_{lower} \times (RR_{lower} - 1)}$$
| E-value | Interpretation |
|---|---|
| < 1.5 | Very weak; easily explained by modest confounding |
| 1.5 - 2.0 | Weak; moderate confounding could explain |
| 2.0 - 3.0 | Moderate; substantial confounding needed |
| 3.0 - 4.0 | Strong; would require strong confounding |
| > 4.0 | Very strong; unlikely to be fully explained |
| Measure | Formula |
|---|---|
| Risk Ratio (RR) | $E = RR + \sqrt{RR(RR-1)}$ |
| Odds Ratio (OR) | Convert to RR approximation first |
| Hazard Ratio (HR) | $E = HR + \sqrt{HR(HR-1)}$ (when rare outcome) |
| Risk Difference | Convert to RR using baseline risk |
| Standardized Mean Difference | $E = \exp(0.91 \times d) + \sqrt{\exp(0.91 \times d)(\exp(0.91 \times d)-1)}$ |
#' Compute E-value for Causal Effect Estimate
#'
#' @param estimate Effect estimate (RR, OR, HR, or SMD)
#' @param lo Lower confidence limit
#' @param hi Upper confidence limit
#' @param type Type of effect measure
#' @param rare For OR/HR, is outcome rare (<15%)?
#' @return E-value and interpretation
compute_evalue <- function(estimate, lo = NULL, hi = NULL,
type = c("RR", "OR", "HR", "SMD"),
rare = TRUE) {
type <- match.arg(type)
# Convert to RR scale
rr <- switch(type,
"RR" estimate
rare estimate estimate
rare estimate estimate
estimate
rr rr 1rr
evalue rr rr rr
evalue_ci
lo
rr_lo type
lo
rare lo lo
rare lo lo
lo
rr_lo rr_lo 1rr_lo
rr_lo
evalue_ci rr_lo rr_lo rr_lo
evalue_ci 1
interpretation case_when
evalue
evalue
evalue
evalue
evalue_point evalue
evalue_ci evalue_ci
interpretation interpretation
message sprintf
evalue
Tipping point analysis identifies the specific parameter values at which conclusions would change (e.g., confidence interval includes null, effect reverses sign).
| Type | Definition | Use Case |
|---|---|---|
| Null tipping point | Where CI includes 0 | Statistical significance |
| Clinical tipping point | Where effect < MCID | Clinical significance |
| Direction tipping point | Where effect changes sign | Effect direction |
#' Create Tipping Point Contour Plot
#'
#' @param estimate Point estimate
#' @param se Standard error
#' @param gamma_range Confounder-treatment association range
#' @param delta_range Confounder-outcome association range
#' @return ggplot2 contour plot
plot_tipping_point <- function(estimate, se,
gamma_range = seq(1, 5, 0.1),
delta_range = seq(1, 5, 0.1)) {
library(ggplot2)
grid <- expand.grid(gamma = gamma_range, delta = delta_range)
grid$bias_factor <- with(grid, ( delta delta
gridadjusted estimate gridbias_factor
gridsignificant gridadjusted se gridbias_factor
ggplotgrid aesx y delta z adjusted
geom_contour_filledbreaks estimate estimate
geom_contouraesz significant
breaks color linewidth
labs
x
y
title
subtitle
theme_minimal
| Type | Description | Effect on Estimates |
|---|---|---|
| Non-differential | Error unrelated to other variables | Usually biases toward null |
| Differential | Error depends on treatment/outcome | Can bias in either direction |
| Systematic | Consistent over/under-reporting | Shifts estimates |
| Random | Noise around true value | Attenuates relationships |
For mediation with misclassified mediator:
$$\hat{a}\hat{b} = ab \times \text{Attenuation Factor}$$
where:
$$\text{Attenuation} = \frac{\text{Sensitivity} + \text{Specificity} - 1}{1}$$
#' Sensitivity Analysis for Mediator Misclassification
#'
#' @param indirect_effect Observed indirect effect
#' @param se_indirect Standard error
#' @param sens_range Sensitivity range to explore
#' @param spec_range Specificity range to explore
#' @return Corrected estimates grid
sensitivity_misclassification <- function(indirect_effect, se_indirect,
sens_range = seq(0.7, 1, 0.05),
spec_range = seq(0.7, 1, 0.05)) {
grid <- expand.grid(sensitivity = sens_range, specificity = spec_range)
# Attenuation factor
grid$attenuation <- grid$sensitivity + grid$specificity
gridcorrected_effect indirect_effect gridattenuation
gridcorrected_se se_indirect gridattenuation
gridci_lower gridcorrected_effect gridcorrected_se
gridci_upper gridcorrected_effect gridcorrected_se
original_significant indirect_effect se_indirect
gridconclusion_change gridci_lower original_significant
original
effect indirect_effect
se se_indirect
significant original_significant
sensitivity_grid grid
robust_region gridgridconclusion_change
vulnerable_region gridgridconclusion_change
Test how results vary across defensible model specifications:
#' Specification Curve Analysis
#'
#' @param data Dataset
#' @param outcome Outcome variable name
#' @param treatment Treatment variable name
#' @param mediator Mediator variable name
#' @param covariate_sets List of covariate sets to try
#' @param model_types Vector of model types to try
#' @return Specification curve results
specification_curve <- function(data, outcome, treatment, mediator,
covariate_sets,
model_types = c("linear", "logistic")) {
results <- list()
spec_id <- 1
for (covs in covariate_sets) {
for (model_type in model_types)
m_formula as.formulapastemediator treatment
pastecovs collapse
y_formula as.formulapasteoutcome treatment mediator
pastecovs collapse
model_type
m_model lmm_formula data data
y_model lmy_formula data data
m_model glmm_formula data data family binomial
y_model glmy_formula data data family binomial
a coefm_modeltreatment
b coefy_modelmediator
indirect a b
resultsspec_id data.frame
spec_id spec_id
covariates pastecovs collapse
model_type model_type
a_path a
b_path b
indirect_effect indirect
n_covariates covs
spec_id spec_id
results_df do.callrbind results
specifications results_df
summary data.frame
median_effect medianresults_dfindirect_effect
mean_effect meanresults_dfindirect_effect
sd_effect sdresults_dfindirect_effect
min_effect results_dfindirect_effect
max_effect results_dfindirect_effect
prop_positive meanresults_dfindirect_effect
prop_significant
n_specifications nrowresults_df
Rosenbaum bounds quantify how sensitive causal conclusions are to hidden bias in observational studies using matched designs.
$\Gamma$ represents the maximum ratio of odds of treatment for two matched subjects:
$$\frac{1}{\Gamma} \leq \frac{P(A_i = 1 \mid X_i)}{P(A_j = 1 \mid X_j)} \times \frac{1 - P(A_j = 1 \mid X_j)}{1 - P(A_i = 1 \mid X_i)} \leq \Gamma$$
| Γ Value | Interpretation |
|---|---|
| 1.0 | No hidden bias (randomization) |
| 1.1 - 1.3 | Sensitive to small hidden bias |
| 1.3 - 2.0 | Moderately robust |
| 2.0 - 3.0 | Robust to substantial bias |
| > 3.0 | Very robust |
#' Rosenbaum Bounds for Matched Study
#'
#' @param outcome_diff Vector of within-pair outcome differences
#' @param gamma_range Range of sensitivity parameter
#' @return Bounds on p-values
rosenbaum_bounds <- function(outcome_diff, gamma_range = seq(1, 3, 0.1)) {
n <- length(outcome_diff)
# Signed rank statistic
ranks <- rank(abs(outcome_diff))
W_obs <- sum(ranks[outcome_diff > 0])
results <- data.frame(gamma = gamma_range)
results$p_upper <- NA
results$p_lower <- NA
for i gamma_range
gamma_rangei
p_treat
E_W ranks p_treat
V_W ranks p_treat p_treat
z_upper W_obs E_W V_W
resultsp_upperi pnormz_upper
p_treat_low 1
E_W_low ranks p_treat_low
V_W_low ranks p_treat_low p_treat_low
z_lower W_obs E_W_low V_W_low
resultsp_loweri pnormz_lower
resultssignificant_upper resultsp_upper
critical_gamma resultsresultssignificant_upper na.rm
bounds results
critical_gamma critical_gamma
interpretation sprintf
critical_gamma
For natural indirect effects, sensitivity to violation of sequential ignorability:
#' Mediation Sensitivity Analysis
#'
#' Following Imai, Keele, & Yamamoto (2010)
#'
#' @param mediation_result Result from mediation analysis
#' @param rho_range Correlation between M and Y errors
#' @return Sensitivity results
sensitivity_mediation <- function(a_coef, b_coef, indirect_effect,
se_indirect,
rho_range = seq(-0.5, 0.5, 0.05)) {
results <- data.frame(rho = rho_range)
# Bias from correlation
# Approximate bias formula from Imai et al.
results$adjusted_indirect <- indirect_effect * (1 - rho_range^2)
# Adjusted inference
results$ci_lower <- results$adjusted_indirect - 1.96 se_indirect
resultsci_upper resultsadjusted_indirect se_indirect
resultssignificant resultsci_lower resultsci_upper
original_sign indirect_effect
critical_rho rho_rangeresultsadjusted_indirect original_sign
sensitivity_grid results
critical_rho critical_rho
interpretation sprintf
critical_rho
robust_range resultsresultssignificant
## Sensitivity Analysis
### Unmeasured Confounding
The E-value for our main finding (RR = X.XX) is E = X.XX, indicating that
an unmeasured confounder would need to be associated with both treatment
and outcome by a risk ratio of at least X.XX each to fully explain away
the observed effect. This represents [interpretation] confounding.
### Tipping Point Analysis
Figure X shows the sensitivity of our conclusions to unmeasured confounding.
The observed effect would be nullified if [specific conditions].
### Measurement Error
Under the assumption of [non-differential/differential] measurement error,
our results remain significant for mediator sensitivity values above X%
and specificity above X%.
### Robustness to Model Specification
Across [N] alternative model specifications varying [covariates/functional
forms/etc.], the median indirect effect was X.XX (range: X.XX to X.XX).
[XX%] of specifications yielded statistically significant positive effects.
Version: 1.0.0 Created: 2025-12-08 Domain: Sensitivity analysis for causal inference Applications: Mediation analysis, observational studies, matched designs