The hardware and bandwidth for this mirror is donated by METANET, the Webhosting and Full Service-Cloud Provider.
If you wish to report a bug, or if you are interested in having us mirror your free-software or open-source project, please feel free to contact us at mirror[@]metanet.ch.
refundBayes::fcox_bayesThis vignette provides a detailed guide to the
fcox_bayes() function in the refundBayes
package, which fits Bayesian Functional Cox Regression (FCR) models for
time-to-event outcomes using Stan. The function extends the
scalar-on-function regression framework to survival analysis with right
censoring, and is designed with a syntax similar to
mgcv::gam.
The methodology follows the tutorial by Jiang, Crainiceanu, and Cui (2025), Tutorial on Bayesian Functional Regression Using Stan, published in Statistics in Medicine.
refundBayes PackageThe refundBayes package can be installed from
GitHub:
The Functional Cox Regression (FCR) model extends the classical Cox proportional hazards model to settings where one or more predictors are functional (i.e., curves or trajectories observed over a continuum).
For subject \(i = 1, \ldots, n\), let \(T_i\) be the event time and \(C_i\) the censoring time. The observed data consist of \([Y_i, \delta_i, \mathbf{Z}_i, \{W_i(t_m), t_m \in \mathcal{T}\}]\), where:
The domain \(\mathcal{T}\) is
not restricted to \([0,1]\); it is determined by the actual
time points in the data (e.g., \(\mathcal{T} =
[1, 1440]\) for minute-level 24-hour activity data). See the
section on tmat, lmat, and wmat
below for details.
The model assumes a proportional hazards structure:
\[h_i(t) = h_0(t) \exp(\eta_i)\]
where \(h_0(t)\) is the baseline hazard function, and \(\eta_i\) is the linear predictor defined as:
\[\eta_i = \eta_0 + \int_{\mathcal{T}} W_i(s)\beta(s)\,ds + \mathbf{Z}_i^t \boldsymbol{\gamma}\]
Here \(\eta_0\) is the intercept,
\(\beta(\cdot)\) is the functional
coefficient, and \(\boldsymbol{\gamma}\) is the vector of
scalar regression coefficients. The integral is approximated by a
Riemann sum using the time point matrix tmat and the
integration weight matrix lmat (see below).
The log-likelihood for this model has the form:
\[\ell(\mathbf{Y}, \boldsymbol{\delta}; h_0, \boldsymbol{\eta}) = \sum_{i=1}^n \left[ (1 - \delta_i)\left\{\log h_0(y_i) + \eta_i - H_0(y_i)\exp(\eta_i)\right\} + \delta_i\left\{-H_0(y_i)\exp(\eta_i)\right\} \right]\]
where \(H_0(t) = \int_0^t h_0(u)\,du\) is the cumulative baseline hazard function.
Unlike the classical Cox model, which leaves the baseline hazard
unspecified and uses partial likelihood, the Bayesian approach requires
a full likelihood specification. The fcox_bayes() function
models the baseline hazard function \(h_0(t)\) using M-splines:
\[h_0(t) = \sum_{l=1}^L c_l M_l(t; \mathbf{k}, \tau)\]
where \(M_l(t; \mathbf{k}, \tau)\) denotes the \(l\)-th M-spline basis function with knots \(\mathbf{k}\) and degree \(\tau\), and \(\mathbf{c} = (c_1, \ldots, c_L)^t\) are the spline coefficients. The constraints \(c_l \geq 0\) and \(\sum_{l=1}^L c_l > 0\) ensure that the baseline hazard is non-negative and non-trivial. M-splines are a family of non-negative, piecewise polynomial basis functions that integrate to one over their support.
The cumulative baseline hazard function is modeled using I-splines, which are the integrated forms of M-splines:
\[H_0(t) = \sum_{l=1}^L c_l I_l(t; \mathbf{k}, \tau)\]
where \(I_l(t; \mathbf{k}, \tau) = \int_0^t M_l(u; \mathbf{k}, \tau)\,du\). Because M-splines are non-negative, the resulting I-spline cumulative hazard is non-decreasing by construction.
The I-spline coefficients \(\mathbf{c}\) and the intercept \(\eta_0\) are not simultaneously
identifiable: for any \(a > 0\), the
parameter pairs \((\mathbf{c},
\eta_0)\) and \((a\mathbf{c}, \eta_0 -
\log a)\) yield the same hazard function. To resolve this, the
model imposes the constraint \(\sum_{l=1}^L
c_l = 1\) by assigning a non-informative Dirichlet prior \(D(\mathbf{c}; \boldsymbol{\alpha})\) with
\(\boldsymbol{\alpha} = (1, \ldots,
1)\) to the coefficients. Consequently, the intercept defaults to
FALSE in fcox_bayes().
As in the SoFR model, the functional coefficient \(\beta(s)\) is represented using \(K\) spline basis functions \(\psi_1(s), \ldots, \psi_K(s)\):
\[\beta(s) = \sum_{k=1}^K b_k \psi_k(s)\]
The spline coefficients \(\mathbf{b}\) are reparametrised using the spectral decomposition of the penalty matrix \(\mathbf{S}\) (the Wahba-O’Sullivan smoothing penalty) to obtain transformed coefficients \(\tilde{\mathbf{b}} = (\tilde{\mathbf{b}}_r^t, \tilde{\mathbf{b}}_f^t)^t\), where:
This reparametrisation ensures numerical stability and efficient sampling in Stan.
tmat, lmat, and
wmatThe integral \(\int_{\mathcal{T}} W_i(s)\beta(s)\,ds\) is approximated by the Riemann sum \(\sum_{m=1}^M L_m W_i(t_m)\psi_k(t_m)\), constructed from three user-supplied matrices:
tmat (an \(n \times M\) matrix): contains the time
points \(t_m\) at which the functional
predictor is observed. The \((i,
m)\)-th entry equals \(t_m\).
The range of values in tmat determines the domain of
integration \(\mathcal{T}\). For
example, if the functional predictor is observed at minutes \(1, 2, \ldots, 1440\) within a day, then
tmat has entries ranging from \(1\) to \(1440\) and \(\mathcal{T} = [1, 1440]\). There is no
requirement that the domain be rescaled to \([0, 1]\).
lmat (an \(n \times M\) matrix): contains the
integration weights \(L_m = t_{m+1} -
t_m\) for the Riemann sum approximation. For equally spaced time
points with spacing \(\Delta t\), every
entry of lmat equals \(\Delta
t\). These weights, together with tmat, fully
specify how the numerical integration is performed and over what
domain.
wmat (an \(n \times M\) matrix): contains the
functional predictor values. The \(i\)-th row contains the \(M\) observed values \(W_i(t_1), \ldots, W_i(t_M)\) for subject
\(i\).
In the formula
s(tmat, by = lmat * wmat, bs = "cc", k = 10), the
mgcv infrastructure uses tmat to construct the
spline basis \(\psi_k(t_m)\) at the
observed time points, and the by = lmat * wmat argument
provides the element-wise product \(L_m \cdot
W_i(t_m)\) that enters the Riemann sum. The basis functions are
evaluated on the scale of tmat, and the integration weights
in lmat ensure that the discrete sum correctly approximates
the integral over the actual domain \(\mathcal{T}\) — regardless of whether it is
\([0, 1]\), \([1, 1440]\), or any other interval.
Note that for all subjects, the time points are assumed to be
identical so that \(t_{im} = t_m\) for
all \(i = 1, \ldots, n\). Thus every
row of tmat is the same, and every row of lmat
is the same. The matrices are replicated across rows to match the
mgcv syntax, which expects all terms in the formula to have
the same dimensions.
The complete Bayesian Functional Cox Regression model is:
\[\begin{cases} \mathbf{Y} \sim \ell(\mathbf{Y}, \boldsymbol{\delta}; h_0, \boldsymbol{\eta}) \\ \boldsymbol{\eta} = \eta_0 \mathbf{J}_n + \tilde{\mathbf{X}}_r^t \tilde{\mathbf{b}}_r + \tilde{\mathbf{X}}_f^t \tilde{\mathbf{b}}_f + \mathbf{Z}^t \boldsymbol{\gamma} \\ \tilde{\mathbf{b}}_r \sim N(\mathbf{0}, \sigma_b^2 \mathbf{I}) \\ \eta_0 \sim p(\eta_0);\; \tilde{\mathbf{b}}_f \sim p(\tilde{\mathbf{b}}_f);\; \boldsymbol{\gamma} \sim p(\boldsymbol{\gamma});\; \sigma_b^2 \sim p(\sigma_b^2) \\ h_0(t) = \sum_{l=1}^L c_l M_l(t; \mathbf{k}, \tau) \\ \mathbf{c} \sim D(\mathbf{c}; \boldsymbol{\alpha}) \end{cases}\]
where most components are shared with the SoFR model, except for the Cox likelihood (first line) and the baseline hazard specification via M-splines with a Dirichlet prior on \(\mathbf{c}\) (last two lines).
When functional predictors are observed with measurement error, the
fcox_bayes() function supports a joint modeling approach
that simultaneously estimates FPCA scores and fits the Cox regression
model. In this case, the model regresses on the latent trajectory \(D_i(t)\) rather than the observed (noisy)
function \(W_i(t) = D_i(t) +
\epsilon_i(t)\), properly accounting for the uncertainty in the
score estimates.
fcox_bayes() Function| Argument | Description |
|---|---|
formula |
Functional regression formula, using the same syntax as
mgcv::gam. The left-hand side should be the observed
survival time \(Y_i = \min(T_i, C_i)\).
Functional predictors are specified using the s() term with
by = lmat * wmat to encode the Riemann sum
integration. |
data |
A data frame containing all scalar and functional variables used in the model, as well as the survival time as the response variable. |
cens |
A binary vector indicating censoring status for each
subject, following the convention: \(\delta_i
= 0\) if the event is observed and \(\delta_i = 1\) if censored. Must have the
same length as the number of observations in data. |
joint_FPCA |
A logical (TRUE/FALSE) vector
of the same length as the number of functional predictors, indicating
whether to jointly model FPCA for each functional predictor. Default is
NULL, which sets all entries to FALSE (no
joint FPCA). |
intercept |
Logical. Whether to include an intercept term in the
linear predictor. Default is FALSE, because the intercept
is not identifiable simultaneously with the M-spline coefficients for
the baseline hazard (see the Identifiability Constraint section
above). |
runStan |
Logical. Whether to run the Stan program. If
FALSE, the function only generates the Stan code and data
without sampling. Default is TRUE. |
niter |
Total number of Bayesian posterior sampling iterations
(including warmup). Default is 3000. |
nwarmup |
Number of warmup (burn-in) iterations. Default is
1000. |
nchain |
Number of Markov chains for posterior sampling. Default
is 3. |
ncores |
Number of CPU cores to use when executing the chains in
parallel. Default is 1. |
The function returns a list of class "refundBayes"
containing the following elements:
| Element | Description |
|---|---|
stanfit |
The Stan fit object (class stanfit). Can
be used for convergence diagnostics, traceplots, and additional
summaries via the rstan package. |
spline_basis |
Basis functions used to reconstruct the functional coefficients from the posterior samples. |
stancode |
A character string containing the generated Stan model code. |
standata |
A list containing the data passed to the Stan model. |
int |
A vector of posterior samples for the intercept term
\(\eta_0\). NULL by
default since intercept = FALSE. |
scalar_coef |
A matrix of posterior samples for scalar coefficients
\(\boldsymbol{\gamma}\), where each row
is one posterior sample and each column corresponds to one scalar
predictor. NULL if no scalar predictors are included. |
func_coef |
A list of posterior samples for functional coefficients. Each element is a matrix where each row is one posterior sample and each column corresponds to one location on the functional domain. |
baseline_hazard |
A list containing posterior samples of baseline hazard
parameters: bhaz (baseline hazard values) and
cbhaz (cumulative baseline hazard values). |
family |
The family type: "Cox". |
The formula follows the mgcv::gam syntax. The left-hand
side is the observed survival time (not a Surv object). The
key component for specifying functional predictors is:
where:
tmat: an \(n \times
M\) matrix of time points defining the domain \(\mathcal{T}\) over which the functional
predictor is observed and the integral is computed. The domain adapts to
the actual values in tmat (e.g., \([0, 1]\), \([1,
1440]\), etc.).lmat: an \(n \times
M\) matrix of Riemann sum weights (\(L_m = t_{m+1} - t_m\)), controlling the
numerical integration over \(\mathcal{T}\).wmat: an \(n \times
M\) matrix of functional predictor values.bs: the type of spline basis (e.g., "cr"
for cubic regression splines, "cc" for cyclic cubic
regression splines).k: the number of basis functions.Scalar predictors are included as standard formula terms. The
censoring information is provided separately via the cens
argument, not through the formula.
We demonstrate the fcox_bayes() function using a
simulated example dataset with a time-to-event outcome and one
functional predictor.
## Load the example data
Func_Cox_Data <- readRDS("data/example_data_Cox.rds")
## Prepare the functional predictor and censoring indicator
Func_Cox_Data$wmat <- Func_Cox_Data$MIMS
Func_Cox_Data$cens <- 1 - Func_Cox_Data$eventThe example dataset contains:
survtime: the observed survival time \(Y_i = \min(T_i, C_i)\),event: a binary event indicator (\(1\) = event occurred, \(0\) = censored),X1: a scalar predictor,tmat: the \(n \times
M\) time point matrix (defines the domain \(\mathcal{T}\)),lmat: the \(n \times
M\) Riemann sum weight matrix (defines the integration weights
over \(\mathcal{T}\)),MIMS: the \(n \times
M\) functional predictor matrix (physical activity data).Note that the censoring indicator cens is constructed as
1 - event, following the convention where \(\delta_i = 0\) indicates an observed event
and \(\delta_i = 1\) indicates
censoring.
library(refundBayes)
refundBayes_FCox <- refundBayes::fcox_bayes(
survtime ~ X1 + s(tmat, by = lmat * wmat, bs = "cc", k = 10),
data = Func_Cox_Data,
cens = Func_Cox_Data$cens,
runStan = TRUE,
niter = 1500,
nwarmup = 500,
nchain = 3,
ncores = 3
)In this call:
survtime as the response, with one scalar predictor
X1 and one functional predictor encoded via
s(tmat, by = lmat * wmat, bs = "cc", k = 10).tmat, and the integration over the domain \(\mathcal{T}\) (determined by
tmat) is approximated using the weights in
lmat.cens is supplied separately, with
\(0\) = event observed and \(1\) = censored.bs = "cc" uses cyclic cubic regression splines,
appropriate for periodic functional predictors (e.g., 24-hour activity
patterns).k = 10 specifies 10 basis functions. In practice, 30–40
basis functions are recommended for moderately smooth functional data on
dense grids.intercept argument is not specified and defaults to
FALSE, which is appropriate for Cox models due to the
identifiability constraint with the baseline hazard.The plot() method for refundBayes objects
displays the estimated functional coefficient \(\hat{\beta}(t)\) along with pointwise 95%
credible intervals:
Posterior summaries of the functional coefficient can be computed
directly from the func_coef element:
## Posterior mean of the functional coefficient
mean_curve <- apply(refundBayes_FCox$func_coef[[1]], 2, mean)
## Pointwise 95% credible interval
upper_curve <- apply(refundBayes_FCox$func_coef[[1]], 2,
function(x) quantile(x, prob = 0.975))
lower_curve <- apply(refundBayes_FCox$func_coef[[1]], 2,
function(x) quantile(x, prob = 0.025))The posterior samples in func_coef[[1]] are stored as a
\(Q \times M\) matrix, where \(Q\) is the number of posterior samples and
\(M\) is the number of time points on
the functional domain.
The Bayesian results can be compared with frequentist estimates
obtained via mgcv::gam, which handles Cox proportional
hazards models through its cox.ph() family using partial
likelihood:
library(mgcv)
## Fit frequentist functional Cox model using mgcv
fit_freq <- gam(
survtime ~ s(tmat, by = lmat * wmat, bs = "cc", k = 10) + X1,
data = Func_Cox_Data,
family = cox.ph(),
weights = Func_Cox_Data$event
)
## Extract frequentist estimates
freq_result <- plot(fit_freq)Note that the frequentist approach uses cox.ph() family
with partial likelihood and a Breslow-type nonparametric estimator for
the baseline hazard, while the Bayesian approach models the baseline
hazard parametrically using M-splines. Despite this difference,
simulation studies in Jiang et al. (2025) show that both approaches
achieve comparable performance in terms of estimation accuracy and
coverage.
Setting runStan = FALSE allows you to inspect or modify
the Stan code before running the model:
## Generate Stan code without running the sampler
fcox_code <- refundBayes::fcox_bayes(
survtime ~ X1 + s(tmat, by = lmat * wmat, bs = "cc", k = 10),
data = Func_Cox_Data,
cens = Func_Cox_Data$cens,
runStan = FALSE
)
## Print the generated Stan code
cat(fcox_code$stancode)The generated Stan code includes a functions block that
defines custom log-likelihood functions for the Cox model
(cox_log_lpdf for observed events and
cox_log_lccdf for censored observations), in addition to
the standard data, parameters, and
model blocks.
k): For
illustrative purposes, k = 10 is often used. In practice,
30–40 basis functions are recommended for moderately smooth functional
data observed on dense grids.bs): Use
"cr" (cubic regression splines) for general functional
predictors. Use "cc" (cyclic cubic regression splines) when
the functional predictor is periodic (e.g., 24-hour activity
patterns).FALSE for Cox models because it is not simultaneously
identifiable with the baseline hazard M-spline coefficients. In most
cases, this default should not be changed.cens
vector correctly follows the convention \(\delta_i = 0\) for observed events and
\(\delta_i = 1\) for censored
observations. If your data has an event indicator (1 = event, 0 =
censored), use cens = 1 - event.niter = 3000 with nwarmup = 1000. Watch for
divergent transitions in the Stan output; if they occur, consider
increasing the number of warmup iterations or adjusting the
adapt_delta parameter.rstan package (e.g.,
rstan::traceplot(refundBayes_FCox$stanfit)) to ensure that
the Markov chains have converged.joint_FPCA = TRUE
for the relevant predictor to jointly estimate FPCA scores and
regression coefficients within the Cox model.These binaries (installable software) and packages are in development.
They may not be fully stable and should be used with caution. We make no claims about them.