Rizopoulos 2016 - Joint Model Specification and Posterior

Summary

Observed data are . The longitudinal outcome follows a GLMM with linear predictor ; the hazard is . Conditional on the processes are independent, which gives a posterior factorisation. The survival integral has no closed form and is computed by Gauss-Kronrod or Gauss-Legendre quadrature.

Main Content

Joint model (Eqs. 1-3)

Notation: true event time, censoring, , , the longitudinal responses at times . Longitudinal (GLMM, Eq. 1): , monotone link, from the exponential family, or multivariate . Survival (Eq. 2): , the marker history, exogenous covariates, the association parameters. Baseline hazard (Eq. 3): , B-splines with knots . Rule of thumb: total parameters between and of the number of events (Harrell 2001); or use 15-20 knots with a penalty (Eilers and Marx 1996).

Conditional independence and posterior (Eqs. 4-7)

Given and , longitudinal and event processes are independent and longitudinal measurements are mutually independent: and . Hence

with the exponential-family density and the survival part

The integral requires numerical quadrature (Gauss-Kronrod, Gauss-Legendre).

Priors. Independent diffuse normals for . Penalised spline: , ( the -th difference penalty, its rank), (Lang and Brezger 2004). Inverse-Wishart for , inverse-Gamma for the error variance .

Examples

Cumulative hazard by Gauss-Legendre

Setup: , baseline , : . With the closed-form cumulative hazard is ; a 15-point Gauss-Legendre rule reproduces it to . Interpretation: for smooth hazards a modest number of quadrature nodes per subject suffices, which is how E25 evaluates inside PyMC.

import numpy as np
def cum_hazard(T, b0, b1, alpha, lam=0.05, k=15):
    x, w = np.polynomial.legendre.leggauss(k)
    s = 0.5*T*(x+1); ww = 0.5*T*w
    return (ww * lam * np.exp(alpha*(b0 + b1*s))).sum()

PyMC-style sketch (untested).

with pm.Model():
    chol, corr, sd = pm.LKJCholeskyCov("chol", n=2, eta=2, sd_dist=pm.HalfNormal.dist(1))
    b = pm.MvNormal("b", 0, chol=chol, shape=(N, 2))             # random intercept, slope
    eta = beta0 + beta1*t_obs + b[sub,0] + b[sub,1]*t_obs
    pm.Normal("y", eta, sigma, observed=y)
    alpha = pm.Normal("alpha", 0, 1)
    H = cum_hazard_gl(T, beta0 + b[:,0], beta1 + b[:,1], alpha, shape, scale)  # nodes via leggauss
    pm.Potential("surv", (delta*(log_h(T)) - H).sum())

Connections

Survival Analysis, Hierarchical Models, Rizopoulos 2016 - Implementation MCMC and Baseline Hazard, Rizopoulos 2016 - Association Structures and Transformation Functions.

See Also

Rizopoulos 2016 - JMbayes Joint Models Overview