Peginterferon beta-1a (Hu 2017)
Source:vignettes/articles/Hu_2017_peginterferon_beta_1a.Rmd
Hu_2017_peginterferon_beta_1a.RmdModel and source
- Citation: Hu X, Hang Y, Cui Y, Zhang J, Liu S, Seddighzadeh A, Deykin A, Nestorov I. Population-Based Pharmacokinetic and Exposure-Efficacy Analyses of Peginterferon Beta-1a in Patients With Relapsing Multiple Sclerosis. J Clin Pharmacol. 2017;57(8):1005-1016. doi:10.1002/jcph.883
- Description: One-compartment population PK model for peginterferon beta-1a in adults with relapsing multiple sclerosis (Hu 2017). First-order SC absorption with the absorption rate constrained above the elimination rate to avoid flip-flop kinetics. BMI is a covariate on both clearance and volume of distribution.
- Article: J Clin Pharmacol. 2017;57(8):1005-1016
Population
The Hu 2017 ADVANCE phase 3 analysis pooled 809 subjects with relapsing multiple sclerosis from a randomised, double-blind, placebo-controlled trial conducted at 183 sites in 26 countries (NCT00906399). Baseline demographics (Hu 2017 Table 1): 239 male and 570 female (70.5% female); predominantly White (n = 668) and Asian (n = 96); age 20.5-54.7 years (2.5th-97.5th percentile; median 36.6); body weight 46.0-103 kg (median 65.0); body mass index 17.4-35.5 kg/m^2 (median 23.3). Patients received SC peginterferon beta-1a 125 ug every 2 weeks or every 4 weeks; placebo subjects were rerandomised to active dosing at the end of year 1. Intensive PK sampling was performed in 25 subjects (12 on Q2W, 13 on Q4W); the remainder had sparse sampling at weeks 4, 12, 24, 56, and 84.
The same information is available programmatically via
readModelDb("Hu_2017_peginterferon_beta_1a")$population.
Source trace
Per-parameter origin is recorded as an in-file comment next to each
ini() entry in
inst/modeldb/specificDrugs/Hu_2017_peginterferon_beta_1a.R.
The table below collects them for review.
| Equation / parameter | Value | Source location |
|---|---|---|
lcl (theta_1) |
log(3.28) L/h |
Table 3 final model |
lvc (theta_2) |
log(435) L |
Table 3 final model |
e_bmi_cl (theta_3) |
0.779 |
Table 3 final model (BMI exponent on CL) |
e_bmi_vc (theta_4) |
0.0353 |
Table 3 final model (coefficient on (BMI - 23.71) inside exp on V) |
ltheta_diff (theta_5) |
log(0.207) 1/h |
Table 3 final model (ka - kel offset) |
etalcl IIV (omega^2_CL) |
0.145 |
Table 3 final model |
etalvc IIV (omega^2_V) |
0.352 |
Table 3 final model |
expSd (SD1) |
0.566 |
Table 3 final model (log-scale residual SD with $SIGMA 1 FIXED) |
| Bioavailability F=1 | n/a | Methods, Population PK Model section (no IV data; F fixed at 1) |
| Ka constraint | ka = exp(ltheta_diff) + cl/vc |
Equation 1; prevents flip-flop kinetics |
| Final CL equation | CL = theta_1 * (BMI/23.71)^theta_3 |
Equation 12 |
| Final V equation | V = theta_2 * exp(theta_4 * (BMI - 23.71)) |
Equation 13 |
| BMI reference 23.71 | n/a | Discussion of Table 3 (typical BMI used in eqs 12-13) |
Virtual cohort
Original observed data are not publicly available. The cohort below approximates Table 1 demographics for the final PK population: BMI sampled from a truncated log-normal distribution centred on the median (23.3 kg/m^2) with spread matched to the reported 2.5th-97.5th percentiles (17.4-35.5 kg/m^2). Five quintile groups based on BMI are also constructed to match Hu 2017’s reported quintile medians (19.3, 21.7, 23.8, 26.3, 31.1 kg/m^2). All subjects receive 125 ug SC every 2 weeks for five dosing intervals (steady state by intervals 3-5 given the ~92-hour terminal half-life).
set.seed(20260520)
n_per_quintile <- 100L
quintile_meds <- c(19.3, 21.7, 23.8, 26.3, 31.1)
make_quintile <- function(med, q, id_offset) {
tibble::tibble(
id = id_offset + seq_len(n_per_quintile),
BMI = med * exp(rnorm(n_per_quintile, mean = 0, sd = 0.04)),
quintile = factor(paste0("Q", q), levels = paste0("Q", 1:5)),
bmi_median = med
)
}
cohort <- dplyr::bind_rows(lapply(seq_along(quintile_meds), function(q) {
make_quintile(quintile_meds[q], q, id_offset = (q - 1L) * n_per_quintile)
}))
stopifnot(!anyDuplicated(cohort$id))
# Q2W dosing for 5 intervals (84 days = 2016 hours), with rich sampling
tau <- 14 * 24 # 14 days in hours
n_doses <- 5L
dose_times <- seq(0, by = tau, length.out = n_doses)
obs_grid <- sort(unique(c(
seq(0, n_doses * tau, by = 6),
unlist(lapply(dose_times, function(t0) t0 + c(0.5, 1, 2, 4, 8, 12, 24, 48, 72, 120, 168, 240, 336)))
)))
obs_grid <- obs_grid[obs_grid >= 0 & obs_grid <= n_doses * tau]
doses <- cohort |>
tidyr::crossing(time = dose_times) |>
dplyr::mutate(amt = 125, cmt = "depot", evid = 1L)
obs <- cohort |>
tidyr::crossing(time = obs_grid) |>
dplyr::mutate(amt = 0, cmt = NA_character_, evid = 0L)
events <- dplyr::bind_rows(doses, obs) |>
dplyr::arrange(id, time, dplyr::desc(evid)) |>
dplyr::select(id, time, amt, cmt, evid, BMI, quintile, bmi_median)
stopifnot(!anyDuplicated(events[, c("id", "time", "evid")]))Simulation
mod <- rxode2::rxode2(readModelDb("Hu_2017_peginterferon_beta_1a"))
#> ℹ parameter labels from comments will be replaced by 'label()'
conc_unit <- mod$units[["concentration"]]
sim <- rxode2::rxSolve(mod, events = events,
keep = c("BMI", "quintile", "bmi_median")) |>
as.data.frame() |>
tibble::as_tibble()Replicate published values
Steady-state concentration-time profiles by BMI quintile
Hu 2017 stratifies post hoc into BMI quintiles to support the
exposure-stratified safety and efficacy subgroup analyses. Lower BMI is
associated with higher exposure (lower CL via the
(BMI/23.71)^0.779 term and lower V via the
exp(0.0353 * (BMI - 23.71)) term). The plot below shows
simulated 5th-50th-95th percentiles by quintile for the final dosing
interval.
last_interval <- (n_doses - 1L) * tau
sim |>
dplyr::filter(!is.na(Cc), time >= last_interval, time <= last_interval + tau) |>
dplyr::mutate(time_rel_h = time - last_interval) |>
dplyr::group_by(time_rel_h, quintile) |>
dplyr::summarise(
Q05 = quantile(Cc * 1000, 0.05),
Q50 = quantile(Cc * 1000, 0.50),
Q95 = quantile(Cc * 1000, 0.95),
.groups = "drop"
) |>
ggplot(aes(time_rel_h, Q50, colour = quintile, fill = quintile)) +
geom_ribbon(aes(ymin = Q05, ymax = Q95), alpha = 0.15, colour = NA) +
geom_line(linewidth = 0.8) +
labs(x = "Time after dose (h)", y = "Cc (pg/mL)",
title = "Steady-state peginterferon beta-1a profile by BMI quintile",
caption = paste0("125 ug SC Q2W; final (5th) dosing interval; conc in pg/mL = 1000 * ",
conc_unit, "."))
Quintile median Cmax and AUC0-tau (deterministic, typical-value check)
Hu 2017 reports the model-derived median Cmax and AUC0-tau (AUCt) for each BMI quintile (Discussion of Table 3): Cmax = 297, 273, 254, 232, 197 pg/mL and AUCt = 44.7, 40.8, 38.0, 35.2, 30.8 hng/mL at quintile medians 19.3, 21.7, 23.8, 26.3, 31.1 kg/m^2. AUCt is the steady-state AUC over a dosing interval but, because for first-order absorption with linear elimination AUC0-tau at steady state equals Dose/CL, it numerically equals AUC0-inf after a single dose. The reported Cmax magnitudes correspond to the single-dose Cmax (the accumulation factor at the Q2W regimen is small, 1/(1-exp(-keltau)) ~ 1.09, so single-dose Cmax ~ 91 percent of Cmax at steady state); a typical-value single-dose simulation (random effects set to zero) reproduces both metrics exactly.
mod_typical <- mod |> rxode2::zeroRe()
typical_cohort <- tibble::tibble(
id = seq_along(quintile_meds),
BMI = quintile_meds,
quintile = factor(paste0("Q", seq_along(quintile_meds)), levels = paste0("Q", 1:5))
)
# Single 125 ug dose, observe over one Q2W interval (336 hours)
single_dose <- typical_cohort |>
dplyr::mutate(time = 0, amt = 125, cmt = "depot", evid = 1L)
single_obs <- typical_cohort |>
tidyr::crossing(time = sort(unique(c(seq(0, tau, by = 2),
c(0.5, 1, 4, 8, 12, 16, 18, 20, 24, 36, 48, 72, 120, 168, 240, 336))))) |>
dplyr::mutate(amt = 0, cmt = NA_character_, evid = 0L)
single_events <- dplyr::bind_rows(single_dose, single_obs) |>
dplyr::arrange(id, time, dplyr::desc(evid)) |>
dplyr::select(id, time, amt, cmt, evid, BMI, quintile)
sim_typ <- rxode2::rxSolve(mod_typical, events = single_events,
keep = c("BMI", "quintile")) |>
as.data.frame() |>
tibble::as_tibble()
#> ℹ omega/sigma items treated as zero: 'etalcl', 'etalvc'
#> Warning: multi-subject simulation without without 'omega'
conc_obj <- PKNCA::PKNCAconc(
sim_typ |>
dplyr::filter(!is.na(Cc)) |>
dplyr::select(id, time, Cc, quintile),
Cc ~ time | quintile + id,
concu = "ng/mL", timeu = "hour"
)
dose_obj <- PKNCA::PKNCAdose(
single_dose |>
dplyr::select(id, time, amt, quintile),
amt ~ time | quintile + id,
doseu = "ug"
)
intervals_single <- data.frame(
start = 0,
end = tau,
cmax = TRUE,
tmax = TRUE,
auclast = TRUE,
aucinf.obs = TRUE
)
nca_typ <- PKNCA::pk.nca(PKNCA::PKNCAdata(conc_obj, dose_obj, intervals = intervals_single))
nca_typ_tbl <- as.data.frame(nca_typ$result) |>
dplyr::filter(PPTESTCD %in% c("cmax", "aucinf.obs")) |>
dplyr::select(quintile, PPTESTCD, PPORRES) |>
tidyr::pivot_wider(names_from = PPTESTCD, values_from = PPORRES) |>
dplyr::mutate(cmax_pg_mL = cmax * 1000)
published <- tibble::tibble(
quintile = factor(paste0("Q", 1:5), levels = paste0("Q", 1:5)),
bmi_median = quintile_meds,
cmax_pub_pg_mL = c(297, 273, 254, 232, 197),
auct_pub_h_ng_mL = c(44.7, 40.8, 38.0, 35.2, 30.8)
)
dplyr::left_join(published, nca_typ_tbl, by = "quintile") |>
dplyr::transmute(
quintile, bmi_median,
cmax_pub_pg_mL,
cmax_sim_pg_mL = round(cmax_pg_mL, 1),
auct_pub_h_ng_mL,
auct_sim_h_ng_mL = round(aucinf.obs, 2)
) |>
knitr::kable(caption = "Typical-value Cmax and AUC by BMI quintile: simulated single-dose vs Hu 2017 Table 3 (Discussion). AUC0-tau at steady state equals AUC0-inf after a single dose for this linear 1-cmt model.")| quintile | bmi_median | cmax_pub_pg_mL | cmax_sim_pg_mL | auct_pub_h_ng_mL | auct_sim_h_ng_mL |
|---|---|---|---|---|---|
| Q1 | 19.3 | 297 | 297.3 | 44.7 | 44.72 |
| Q2 | 21.7 | 273 | 273.0 | 40.8 | 40.82 |
| Q3 | 23.8 | 254 | 253.6 | 38.0 | 37.99 |
| Q4 | 26.3 | 232 | 232.3 | 35.2 | 35.14 |
| Q5 | 31.1 | 197 | 196.8 | 30.8 | 30.84 |
PKNCA validation on the stochastic cohort
The full multi-dose stochastic cohort lets us inspect the steady-state Cmax / AUC distribution per BMI quintile, including between-subject variability.
sim_nca <- sim |>
dplyr::filter(!is.na(Cc), time >= last_interval, time <= last_interval + tau) |>
dplyr::select(id, time, Cc, quintile)
conc_obj_all <- PKNCA::PKNCAconc(sim_nca, Cc ~ time | quintile + id,
concu = "ng/mL", timeu = "hour")
dose_df_all <- doses |>
dplyr::filter(time == last_interval) |>
dplyr::select(id, time, amt, quintile)
dose_obj_all <- PKNCA::PKNCAdose(dose_df_all, amt ~ time | quintile + id,
doseu = "ug")
intervals_ss <- data.frame(
start = last_interval,
end = last_interval + tau,
cmax = TRUE,
tmax = TRUE,
auclast = TRUE
)
nca_all <- PKNCA::pk.nca(PKNCA::PKNCAdata(conc_obj_all, dose_obj_all,
intervals = intervals_ss))
summary(nca_all)
#> Interval Start Interval End quintile N AUClast (hour*ng/mL) Cmax (ng/mL)
#> 1344 1680 Q1 100 43.3 [34.5] 0.332 [49.7]
#> 1344 1680 Q2 100 40.8 [39.4] 0.326 [48.6]
#> 1344 1680 Q3 100 38.5 [34.5] 0.312 [43.1]
#> 1344 1680 Q4 100 35.3 [36.3] 0.253 [41.6]
#> 1344 1680 Q5 100 31.1 [35.6] 0.244 [46.1]
#> Tmax (hour)
#> 18.0 [4.00, 18.0]
#> 18.0 [8.00, 18.0]
#> 18.0 [8.00, 18.0]
#> 18.0 [8.00, 18.0]
#> 18.0 [8.00, 18.0]
#>
#> Caption: AUClast, Cmax: geometric mean and geometric coefficient of variation; Tmax: median and range; N: number of subjectsAssumptions and deviations
- The virtual cohort approximates Table 1 demographics by sampling BMI within each published quintile from a log-normal distribution centred on the quintile median; the model’s only structural covariate is BMI so other Table 1 columns (weight, height, age, sex, race) are not represented.
- The IIV variance is encoded directly from the paper’s
omega^2point estimates (0.145 for CL and 0.352 for V), which Hu 2017 reports as intersubject variances (not CV%); nolog(1 + CV^2)conversion is required. - The residual error is encoded as
Cc ~ lnorm(expSd)withexpSd = 0.566on the log scale, matching the NONMEM “log-additive” formY = LOG(F) + SD1 * EPS(1)with$SIGMA 1 FIXEDreported in Table 3. - Bioavailability is held at F = 1 because no IV reference PK was
available; the absorption rate is constrained as
ka = exp(ltheta_diff) + cl/vcto prevent the flip-flop kinetic ambiguity (Hu 2017 Equation 1). - The exposure-efficacy (AUC -> ARR) component of the publication is not packaged here because it is a Poisson-gamma WinBUGS regression on individual-level cumulative AUC rather than a continuous-time ODE PD model; the model file covers only the PopPK structure (Equations 12 and 13 with Equation 1).
- Renal function, age, and sex were significant covariates in the full PK model (Table 2) but were dropped in the backward-elimination step and do not appear in the packaged final model (Table 3); see Hu 2017 Discussion for the renal-impairment justification.