MLB_SLB_anlaysis: The mixture prior for longitudinal data borrowing (MLB) and...

View source: R/MLB_SLB_anlaysis.R

MLB_SLB_anlaysisR Documentation

The mixture prior for longitudinal data borrowing (MLB) and self-adapting mixture prior for longitudinal data information borrowing (SLB) Analysis under SPM with MNAR dropout

Description

Arms and notation (H/C/T):

  • H — Historical control arm. External/previous-study control, used to build an informative prior for the concurrent control.

  • C — Concurrent control arm. In-trial control; first fitted under a non-informative prior to assess prior–data conflict and compute an adaptive weight; then re-fitted under an MLB/SLB prior.

  • T — Treatment arm. In-trial treatment; typically fitted under a non-informative prior, then compared against the (re)fitted control.

Usage

MLB_SLB_anlaysis(
  historical_df,
  concurrent_df,
  treatment_df,
  family = c("gaussian", "bernoulli"),
  delta,
  n_hist = NULL,
  fixed_weight = 0.5,
  mcmc_settings = list(n.chains = 3, n.iter = 10000, n.burnin = 5000, n.thin = 2,
    parallel = FALSE),
  decision_MLB,
  direction_MLB = c("lower", "higher"),
  decision_SLB,
  direction_SLB = c("lower", "higher")
)

Arguments

historical_df

Long-format data.frame for H with columns id,time,R,Y.

concurrent_df

Long-format data.frame for C with columns id,time,R,Y.

treatment_df

Long-format data.frame for T with columns id,time,R,Y.

family

Character, "gaussian" or "bernoulli" (probit link), passed to SPM.

delta

Clinically significant difference (CSD) used in SLB weight.

n_hist

Positive integer: historical sample size for unit-information prior (continuous only).

fixed_weight

MLB mixing weight \omega (default 0.5).

mcmc_settings

JAGS settings list with fields n.chains,n.iter,n.burnin,n.thin,parallel.

decision_MLB

A REQUIRED decision function for MLB prior with threshold p that takes two numeric vectors of posterior samples (\theta_T,\theta_C) and returns logical/0-1 indicating treatment superiority.

Direction of test (how probabilities are computed/decisions typically defined):

  • Larger-is-better: function(theta_t, theta_c, p=0.95) mean(theta_t > theta_c) > p

  • Smaller-is-better: function(theta_t, theta_c, p=0.95) mean(theta_t < theta_c) > p

direction_MLB

Character scalar specifying the clinical direction of superiority for MLB prior:

  • "lower": smaller is better; report \Pr(\theta_T < \theta_C).

  • "higher": larger is better; report \Pr(\theta_T > \theta_C).

decision_SLB

A REQUIRED decision function for SLB prior with threshold p that takes two numeric vectors of posterior samples (\theta_T,\theta_C) and returns logical/0-1 indicating treatment superiority.

Direction of test (how probabilities are computed/decisions typically defined):

  • Larger-is-better: function(theta_t, theta_c, p=0.95) mean(theta_t > theta_c) > p

  • Smaller-is-better: function(theta_t, theta_c, p=0.95) mean(theta_t < theta_c) > p

direction_SLB

Character scalar specifying the clinical direction of superiority for SLB prior:

  • "lower": smaller is better; report \Pr(\theta_T < \theta_C).

  • "higher": larger is better; report \Pr(\theta_T > \theta_C).

Details

Target parameters \theta_H,\theta_C,\theta_T:

  • family = "gaussian" (continuous outcome): \theta is the total change at the final visit t_K, i.e., \theta=\beta_1 t_K (thus \beta_1=\theta/t_K).

  • family = "bernoulli" (binary, probit link): \theta is the marginal response probability at the final visit, \Pr(Y=1 \text{ at } t_K)\in (0,1).

We write \theta_H, \theta_C, \theta_T for the historical, concurrent-control, and treatment arms, respectively.

Workflow (continuous or binary endpoints):

  1. Fit H under SPM with a vague prior on \theta to obtain posterior draws.

  2. Build an informative prior g_0 for \theta_C via RBesT::mixfit on the \theta_H draws.

  3. Build a non-informative prior g_1: Gaussian: unit-information prior from g_0 (inflate SD by \sqrt{n_\mathrm{hist}}); Bernoulli: \mathrm{Beta}(1,1).

  4. Fit C under g_1 to get posterior samples.

  5. Compute SLB weight via posterior-probability-ratio KDE (see SLB_weight).

  6. Construct MLB prior (fixed weight) and SLB prior (data-adaptive weight) via Mixprior.

  7. Fit C under MLB/SLB priors; fit T under g_1.

  8. Posterior comparisons \theta_T vs \theta_C and decisions per direction.

Value

An object of class "mlbslb_result":

  • estimates: posterior means of \theta for each arm/prior (MLB/SLB).

  • weights: list with MLB_weight and SLB_weight.

  • probabilities: posterior superiority probabilities (per direction) under MLB/SLB.

  • decisions: 0/1 decisions under MLB/SLB according to your decision(). (1 indicates test superiority is established).

  • posterior_samples: posterior draws used in the analysis.

Examples

set.seed(1000)
t_vec <- seq(4, 48, 4)
# --- Continuous outcome ---
data_H <- generate_spm(n=60, t_vec, family="gaussian",
                       alpha0=-4, alpha1=0.05, rho=-1, sigma_b=1,
                       theta= -3.2, sigma_e=1)$dat
data_C <- generate_spm(n=30,  t_vec, family="gaussian",
                       alpha0=-4, alpha1=0.05, rho=-1, sigma_b=1,
                       theta= -3.2, sigma_e=1)$dat
data_T <- generate_spm(n=60,  t_vec, family="gaussian",
                       alpha0=-5.3, alpha1=0.05, rho=-1.5, sigma_b=1,
                       theta= -3.7, sigma_e=1)$dat


# Full MCMC fitting takes several minutes.
ans_1 <- MLB_SLB_anlaysis(
  historical_df = data_H, concurrent_df = data_C, treatment_df = data_T,
  family="gaussian", delta=0.5, n_hist=length(unique(data_H$id)), fixed_weight=0.5,
  mcmc_settings = list(n.chains=3, n.iter=10000, n.burnin=5000, n.thin=2, parallel=FALSE),
  decision_MLB = function(theta_t, theta_c, p = 0.95) mean(theta_t < theta_c) > 0.95,
  # Smaller-is-better (treatment < control), p = 0.95
  direction_MLB =  "lower",
  decision_SLB = function(theta_t, theta_c, p = 0.95) mean(theta_t < theta_c) > 0.95,
  # Smaller-is-better (treatment < control), p = 0.95
  direction_SLB =  "lower"
)
ans_1$decisions; ans_1$probabilities


# --- Binary outcome ---
set.seed(1000)
data_H <- generate_spm(n=200, t_vec, family="bernoulli",
                       alpha0=-4, alpha1=0.05, rho=-1, sigma_b=1,
                       theta=0.40, beta0=-2)$dat
data_C <- generate_spm(n=100, t_vec, family="bernoulli",
                       alpha0=-4, alpha1=0.05, rho=-1, sigma_b=1,
                       theta=0.40, beta0=-2)$dat
data_T <- generate_spm(n=200, t_vec, family="bernoulli",
                       alpha0=-5.3, alpha1=0.05, rho=-1.5, sigma_b=1,
                       theta=0.50, beta0=-1.5)$dat


# Full MCMC fitting takes several minutes.
ans_2 <- MLB_SLB_anlaysis(historical_df = data_H, concurrent_df = data_C, treatment_df = data_T,
   family="bernoulli", delta=0.1, n_hist=length(unique(data_H$id)), fixed_weight=0.5,
   mcmc_settings = list(n.chains=3, n.iter=10000, n.burnin=5000, n.thin=2, parallel=FALSE),
   decision_MLB = function(theta_t, theta_c, p = 0.95) mean(theta_t > theta_c) > 0.95,
   # Larger-is-better (treatment > control), p = 0.95
   direction_MLB =  "higher",
   decision_SLB = function(theta_t, theta_c, p = 0.95) mean(theta_t > theta_c) > 0.95,
   # Larger-is-better (treatment > control), p = 0.95
   direction_SLB =  "higher"
)
ans_2$decisions; ans_2$probabilities


BDIB documentation built on Oct. 18, 2026, 5:08 p.m.

Related to MLB_SLB_anlaysis in BDIB...