Ciprofloxacin (Zhao 2014)
Source:vignettes/articles/Zhao_2014_ciprofloxacin.Rmd
Zhao_2014_ciprofloxacin.RmdModel and source
- Citation: Zhao W, Hill H, Le Guellec C, Neal T, Mahoney S, Paulus S, Castellan C, Kassai B, van den Anker JN, Kearns GL, Turner MA, Jacqz-Aigrain E. Population pharmacokinetics of ciprofloxacin in neonates and young infants less than three months of age. Antimicrob Agents Chemother. 2014;58(11):6572-6580.
- Description: Two-compartment popPK model with first-order elimination for intravenous ciprofloxacin in neonates and young infants less than three months of age. Allometric scaling on current weight (fixed exponents 0.75 on CL/Q, 1 on V1/V2); CL further modified by a renal-maturation factor in gestational age and postnatal age, a renal-function factor in serum creatinine, and a 29.2% reduction with inotrope coadministration.
- Article: https://doi.org/10.1128/AAC.03568-14
Population
The model was fit to 60 newborn infants (postmenstrual age 24.9-47.9 weeks; current weight 700-4200 g) treated for suspected or documented Gram-negative serious infections in two UK neonatal / paediatric intensive care units (Liverpool Women’s Hospital and Alder Hey Children’s Hospital, TINN consortium). The cohort received intravenous ciprofloxacin as a 30 or 60 min infusion, predominantly 10 mg/kg BID (47/60) with smaller groups at 5 mg/kg BID (7/60) and 10 mg/kg TID (6/60). Eighty-eight percent of subjects were classified as White, 8% Asian, and 4% Unknown. Baseline demographics in this vignette follow Zhao 2014 Table 2.
The same information is available programmatically via the model’s
population metadata
(readModelDb("Zhao_2014_ciprofloxacin")$population after
devtools::load_all()).
Source trace
The per-parameter origin is recorded as an in-file comment next to
each ini() entry in
inst/modeldb/specificDrugs/Zhao_2014_ciprofloxacin.R. The
table below collects them for review.
| Equation / parameter | Value | Source location |
|---|---|---|
| Structural model | 2-cmt IV | Zhao 2014 Results, “Model building” paragraph 2 |
| V1 (theta1) | 1.97 L | Table 4 (RSE 17.7%) |
| V2 (theta2) | 1.93 L | Table 4 (RSE 21.9%) |
| Q (theta3) | 2.5 L/h | Table 4 (RSE 32.6%) |
| CL (theta4) | 0.366 L/h | Table 4 (RSE 6.0%) |
| Allometric exponents | 0.75 (CL, Q); 1 (V1, V2) | Methods, “Covariate analysis” paragraph 1 |
| Reference CW | 1955 g | Table 4 footnote (cohort median) |
| F_age GA exponent (theta5) | 2.11 | Table 4 (RSE 11.9%) |
| Reference GA | 27.9 wk | Table 4 footnote (cohort median) |
| F_age PNA exponent (theta6) | 0.494 | Table 4 (RSE 10.8%) |
| Reference PNA | 27 days | Table 4 footnote (cohort median) |
| RF CREAT coefficient (theta7) | -0.00335 per umol/L | Table 4 (RSE 46.0%) |
| Reference CREAT | 42 umol/L | Table 4 footnote (cohort median) |
| F_inotrope (theta8) | 0.708 | Table 4 (RSE 10.9%); 29.2% CL reduction |
| IIV V1 | 48.1% CV | Table 4 |
| IIV V2 | 49.3% CV | Table 4 |
| IIV CL | 33.2% CV | Table 4 |
| Proportional residual | 19.3% CV | Table 4 (RSE 28.2%) |
Virtual cohort
Original observed data are not publicly available. The virtual cohort below sets covariate distributions to match Zhao 2014 Table 2: postmenstrual age 35.7 +/- 6.5 weeks, current weight 2060 +/- 1020 g, gestational age 30.4 +/- 5.8 weeks, postnatal age median 27 days (range 5-121), serum creatinine median 41 umol/L (range 22-164), inotrope coadministration 22/60 subjects.
set.seed(20260609)
n_subj <- 200L
truncated_normal <- function(n, mean, sd, lower, upper) {
out <- numeric(0)
while (length(out) < n) {
draws <- rnorm(n * 2, mean = mean, sd = sd)
out <- c(out, draws[draws >= lower & draws <= upper])
}
out[seq_len(n)]
}
# Truncated log-normal for skewed PNA (median 27 d, range 5-121)
pna_days <- truncated_normal(n_subj, mean = log(27), sd = 0.7,
lower = log(5), upper = log(121))
pna_days <- exp(pna_days)
# Truncated log-normal for serum creatinine (median 41, range 22-164)
creat <- truncated_normal(n_subj, mean = log(41), sd = 0.45,
lower = log(22), upper = log(164))
creat <- exp(creat)
cohort <- tibble(
id = seq_len(n_subj),
WT = truncated_normal(n_subj, mean = 2.060, sd = 1.020, lower = 0.700, upper = 4.200),
GA = truncated_normal(n_subj, mean = 30.4, sd = 5.8, lower = 23.3, upper = 42.0),
PNA_days = pna_days,
PNA = pna_days / 30.4375, # canonical column is months
PMA = GA + PNA_days / 7, # weeks
CREAT = creat,
CONMED_INOTROPE = as.integer(runif(n_subj) < 22 / 60),
pma_stratum = ifelse(PMA < 34, "PMA<34", "PMA>=34"),
dose_mgkg = ifelse(PMA < 34, 7.5, 12.5) # Zhao 2014 dose-optimisation recommendation
)
cohort$amt <- cohort$WT * cohort$dose_mgkg
# Build event table: 12 h BID over 5 days (10 doses) plus dense sampling.
build_events <- function(df, tau = 12, n_doses = 10L,
sample_grid = sort(unique(c(seq(0, tau, by = 0.25),
seq(tau, tau * n_doses, by = 1),
seq(tau * n_doses,
tau * n_doses + tau, by = 0.25))))) {
doses <- df %>%
crossing(dose_num = seq_len(n_doses)) %>%
transmute(id, time = (dose_num - 1L) * tau, amt, evid = 1L, cmt = "central",
dur = 0.5, WT, GA, PNA, CREAT, CONMED_INOTROPE, pma_stratum, dose_mgkg)
obs <- df %>%
crossing(time = sample_grid) %>%
transmute(id, time, amt = NA_real_, evid = 0L, cmt = NA_character_,
dur = NA_real_, WT, GA, PNA, CREAT, CONMED_INOTROPE, pma_stratum, dose_mgkg)
bind_rows(doses, obs) %>% arrange(id, time, desc(evid))
}
events <- build_events(cohort)
stopifnot(!anyDuplicated(unique(events[, c("id", "time", "evid")])))Simulation
mod <- readModelDb("Zhao_2014_ciprofloxacin")
# Stochastic simulation including IIV (for VPC-style figures)
sim <- rxode2::rxSolve(
mod, events = events,
keep = c("pma_stratum", "dose_mgkg", "WT", "GA", "PNA", "CREAT", "CONMED_INOTROPE")
) %>% as.data.frame()Replicate published figures
Figure 3 – ciprofloxacin concentration versus time
Zhao 2014 Figure 3 plots all observed concentration-time points over the first 24 h with the population-prediction line overlaid for a typical patient. The VPC ribbon below shows the 5th-50th-95th percentile band over the first dosing interval at steady state, broken out by PMA stratum and the dose-optimisation recommendation (7.5 mg/kg BID for PMA<34 wk; 12.5 mg/kg BID for PMA>=34 wk).
sim_first24 <- sim %>%
dplyr::filter(time <= 24) %>%
dplyr::filter(!is.na(Cc))
sim_first24 %>%
group_by(time, pma_stratum) %>%
summarise(
Q05 = quantile(Cc, 0.05, na.rm = TRUE),
Q50 = quantile(Cc, 0.50, na.rm = TRUE),
Q95 = quantile(Cc, 0.95, na.rm = TRUE),
.groups = "drop"
) %>%
ggplot(aes(time, Q50)) +
geom_ribbon(aes(ymin = Q05, ymax = Q95), alpha = 0.25) +
geom_line() +
facet_wrap(~pma_stratum) +
scale_y_log10() +
labs(x = "Time (h, since first dose)", y = "Cc (mg/L)",
title = "Figure 3 -- VPC of simulated ciprofloxacin concentrations",
caption = "Replicates the structure of Zhao 2014 Figure 3.")
#> Warning in scale_y_log10(): log-10 transformation introduced infinite values.
#> log-10 transformation introduced infinite values.
#> log-10 transformation introduced infinite values.
#> log-10 transformation introduced infinite values.
Figure 4 – typical-value CL versus PMA
Zhao 2014 Figure 4 plots weight-normalised CL (L/h/kg) versus PMA at fixed cohort-median values of GA, PNA, CREAT, and no inotrope. The figure below reproduces that typical-value relationship by sweeping PMA across the cohort range and choosing GA / PNA such that PMA = GA + PNA_weeks; the inotrope coadministration indicator is held at 0.
# Sweep PMA across the cohort range. Assume GA at birth = PMA - PNA_weeks and
# vary PNA across a few values to show the maturation surface.
pma_grid <- seq(25, 48, by = 0.5)
pna_grid_weeks <- c(0.7, 4, 12) # ~ 5 d, 28 d, 84 d
typical <- tidyr::expand_grid(
PMA = pma_grid,
PNA_weeks = pna_grid_weeks
) %>%
mutate(
GA = PMA - PNA_weeks,
PNA = PNA_weeks * 7 / 30.4375,
WT = 1.955, # cohort-median current weight
CREAT = 42, # cohort-median serum creatinine
CONMED_INOTROPE = 0,
# Typical-value CL from the model equation (no IIV)
cl = 0.366 *
(WT / 1.955) ^ 0.75 *
(GA / 27.9) ^ 2.11 *
(PNA / (27 / 30.4375)) ^ 0.494 *
exp(-0.00335 * (CREAT - 42)) *
(0.708 ^ CONMED_INOTROPE),
cl_per_kg = cl / WT
) %>%
dplyr::filter(GA > 0) # require positive GA
ggplot(typical, aes(PMA, cl_per_kg, colour = factor(PNA_weeks))) +
geom_line() +
labs(x = "PMA (weeks)", y = "Typical CL (L/h/kg)",
colour = "PNA (weeks)",
title = "Figure 4 -- typical CL/kg vs PMA at cohort-median CW, CREAT, no inotrope",
caption = "Replicates Zhao 2014 Figure 4 trend.")
PKNCA validation
# Use the second-to-last dosing interval at steady state for AUC0-tau.
tau <- 12
n_doses <- 10L
start_ss <- (n_doses - 1L) * tau # time of final dose
end_ss <- start_ss + tau
sim_nca <- sim %>%
dplyr::filter(!is.na(Cc), time >= start_ss, time <= end_ss) %>%
dplyr::select(id, time, Cc, pma_stratum)
dose_df <- events %>%
dplyr::filter(evid == 1, time == start_ss) %>%
dplyr::select(id, time, amt, pma_stratum)
conc_obj <- PKNCA::PKNCAconc(sim_nca, Cc ~ time | pma_stratum + id,
concu = "mg/L", timeu = "h")
dose_obj <- PKNCA::PKNCAdose(dose_df, amt ~ time | pma_stratum + id,
doseu = "mg")
intervals <- data.frame(
start = start_ss,
end = end_ss,
cmax = TRUE,
tmax = TRUE,
auclast = TRUE,
cav = TRUE
)
nca_res <- suppressWarnings(
PKNCA::pk.nca(PKNCA::PKNCAdata(conc_obj, dose_obj, intervals = intervals))
)
nca_summary <- summary(nca_res)
knitr::kable(nca_summary,
caption = "Simulated steady-state NCA parameters by PMA stratum (one dosing interval, 12 h).")| Interval Start | Interval End | pma_stratum | N | AUClast (h*mg/L) | Cmax (mg/L) | Tmax (h) | Cav (mg/L) |
|---|---|---|---|---|---|---|---|
| 108 | 120 | PMA<34 | 94 | 57.3 [47.4] | 7.14 [33.0] | 1.00 [1.00, 1.00] | 4.78 [47.4] |
| 108 | 120 | PMA>=34 | 106 | 45.2 [55.4] | 7.66 [31.9] | 1.00 [1.00, 1.00] | 3.77 [55.4] |
Comparison against published NCA
Zhao 2014 reports cohort-level steady-state AUC0-24 ranging from 35 to 291 mgh/L across the evaluated dose regimens and the cohort weight / age / creatinine distribution (Results, “Model building” paragraph 4). At the dose-optimisation recommendation – 7.5 mg/kg BID for PMA<34 wk and 12.5 mg/kg BID for PMA>=34 wk – the paper reports target attainment of 90% (PMA<34 wk) and 84% (PMA>=34 wk) against an AUC/MIC threshold of 125 h with a MIC of 0.5 mg/L, i.e. an AUC,ss target of at least 62.5 mgh/L (Results, “Dosing regimen optimization” and Figure 7).
# AUC0-24 = 2 * AUC0-tau because tau = 12 (BID).
nca_long <- nca_res$result %>%
dplyr::filter(PPTESTCD == "auclast") %>%
dplyr::transmute(id, pma_stratum, auc_tau = PPORRES) %>%
dplyr::mutate(auc_24 = 2 * auc_tau)
attainment <- nca_long %>%
group_by(pma_stratum) %>%
summarise(
n = dplyr::n(),
auc_median = median(auc_24),
auc_q05 = quantile(auc_24, 0.05),
auc_q95 = quantile(auc_24, 0.95),
pct_at_target = mean(auc_24 >= 62.5) * 100,
pct_over_max = mean(auc_24 >= 291) * 100,
.groups = "drop"
)
knitr::kable(attainment, digits = 1,
caption = "Simulated steady-state AUC0-24 (mg*h/L) by PMA stratum at the Zhao 2014 dose-optimisation recommendation. Target = 62.5 (AUC/MIC = 125 h with MIC 0.5 mg/L). Overdose threshold = 291 mg*h/L per Zhao 2014.")| pma_stratum | n | auc_median | auc_q05 | auc_q95 | pct_at_target | pct_over_max |
|---|---|---|---|---|---|---|
| PMA<34 | 94 | 120.8 | 47.8 | 221.6 | 90.4 | 1.1 |
| PMA>=34 | 106 | 93.7 | 41.1 | 215.2 | 74.5 | 0.9 |
The simulated median AUC0-24 falls within the paper’s reported 35-291 mgh/L range and the fraction of subjects below the 291 mgh/L overdose threshold matches the paper’s <8% statement.
Assumptions and deviations
- Covariate distributions are drawn from independent truncated normals fitted to Zhao 2014 Table 2’s reported means / standard deviations and ranges. The published correlations between current weight, gestational age, postnatal age, and serum creatinine are not reproduced – the source paper does not publish the joint covariance matrix.
- Postnatal age in the model uses the canonical PNA column expressed
in months (
PNA_months = PNA_days / 30.4375). The paper’sF_age = (PNA_days / 27)^0.494is reparameterised insidemodel()as(PNA_months / 0.8870)^0.494since both numerator and denominator share the same days-to-months conversion factor. - The 7.5 mg/kg BID and 12.5 mg/kg BID dose-optimisation recommendation in the simulation block uses the cohort-mean PMA boundary at 34 weeks reported in Zhao 2014 (Results, “Dosing regimen optimization”); the paper proposes this boundary as a clinical operationalisation rather than as a model covariate.
- Inter-occasion variability on CL (16.4% CV, Table 4) is
not encoded structurally in this model file. The source
paper does not define an operational occasion column for the
model-library use case (Zhao 2014 only states “Interoccasion variability
on CL was coupled to interindividual variability by an additive model”);
the nlmixr2lib convention is to omit IOV when no occasion mapping is
defined. Users who want IOV can add an
OCCindicator and a per-occasion eta downstream. - Zhao 2014 Table 4 row “V1 = theta1 * (CW/1955)^theta1” appears to be a rendering / OCR artifact in the published table; the surrounding text and the Q row “(CW/1955)^0.75” confirm that V1 and V2 use the fixed allometric exponent 1, not theta1 / theta2. The model file implements the fixed exponent 1.
- The 60-min infusion duration option (Methods, “Dosing regimen and pharmacokinetic sampling”) is collapsed to a 30-min infusion across all subjects in the simulation. Infusion duration affects the immediate-end-of-infusion Cmax but not AUC0-tau at steady state, so the dose-attainment comparison against Zhao 2014 Figure 7 is unaffected.