PSsurvival: Propensity Score Methods for Survival Analysis

knitr::opts_chunk$set(
  collapse = TRUE,
  comment = "#>",
  fig.width = 6,
  fig.height = 4
)

Introduction

PSsurvival implements propensity score methods for causal inference with time-to-event outcomes. The package provides two main functions:

Both functions support binary and multiple treatment groups, multiple weighting schemes, and propensity score trimming.

library(PSsurvival)

Data

The package includes two simulated datasets:

data(simdata_bin)   # Binary treatment (A vs B)
data(simdata_multi) # Four treatment groups (A, B, C, D)

# Binary treatment data
head(simdata_bin)
table(simdata_bin$Z)

# Multiple treatment data
table(simdata_multi$Z)

Both datasets contain:

Counterfactual Survival Analysis with surveff()

Key Arguments

Data and model specification:

Weighting and trimming:

Variance estimation:

Basic Usage: Binary Treatment

result_bin <- surveff(
  data = simdata_bin,
  ps_formula = Z ~ X1 + X2 + X3 + B1 + B2,
  censoring_formula = survival::Surv(time, event) ~ X1 + B1,
  estimand = "overlap",
  censoring_method = "weibull"
)

print(result_bin, max.len = 3)

The ps_formula specifies the propensity score model (treatment ~ covariates). The censoring_formula models the censoring distribution within each treatment group.

Multiple Treatment Groups

For multiple groups, survival differences require a contrast_matrix specifying which comparisons to make. Each row represents one contrast with exactly two non-zero elements: 1 and -1. Column names must match treatment levels exactly.

# Define pairwise comparisons
contrast_mat <- matrix(
  c(1, -1, 0, 0,   # A vs B
    1, 0, -1, 0,   # A vs C
    1, 0, 0, -1),  # A vs D
  nrow = 3, byrow = TRUE
)
colnames(contrast_mat) <- c("A", "B", "C", "D")  # Must match treatment levels
rownames(contrast_mat) <- c("A vs B", "A vs C", "A vs D") # row names are optional

result_multi <- surveff(
  data = simdata_multi,
  ps_formula = Z ~ X1 + X2 + X3 + B1 + B2,
  censoring_formula = survival::Surv(time, event) ~ X1 + B1,
  estimand = "ATE",
  contrast_matrix = contrast_mat,
  censoring_method = "cox",
  variance_method = "bootstrap",
  B = 50,
  seed = 123
)

print(result_multi, max.len = 3)

Without contrast_matrix, only group-specific survival functions are estimated (no differences in survivals).

Estimand Options

Three estimands are supported and estimated by corresponding weighting methods:

# ATE (default)
surveff(..., estimand = "ATE")

# ATT targeting group B
surveff(..., estimand = "ATT", att_group = "B")

# Overlap weights
surveff(..., estimand = "overlap")

Propensity Score Trimming

Trimming excludes observations with extreme propensity scores. Not available with overlap weights (which already downweight extremes).

# Symmetric trimming
surveff(..., estimand = "ATE", trim = "symmetric", delta = 0.1)

# Asymmetric trimming
surveff(..., estimand = "ATE", trim = "asymmetric", alpha = 0.05)

Censoring Methods

Two methods are available for estimating censoring distributions:

# Weibull censoring model
surveff(..., censoring_method = "weibull")

# Cox censoring model (requires bootstrap)
surveff(..., censoring_method = "cox", variance_method = "bootstrap", B = 200)

No censoring adjustment: To skip censoring adjustment entirely (e.g., when there is no censoring), use censoring_formula = Surv(time, event) ~ 0. In this case, all censoring scores are set to 1.

Variance Estimation

Two variance estimation methods are available:

# Analytical variance (binary + weibull only)
surveff(..., censoring_method = "weibull", variance_method = "analytical")

# Bootstrap variance
surveff(..., variance_method = "bootstrap", B = 200)

Bootstrap sampling level (boot_level): Controls how bootstrap samples are drawn.

# Stratified bootstrap
surveff(..., variance_method = "bootstrap", boot_level = "strata", B = 200)

Summary Output

The summary() method provides two output styles:

Printed output (style = "prints", default): Displays formatted tables with confidence intervals. Customize with:

Programmatic output (style = "returns"): Returns a list of matrices for further processing:

summary(result_bin, conf_level = 0.95, max.len = 5)

For programmatic access:

summ <- summary(result_bin, style = "returns")
names(summ)
head(summ$survival_summary$A)
head(summ$difference_summary$`B vs A`)

Plotting Results

The plot() method produces survival curves (type = "surv") or treatment effect curves (type = "survdiff").

# Survival curves for all groups
plot(result_multi, type = "surv", curve_width = 0.5)
# Treatment effect curves
plot(result_multi, type = "survdiff", curve_width = 0.5)

Selecting specific strata: Use strata_to_plot to display a subset of groups or contrasts.

# Only groups A and C
plot(result_multi, type = "surv", curve_width = 0.5,
     strata_to_plot = c("A", "C"))
# Only specific contrasts (names must match contrast_matrix rownames exactly)
plot(result_multi, type = "survdiff", curve_width = 0.5,
     strata_to_plot = c("A vs B", "A vs D"))

Customization options:

plot(result_multi,
     type = "surv",
     curve_width = 0.5,
     strata_to_plot = c("A", "B"),
     strata_colors = c("steelblue", "coral"),
     max_time = 15,
     include_CI = TRUE,
     legend_position = "bottom",
     plot_title = "Survival by Treatment Group")

Marginal Hazard Ratios with marCoxph()

marCoxph() fits a weighted Cox model to estimate marginal hazard ratios.

Key Arguments

Data and model specification:

Weighting and trimming:

Variance estimation:

Basic Usage: Binary Treatment

hr_result <- marCoxph(
  data = simdata_bin,
  ps_formula = Z ~ X1 + X2 + X3 + B1 + B2,
  time_var = "time",
  event_var = "event",
  reference_level = "A",
  estimand = "overlap"
)

print(hr_result)

The reference_level argument is mandatory and specifies the baseline group for hazard ratio comparisons.

Multiple Treatment Groups

hr_multi <- marCoxph(
  data = simdata_multi,
  ps_formula = Z ~ X1 + X2 + X3 + B1 + B2,
  time_var = "time",
  event_var = "event",
  reference_level = "A",
  estimand = "ATE",
  variance_method = "bootstrap",
  B = 50,
  seed = 456
)

print(hr_multi)

Estimand Options

Same as surveff(): ATE, ATT, and overlap weights are supported. Trimming options (symmetric/asymmetric) are also available.

# ATE (default)
marCoxph(..., estimand = "ATE")

# ATT targeting specific group
marCoxph(..., estimand = "ATT", att_group = "treated")

# Overlap weights
marCoxph(..., estimand = "overlap")

Trimming Options

Propensity score trimming works identically to surveff():

# Symmetric trimming
marCoxph(..., estimand = "ATE", trim = "symmetric", delta = 0.1)

# Asymmetric trimming
marCoxph(..., estimand = "ATE", trim = "asymmetric", alpha = 0.05)

Variance Options

Two variance estimation methods:

# Bootstrap variance (default)
marCoxph(..., variance_method = "bootstrap", B = 200)

# Robust sandwich variance (no bootstrap)
marCoxph(..., variance_method = "robust")

The boot_level argument ("full" or "strata") also applies here when using bootstrap variance, with the same interpretation as in surveff().

Summary Output

The summary() method provides detailed results with confidence intervals on both log and original scales:

summary(hr_multi, conf_level = 0.95)

Output styles:

summ_hr <- summary(hr_multi, style = "returns")
names(summ_hr)
summ_hr$HR  # Exponentiated hazard ratios

Summary

| Feature | surveff() | marCoxph() | |---------|-------------|--------------| | Output | Survival curves, survival differences | Hazard ratios | | Estimands | ATE, ATT, overlap | ATE, ATT, overlap | | Censoring adjustment | Weibull or Cox | None (standard Cox) | | Variance | Analytical or bootstrap | Robust or bootstrap | | Trimming | Symmetric, asymmetric | Symmetric, asymmetric | | Multiple groups | Yes (with contrast_matrix) | Yes |

References

Cheng, C., Li, F., Thomas, L. E., & Li, F. (2022). Addressing extreme propensity scores in estimating counterfactual survival functions via the overlap weights. American Journal of Epidemiology, 191(6), 1140-1151.

Li, F., & Li, F. (2019). Propensity score weighting for causal inference with multiple treatments. The Annals of Applied Statistics, 13(4), 2389-2415.



Try the PSsurvival package in your browser

Any scripts or data that you put into this service are public.

PSsurvival documentation built on Dec. 9, 2025, 9:07 a.m.