Skip to contents

The goal of the jmpost package is to fit joint models involving:

  1. a parametric time-to-event sub-model,
  2. a nonlinear (or linear) mixed-effect sub-model, describing individual time profiles (i.e. trajectories) for a continuous marker,
  3. a link function (a.k.a. association term).

More specifically, the model implemented in this package utilizes a modelling framework described previously [1-3] to link overall survival to tumour size data in oncology clinical trials.

[1] Tardivon et al. Association between tumour size kinetics and survival in patients with urothelial carcinoma treated with atezolizumab: Implications for patient follow-up. Clin Pharm Ther, 2019.
[2] Kerioui et al. Bayesian inference using Hamiltonian Monte-Carlo algorithm for nonlinear joint modelling in the context of cancer immunotherapy. Stat in Med, 2020.
[3] Kerioui et al. Modelling the association between biomarkers and clinical outcome: An introduction to nonlinear joint models. Br J Clin Pharm, 2022.

The models are implemented in STAN, and the package provides a flexible user interface. Please reach out to us via issues or email (see the DESCRIPTION file) if you have comments or questions or would like to get involved in the ongoing development, thank you!

Installation

GitHub

You can install the current development version from GitHub with:

if (!require("remotes")) {
    install.packages("remotes")
}
remotes::install_github("genentech/jmpost")

Please note that this package requires cmdstanr.

CRAN

This package has not been published to CRAN yet.

Getting Started

See also the model fitting vignette for more details. Here we present a very basic example here.

First we simulate a data set. In practice you want to follow a similar structure of the input data and use DataJoint() to bring it into the right format.

library(jmpost)
#> Registered S3 methods overwritten by 'ggpp':
#>   method                  from   
#>   heightDetails.titleGrob ggplot2
#>   widthDetails.titleGrob  ggplot2
set.seed(321)
sim_data <- SimJointData(
    design = list(
        SimGroup(50, "Arm-A", "Study-X"),
        SimGroup(50, "Arm-B", "Study-X")
    ),
    longitudinal = SimLongitudinalRandomSlope(
        times = c(1, 50, 100, 150, 200, 250, 300),
    ),
    survival = SimSurvivalWeibullPH(
        lambda = 1 / 300,
        gamma = 0.97
    )
)
#> INFO: 1 subject did not die before max(times)

joint_data <- DataJoint(
    subject = DataSubject(
        data = sim_data@survival,
        subject = "subject",
        arm = "arm",
        study = "study"
    ),
    survival = DataSurvival(
        data = sim_data@survival,
        formula = Surv(time, event) ~ cov_cat + cov_cont
    ),
    longitudinal = DataLongitudinal(
        data = sim_data@longitudinal,
        formula = sld ~ time,
        threshold = 5
    )
)

Then we specify the joint model, here we use a Generalized Stein-Fojo model for the longitudinal part, and a Weibull proportional hazards model for the survival part. The longitudinal model impacts the hazard via a term for the derivative and another term for the time-to-growth.

joint_model <- JointModel(
    longitudinal = LongitudinalGSF(),
    survival = SurvivalWeibullPH(),
    link = Link(
        linkDSLD(),
        linkTTG()
    )
)

Finally we can sample the parameters via MCMC from the underlying Stan model. Note that in a real application you will choose more warm up and sampling iterations.

mcmc_results <- sampleStanModel(
    joint_model,
    data = joint_data,
    iter_sampling = 100,
    iter_warmup = 100,
    chains = 1,
    parallel_chains = 1
)

Citing jmpost

To cite jmpost please see here.