| Title: | Bayesian EXNEX Models for Survival Analysis in Basket Trials |
|---|---|
| Description: | Implements the Bayesian Exchangeable Non-Exchangeable (EXNEX) framework for right-censored log-normal survival data in basket trials. Based on 'Rcpp' and 'RcppArmadillo', the package provides a fast Gibbs sampler supporting EXNEX, complete pooling, and no pooling models to facilitate methodological comparisons and simulation studies. |
| Authors: | Victor Ney [aut, cre] |
| Maintainer: | Victor Ney <[email protected]> |
| License: | MIT + file LICENSE |
| Version: | 1.3.0 |
| Built: | 2026-10-11 15:27:04 UTC |
| Source: | https://github.com/cran/exnexSurv |
Computes [compute_waic()] for each supplied fit and reports them in a single 'data.frame', sorted by ascending WAIC.
compare_waic(..., digit = 2)compare_waic(..., digit = 2)
... |
Two or more fitted 'exnex_surv' objects. |
digit |
Number of decimal places for the reported statistics. |
A 'data.frame' with one row per model and columns 'model', 'waic', 'se_elpd_waic', 'lpd', 'p_waic', 'elpd_waic'.
Computes the Watanabe-Akaike Information Criterion (WAIC) for a fitted
'exnex_surv' model. WAIC is a fully Bayesian information criterion that uses
the posterior draws of the log-likelihood and adds a penalty for effective
number of parameters .
compute_waic(fit, ...)compute_waic(fit, ...)
fit |
A fitted 'exnex_surv' object. |
... |
Unused. |
For each observation , with posterior draws indexed by
, we compute the pointwise log-likelihood
, where the log-normal AFT model gives
for an observed event ()
and for a censored observation ()
where is the linear predictor built from the draws.
WAIC is then
Rows with extreme leverage ('p_waic' above a large threshold) may flag issues; the function returns a 'pointwise' matrix so users can investigate.
A named list with elements 'waic', 'se_elpd_waic', 'lpd', 'p_waic', 'elpd_waic', and 'pointwise' (an 'n' by 3 matrix with columns 'lpd', 'p_waic', 'waic').
Fits a Bayesian Exchangeable Non-Exchangeable (EXNEX) hierarchical model for right-censored log-normal survival data in basket trials using a data-augmented Gibbs sampler.
exnex_surv(x, ...) ## Default S3 method: exnex_surv(x, ...) ## S3 method for class 'formula' exnex_surv( formula, data, priors = list(), iter = 2000, warmup = 1000, chains = 1, parallel_chains = 1, group_col = NULL, seed = NULL, ... ) ## S3 method for class 'data.frame' exnex_surv( x, y, priors = list(), iter = 2000, warmup = 1000, chains = 1, parallel_chains = 1, group_col = NULL, seed = NULL, ... )exnex_surv(x, ...) ## Default S3 method: exnex_surv(x, ...) ## S3 method for class 'formula' exnex_surv( formula, data, priors = list(), iter = 2000, warmup = 1000, chains = 1, parallel_chains = 1, group_col = NULL, seed = NULL, ... ) ## S3 method for class 'data.frame' exnex_surv( x, y, priors = list(), iter = 2000, warmup = 1000, chains = 1, parallel_chains = 1, group_col = NULL, seed = NULL, ... )
x |
An object containing the predictors (subgroup assignment). Can be a data frame or a formula. |
... |
Additional arguments passed to methods. |
formula |
A model formula with structure: 'Surv(time, event) ~ group + covariates'. The first RHS variable is the group/basket assignment. Additional variables are covariates. |
data |
A data frame containing the variables in the formula. |
priors |
Optional named list of prior hyperparameters. Supported fields:
|
iter |
Total number of MCMC iterations. Default is 2000. |
warmup |
Number of warmup iterations to discard. Default is 1000. Posterior samples will have (iter - warmup) rows. |
chains |
Number of independent MCMC chains. Default is 1. |
parallel_chains |
Number of chains to run in parallel at the R level. Must be between 1 and 'chains'. Default is 1 (sequential chain execution). |
group_col |
Name of the column in 'x' that represents the basket/group assignment. If NULL (default), assumes the first column in x is the group. |
seed |
Random seed for reproducibility (optional). |
y |
A Surv object or matrix containing outcome (time and event status). |
For patient , the model is
with a latent EXNEX hierarchy on the basket effects,
so that each basket either borrows strength from the exchangeable component
or follows its own non-exchangeable prior
. The first predictor variable in the model
formula is interpreted as the basket/group assignment; additional variables
are covariates in the linear predictor on the log-survival scale.
Censored event times are handled by data augmentation: a censored log-time is
imputed from its truncated-Normal conditional distribution (inverse-CDF in log
space) before the remaining parameters are updated with their conjugate full
conditionals. The sampler keeps only the posterior draws of ,
, and .
An object of class 'exnex_surv' containing posterior samples and metadata.
Components include draws (a data frame with columns
theta_1, ..., theta_K, beta_1, ..., beta_P, and
sigma2), data (the processed data: time, event,
group, X, n, n_groups, n_covariates,
cov_names, chain_seeds), priors (the supplied priors),
resolved_priors (defaults merged with overrides), iter,
warmup, chains, and blueprint. Use summary(),
print(), and plot() to inspect it.
# Small simulated dataset: three baskets, one covariate, ~25% censoring set.seed(1) n <- 90 group <- factor(rep(1:3, each = 30)) x1 <- rnorm(n) eta <- rep(c(1.1, 1.6, 2.0), each = 30) + 0.5 * x1 true_time <- exp(eta + rnorm(n, 0, 0.6)) cens_time <- runif(n, 2, 9) d <- data.frame( time = pmin(true_time, cens_time), event = as.integer(true_time <= cens_time), group = group, x1 = x1 ) # Fit with group effects and one covariate (small run for the example) fit <- exnex_surv( survival::Surv(time, event) ~ group + x1, data = d, priors = list(p_mix = 0.7), iter = 300, warmup = 150, chains = 1 ) print(fit, show_trace = FALSE) summary(fit)# Small simulated dataset: three baskets, one covariate, ~25% censoring set.seed(1) n <- 90 group <- factor(rep(1:3, each = 30)) x1 <- rnorm(n) eta <- rep(c(1.1, 1.6, 2.0), each = 30) + 0.5 * x1 true_time <- exp(eta + rnorm(n, 0, 0.6)) cens_time <- runif(n, 2, 9) d <- data.frame( time = pmin(true_time, cens_time), event = as.integer(true_time <= cens_time), group = group, x1 = x1 ) # Fit with group effects and one covariate (small run for the example) fit <- exnex_surv( survival::Surv(time, event) ~ group + x1, data = d, priors = list(p_mix = 0.7), iter = 300, warmup = 150, chains = 1 ) print(fit, show_trace = FALSE) summary(fit)
For the log-normal AFT model the median survival time for a linear
predictor is , since
when . Posterior draws of and
therefore induce a posterior distribution of whose quantiles
are reported.
median_survival(fit, newdata = NULL, level = 0.95, ...)median_survival(fit, newdata = NULL, level = 0.95, ...)
fit |
A fitted 'exnex_surv' object. |
newdata |
Optional data frame (one row gives one median). |
level |
Credible-interval level (default '0.95'). |
... |
Unused. |
A 'data.frame' with columns 'group', 'median', 'lower', 'upper'.
Generates one bayesplot traceplot per parameter.
## S3 method for class 'exnex_surv' plot(x, parameters = NULL, ask = interactive(), ...)## S3 method for class 'exnex_surv' plot(x, parameters = NULL, ask = interactive(), ...)
x |
A fitted 'exnex_surv' object. |
parameters |
Optional character vector of parameter names to plot. |
ask |
Should R pause between plots? Defaults to 'interactive()'. |
... |
Unused. |
Invisibly returns 'x'.
Draws the posterior median and credible band of the survival function for each group. Requires 'ggplot2'.
## S3 method for class 'survival_exnex' plot(x, ...)## S3 method for class 'survival_exnex' plot(x, ...)
x |
An object of class 'survival_exnex' returned by [survival_curves()]. |
... |
Unused. |
Invisibly returns 'x'.
Prints a compact summary and optionally traceplots of posterior draws.
## S3 method for class 'exnex_surv' print(x, show_trace = TRUE, parameters = NULL, max_parameters = Inf, ...)## S3 method for class 'exnex_surv' print(x, show_trace = TRUE, parameters = NULL, max_parameters = Inf, ...)
x |
A fitted 'exnex_surv' object. |
show_trace |
Should traceplots be shown? Default is 'TRUE'. |
parameters |
Optional character vector of parameter names for traceplots. |
max_parameters |
Maximum number of parameters to plot. |
... |
Unused. |
Invisibly returns 'x'.
Estimates the posterior probability that a certain scalar summary of the survival distribution for group 'a' is greater than the same summary for group 'b'. Supported summaries are the median survival time, the survival probability at a fixed time 'S(t_0)', and the restricted mean survival time (RMST). The function works draw-by-draw on the posterior, so the probability is computed on the joint posterior of the two groups.
probability_superiority( fit, a, b, function_of = "median", newdata = NULL, times = NULL, tmax = NULL, ... )probability_superiority( fit, a, b, function_of = "median", newdata = NULL, times = NULL, tmax = NULL, ... )
fit |
A fitted 'exnex_surv' object. |
a |
An integer index (or group label) of the first group. |
b |
An integer index (or group label) of the second group. |
function_of |
Character; one of '"median"', '"survival"' (alias '"S_t"'), or '"rmst"'. Selects which summary is compared. |
newdata |
Optional data frame with one row per group, used to fix covariates. If 'NULL', covariates are set to zero. |
times |
A scalar time at which to evaluate the survival function when 'function_of = "survival"'. |
tmax |
A positive horizon when 'function_of = "rmst"'. |
... |
Unused. |
A named list with elements 'prob' (posterior probability that the summary of group 'a' exceeds that of group 'b'), 'summary' (which summary was used), and 'groups' (the two groups compared).
Computes the restricted mean survival time up to a horizon 'tmax':
The integral is evaluated numerically (trapezoidal rule over a fine grid) for every posterior draw, then summarised with posterior quantiles.
rmst(fit, tmax = NULL, newdata = NULL, level = 0.95, grid_points = 400, ...)rmst(fit, tmax = NULL, newdata = NULL, level = 0.95, grid_points = 400, ...)
fit |
A fitted 'exnex_surv' object. |
tmax |
A positive scalar horizon up to which the RMST is computed. Defaults to 'max(fit$data$time)'. |
newdata |
Optional data frame (one row gives one RMST). |
level |
Credible-interval level (default '0.95'). |
grid_points |
Resolution of the numerical quadrature (default '400'). |
... |
Unused. |
A 'data.frame' with columns 'group', 'rmst', 'lower', 'upper'.
Generates a synthetic dataset from the log-normal AFT model used by 'exnexSurv':
Healthy baskets draw their location from a common baseline plus random noise; "outlier" baskets (specified via 'outlier_baskets') have their location shifted by 'resist_delta'. The function is useful for simulation studies and teaching examples.
simulate_data( n = 30, K = 9, beta = c(0.5, -0.2), sigma = 1.2, outlier_baskets = NULL, resist_delta = -0.8, censoring_rate = NULL, censor_upper = NULL, theta = 0, seed = NULL )simulate_data( n = 30, K = 9, beta = c(0.5, -0.2), sigma = 1.2, outlier_baskets = NULL, resist_delta = -0.8, censoring_rate = NULL, censor_upper = NULL, theta = 0, seed = NULL )
n |
Number of patients per basket. A scalar is replicated across all 'K' baskets; a numeric vector of length 'K' assigns a size to each basket individually. |
K |
Number of baskets (default '9'). |
beta |
Numeric vector of regression coefficients for the covariates. Length determines the number of covariates. |
sigma |
Residual standard deviation (default '1.2'). |
outlier_baskets |
Optional integer vector of basket indices (1 to K) whose true location is shifted away from the healthy population. These are the baskets the EXNEX model is designed to detect. |
resist_delta |
Additive shift applied to the 'theta' of outlier baskets (default '-0.8'). |
censoring_rate |
Approximate proportion of censoring after 'censor_upper'; if 'NULL', no censoring is applied. |
censor_upper |
Upper bound of the censoring-time uniform distribution. |
theta |
Baseline location for the healthy (non-outlier) baskets; a scalar used as the centre around which the healthy basket locations vary. |
seed |
Optional seed for reproducibility. |
A 'data.frame' with columns 'time', 'event', 'group' (a factor), and one covariate column ('x1', ...) per entry in 'beta'. True parameter values are stored as attributes 'true_theta', 'true_beta', and 'true_sigma'.
Summarize posterior draws from an exnex_surv fit
## S3 method for class 'exnex_surv' summary(object, probs = c(0.05, 0.5, 0.95), ...)## S3 method for class 'exnex_surv' summary(object, probs = c(0.05, 0.5, 0.95), ...)
object |
A fitted 'exnex_surv' object. |
probs |
Quantiles to report. |
... |
Unused. |
A data frame with posterior summaries.
Computes posterior survival curves from a fitted
'exnex_surv' model for a log-normal AFT specification:
For a fixed time and linear predictor , the survival
probability of the log-normal distribution is
where is the residual variance. Posterior draws of
are propagated through this expression to
obtain a full posterior distribution of at each time point.
survival_curves(fit, newdata = NULL, times = NULL, level = 0.95, ...)survival_curves(fit, newdata = NULL, times = NULL, level = 0.95, ...)
fit |
A fitted 'exnex_surv' object. |
newdata |
Optional data frame with columns matching the covariates of the model. If it contains a 'group' column, that is used for the group index; otherwise the first group is used for all rows. |
times |
Optional numeric vector of times at which to evaluate the curves. If 'NULL', a sensible grid is built from the observed follow-up times. |
level |
Credible-interval level (default '0.95'). |
... |
Unused. |
If 'newdata' is supplied, each row is evaluated at its own group and covariate values; otherwise the covariates are fixed at zero and the first group is used (with a warning if more than one group exists).
An object of class 'survival_exnex' (also a 'data.frame') with long format columns: 'time', 'median', 'lower', 'upper', and 'group'.