--- title: "Getting started with spsurv" output: rmarkdown::html_vignette vignette: > %\VignetteIndexEntry{Getting started with spsurv} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- ```{r, include = FALSE} knitr::opts_chunk$set( collapse = TRUE, comment = "#>", fig.width = 7, fig.height = 4.5, dpi = 96, message = FALSE, warning = FALSE ) ``` **spsurv** fits semi-parametric survival regression for right-censored data using Bernstein-polynomial (BP) baselines. Three model families share one interface: - **PH** — proportional hazards (`bpph`, `model = "ph"`) - **PO** — proportional odds (`bppo`, `model = "po"`) - **AFT** — accelerated failure time (`bpaft`, `model = "aft"`) ## Before you model ```{r setup} library(spsurv) library(KMsurv) library(survival) library(ggplot2) library(generics) data(larynx) larynx$stage <- factor(larynx$stage) ``` ```{r eda-censoring} censor_tbl <- do.call(rbind, lapply(split(larynx, larynx$stage), function(d) { data.frame( stage = as.character(d$stage[1]), n = nrow(d), events = sum(d$delta), censored = sum(1 - d$delta), stringsAsFactors = FALSE ) })) censor_tbl$pct_censored <- round(100 * censor_tbl$censored / censor_tbl$n, 1) censor_tbl ``` ```{r eda-km, fig.cap = "Kaplan-Meier survival by larynx cancer stage."} km_stage <- survfit(Surv(time, delta) ~ stage, data = larynx) km_long <- data.frame( time = km_stage$time, surv = km_stage$surv, stage = rep(levels(larynx$stage), km_stage$strata) ) ggplot(km_long, aes(x = time, y = surv, color = stage)) + geom_step(linewidth = 0.6) + labs(x = "Time (years)", y = "Survival probability", color = "Stage") + theme_bw() + theme(legend.position = "bottom") ``` ### Why this is insightful Stage separation in the KM plot motivates including `stage` as a covariate. Censoring percentages set expectations for precision — heavy censoring or tiny stage groups mean wider confidence intervals. ### What to decide - Clear stage ordering → PH with `stage` is a plausible starting point. - Heavy censoring or small groups → interpret CIs cautiously; consider simpler models or Bayesian analysis. - If KM curves cross → see the *Choosing PH, PO, and AFT models* vignette before fitting Cox PH blindly. ## Fit and summarize ```{r fit} fit <- bpph( Surv(time, delta) ~ age + stage, degree = 5, data = larynx, approach = "mle", init = 0 ) summary(fit) ``` The generic `spbp()` function is equivalent when you pass `model` explicitly: ```{r spbp} fit2 <- spbp( Surv(time, delta) ~ age + stage, degree = 5, data = larynx, model = "ph", approach = "mle", init = 0 ) ``` ## Specifying the Bernstein degree ```{r bernstein-spec} fit3 <- bpph( Surv(time, delta) ~ age + stage, data = larynx, approach = "mle", dist = bernstein(5), init = 0 ) length(fit3$bp.param) ``` ## The `spbp` object ```{r object-parts} names(fit)[names(fit) %in% c("coefficients", "bp.param", "n", "nevent")] fit$call$model fit$call$approach ``` | Component | Meaning | |-----------|---------| | `coefficients` | Regression estimates (on original covariate scale) | | `bp.param` | Bernstein baseline coefficients (`gamma`) | | `degree` | Bernstein polynomial degree used in the fit | | `bp.param` length | Same as `degree` | | `call$model` | `"ph"`, `"po"`, or `"aft"` | | `call$approach` | `"mle"` or `"bayes"` | ## Visual check — forest plot ```{r forest, fig.cap = "Exponentiated coefficients (hazard ratios) with 95% CIs."} td <- tidy(fit, conf.int = TRUE, exponentiate = TRUE) td$term <- factor(td$term, levels = rev(td$term)) ggplot(td, aes(x = estimate, y = term, xmin = conf.low, xmax = conf.high)) + geom_vline(xintercept = 1, linetype = "dashed", color = "grey50") + geom_pointrange(linewidth = 0.4) + labs(x = "Hazard ratio", y = NULL) + theme_bw() ``` ### Why this is insightful Forest plots translate coefficients into decision-relevant effect sizes. Stage effects relative to the reference level show how much each stage shifts hazard after adjusting for age. ### What to decide - CI excludes 1 → evidence of effect at conventional levels. - Large age effect → clinically meaningful covariate; keep in model. - For smooth survival curves at fixed covariate profiles → see the *Survival prediction and ggplot* vignette. ## Printing ```{r print} print(fit, what = "summary") ``` ## Next steps - *Choosing PH, PO, and AFT models* — compare regression families - *Survival prediction and ggplot* — smooth survival curves - *Bayesian analysis with Stan* — priors and posterior summaries