---
title: "Transportability and Policy Learning"
output: rmarkdown::html_vignette
vignette: >
  %\VignetteIndexEntry{Transportability and Policy Learning}
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteEncoding{UTF-8}
---

```{r, include = FALSE}
knitr::opts_chunk$set(
  collapse = TRUE,
  comment = "#>"
)
```

This vignette demonstrates two advanced applications of the **causaldef** framework:
1.  **Transportability**: Generalizing experimental results to a new target population.
2.  **Policy Learning Bounds**: Quantifying the limits of decision-making under confounding.

We utilize classical datasets (**Lalonde NSW** and **Right Heart Catheterization**) to illustrate these concepts.

```{r setup}
library(causaldef)
library(stats)

# Helper for plot resizing
if (!exists("deparse1", envir = baseenv())) {
  deparse1 <- function(expr, collapse = " ", width.cutoff = 500L, ...) {
    paste(deparse(expr, width.cutoff, ...), collapse = collapse)
  }
}
```

## 1. Transportability: Lalonde's Job Training

A common challenge in causal inference is **external validity**: Can we apply the results of a Randomized Controlled Trial (RCT) to a diferent target population?

We use the Lalonde dataset to simulate a transportability problem.
*   **Source Population ($S=1$)**: The NSW experimental participants (typically disjoint from the general population).
*   **Target Population ($S=0$)**: The CPS comparison group (representative of the broader population).

```{r lalonde-data}
data("nsw_benchmark")

# Define Source: Experimental Sample
source_data <- subset(nsw_benchmark, sample_id %in% c("nsw_treated", "nsw_control"))

# Define Target: CPS Control Group (Broader population)
target_data <- subset(nsw_benchmark, sample_id == "cps_control")

# Covariates available for transport
transport_vars <- c("age", "education", "black", "hispanic", "married", "nodegree", "re74", "re75")

# Comparison of demographics
print(summary(source_data[, c("age", "education", "re74")]))
print(summary(target_data[, c("age", "education", "re74")]))
```
The target population (CPS) is significantly wealthier (`re74` mean is much higher) and slightly older. We want to know: *What would be the effect of job training if applied to the CPS population?*

### Transport Deficiency
We calculate the **Transport Deficiency** $\delta(E_S, E_T)$. This measures how much information is lost due to the distributional shift between Source and Target.

```{r transport-calc}
# Create causal specification for the SOURCE
source_spec <- causal_spec(
  data = source_data,
  treatment = "treat",
  outcome = "re78",
  covariates = transport_vars
)

# Compute Transport Deficiency
trans_def <- transport_deficiency(
  source_spec,
  target_data = target_data,
  transport_vars = transport_vars,
  method = "iptw",
  n_boot = 50 # Low for vignette speed
)

print(trans_def)
plot(trans_def, type = "shift")
```

**Interpretation**:
*   **Covariate Shift**: The plot shows which variables differ most (likely `re74` and `re75`).
*   **Transported ATE**: The estimated effect in the target population.
*   **Deficiency**: A low delta implies we can reliably transport the result. A high delta warns that the populations are too distinct (lack of overlap or extreme weights).

---

## 2. Policy Learning Bounds: RHC

In **Policy Learning**, we seek an optimal treatment rule $\pi(X)$ to maximize utility. However, with observational data, our estimate of a policy's value is biased by confounding.

We use the **Right Heart Catheterization (RHC)** dataset to evaluate a risk-based policy.
*   **Decision**: Treat with RHC?
*   **Outcome**: 30-day Mortality (lower is better).
*   **Policy**: "Treat only high-risk patients" (e.g., APACHE score > 50).

```{r rhc-setup}
data("rhc")

# Preprocessing
if (is.factor(rhc$swang1)) rhc$treat <- as.numeric(rhc$swang1) - 1 else rhc$treat <- rhc$swang1
if (is.factor(rhc$dth30)) rhc$outcome <- as.numeric(rhc$dth30) - 1 else rhc$outcome <- rhc$dth30

# Variables for adjustment
covariates <- c("age", "sex", "race", "aps1", "cat1") 

spec_rhc <- causal_spec(
  data = rhc,
  treatment = "treat",
  outcome = "outcome",
  covariates = covariates
)
```

### Policy Evaluation
We compare two policies:
1.  **Treat All**: Everyone gets RHC.
2.  **Risk-Based**: Treat only if APACHE III score (`aps1`) > 50.

We estimate the *observational* value of these policies using IPW.

```{r policy-eval}
# Estimate propensity scores for adjustment
ps_model <- glm(treat ~ age + sex + race + aps1 + cat1, data = rhc, family = binomial)
rhc$ps <- predict(ps_model, type = "response")

# Define policies
policy_all <- rep(1, nrow(rhc))
policy_risk <- ifelse(rhc$aps1 > 50, 1, 0)

# Estimate Value (Inverse Propensity Weighted)
# Value = Mean of Y under policy. We want to MINIMIZE mortality.
# Equivalent to Maximizing Survival (1 - Y).
# Let's compute expected mortality.

get_policy_value <- function(policy, treat, outcome, ps) {
  # IPW estimator for policy value
  # Weight = I(A = \pi(X)) / P(A|X)
  w <- (treat == policy) / ifelse(policy == 1, ps, 1 - ps)
  mean(w * outcome) # Expected Mortality
}

val_all <- get_policy_value(policy_all, rhc$treat, rhc$outcome, rhc$ps)
val_risk <- get_policy_value(policy_risk, rhc$treat, rhc$outcome, rhc$ps)

cat("Estimated Mortality (Treat All):", round(val_all, 3), "\n")
cat("Estimated Mortality (Risk-Based):", round(val_risk, 3), "\n")
```

### The Safety Floor
Even if the Risk-Based policy looks better, can we trust it?
The **Safety Floor** tells us the worst-case error in our value estimate due to unmeasured confounding.

```{r safety-floor}
# 1. Estimate Deficiency of the dataset
defom <- estimate_deficiency(spec_rhc, methods = "iptw", n_boot = 0)
delta <- defom$estimates["iptw"]

# 2. Compute Safety Floor
# Utility range is [0, 1] (Mortality 0 or 1)
bounds <- policy_regret_bound(defom, utility_range = c(0, 1), method = "iptw")

print(bounds)
```

**Conclusion**:
*   The **Safety Floor** represents the *irreducible uncertainty*.
*   If the difference between `Treat All` and `Risk-Based` is smaller than the safety floor, we cannot be confident the new policy is actually superior to the baseline, regardless of sample size.
*   This illustrates the fundamental limit of offline policy learning from observational data.
