MI-210 Essentials of Population PKPD M&S — Pumas Edition
Author
Adapted from Marc R. Gastonguay, Ph.D. (Metrum Institute)
Published
April 18, 2026
1 Overview
Model qualification (or evaluation) methods help assess how well a model describes the observed data and whether it is suitable for its intended purpose:
Assumption Checking
Test Data Sets
Log-Likelihood Profile
Bootstrap
Leverage Analysis
Predictive Performance (VPC)
Posterior Predictive Check
2 A Risk-Based Approach to Model Qualification
The level of qualification should match the intended use of the model
Exploratory models require less rigorous qualification than models used for regulatory decision-making
All models should pass basic assumption checks and diagnostic evaluation
3 Model Qualification Methods
3.1 Assumption Checking
Distributional assumptions on random effects (ETAs should be approximately normal)
Residual error assumptions (CWRES should be approximately N(0,1))
Structural model assumptions (systematic trends in residuals indicate misspecification)
Interpreting Diagnostic Plots: What Each Panel Reveals
Standard goodness-of-fit diagnostics each target a specific aspect of model adequacy:
DV vs PRED — Assesses population-level structural fit. Systematic deviations from the line of identity indicate structural model misspecification (e.g., wrong number of compartments or incorrect absorption model).
DV vs IPRED — Assesses individual-level fit after incorporating empirical Bayes estimates. Scatter should be tighter than DV vs PRED; if not, the random effects structure may be inadequate.
CWRES vs PRED — Evaluates residual error model adequacy. A fan-shaped (heteroscedastic) pattern suggests proportional error is needed; a U-shaped trend suggests structural misspecification persists even after accounting for random effects.
CWRES vs TIME — Detects time-dependent model misspecification, such as missing absorption lag time, autoinduction, or time-varying clearance.
If the model is correctly specified, CWRES should be approximately \(N(0,1)\) with no systematic trends. Deviations from this expectation guide targeted model refinement.
3.2 Bootstrap: Qualification of Parameter Estimates
Bootstrap vs. Asymptotic Standard Errors
Asymptotic standard errors derived from the Fisher information matrix assume that the likelihood surface is approximately quadratic (i.e., the parameter estimates are normally distributed) near the minimum. This assumption can fail for small datasets, when variance parameters are estimated near their boundary (e.g., \(\omega^2 \approx 0\)), or when the likelihood surface is flat or irregular. In such cases, asymptotic confidence intervals may be misleading. Bootstrap resampling makes no distributional assumptions: by repeatedly resampling subjects with replacement and re-estimating the model, it constructs empirical confidence intervals that reflect the actual sampling distribution of the estimator. However, bootstrap is not without limitations — if the convergence rate across resamples falls below approximately 80%, this signals model instability or overparameterization, and the bootstrap results themselves become unreliable.
Bootstrap provides non-parametric confidence intervals for parameter estimates by resampling subjects with replacement.
3.2.1 Base PK Model
The book uses a 1-compartment IV model with combined error (ADVAN1 TRANS2):
# 1-cpt IV model with BLOCK(2) OMEGA and combined error# From 501.ctl: ADVAN1 TRANS2, Y=F + F*ERR(1) + ERR(2)pk_model =@modelbegin@metadatabegin desc ="1-Cpt IV PopPK (Bootstrap Base Model)"end@parambegin tvCL ∈RealDomain(lower =0.0, init =13.0) tvV ∈RealDomain(lower =0.0, init =75.0) Ω ∈PSDDomain(2) σ_prop ∈RealDomain(lower =0.0, init =0.2) σ_add ∈RealDomain(lower =0.0, init =1.0)end@randombegin η ~MvNormal(Ω)end@covariates WT CLCR SEX AGE HT@prebegin CL = tvCL *exp(η[1]) Vc = tvV *exp(η[2])end@dynamics Central1@derivedbegin cp := @. Central / Vc dv ~ @. Normal(cp, sqrt((cp * σ_prop)^2+ σ_add^2))endend
┌ Warning: Covariates WT, CLCR, SEX, AGE and HT are not used in the model.
└ @ Pumas ~/.julia/packages/Pumas/GZeMg/src/dsl/model_macro.jl:3399
PumasModel
Parameters: tvCL, tvV, Ω, σ_prop, σ_add
Random effects: η
Covariates: WT, CLCR, SEX, AGE, HT
Dynamical system variables: Central
Dynamical system type: Closed form
Derived: dv
Observed: dv
In Pumas, bootstrap is performed via infer(fit, Bootstrap()):
# Bootstrap with 200 replicates (use more for production — e.g., 1000)boot_result =infer(base_fit, Pumas.Bootstrap(samples =200))boot_result
[ Info: Bootstrap inference finished.
Bootstrap inference results
Dynamical system type: Closed form
Number of subjects: 40
Observation records: Active Missing
dv: 560 0
Total: 560 0
Number of parameters: Constant Optimized
0 7
Likelihood approximation: FOCE
Likelihood optimizer: BFGS
Termination Reason: GradientNorm
Log-likelihood value: -679.2196
------------------------------------------------------------
Estimate SE 95.0% C.I.
------------------------------------------------------------
tvCL 11.806 0.48494 [ 10.889 ; 12.684 ]
tvV 84.841 3.5461 [ 78.503 ; 92.273 ]
Ω₁,₁ 0.05785 0.013835 [ 0.032432 ; 0.0842 ]
Ω₂,₁ 0.011617 0.0090141 [ -0.0059066; 0.026267 ]
Ω₂,₂ 0.061883 0.012881 [ 0.035084 ; 0.082688 ]
σ_prop 0.20242 0.0072407 [ 0.1903 ; 0.21753 ]
σ_add 0.0028996 0.0010607 [ 1.1109e-5; 0.0049531]
------------------------------------------------------------
Unique resampled populations: 200 out of 200
No stratification.
Note
In NONMEM, bootstrap requires external tools (PsN, metrumrg) to resample datasets and re-run the model hundreds of times. In Pumas, infer(fit, Bootstrap()) handles everything in a single call.
3.3 Visual Predictive Check (VPC)
VPC compares the distribution of observed data to simulated data from the model. It assesses whether the model can reproduce the key features of the observed data.
In NONMEM, VPC requires $SIMULATION and post-processing with R/PsN. In Pumas, use vpc() and vpc_plot():
vpc_result =vpc(base_fit, 200) # 200 simulations
[ Info: Continuous VPC
Visual Predictive Check
Type of VPC: Continuous VPC
Simulated populations: 200
Subjects in data: 40
Stratification variable(s): None
Confidence level: 0.95
VPC lines: quantiles ([0.1, 0.5, 0.9])
vpc_plot(vpc_result)
Figure 1: Visual Predictive Check
3.4 Log-Likelihood Profile
Log-likelihood profiling provides confidence intervals for individual parameters by fixing one parameter at a range of values and re-estimating the rest:
# Profile tvCL over a range around the estimate# (computationally intensive — commented for rendering speed)# cl_range = range(coef(base_fit).tvCL * 0.8, coef(base_fit).tvCL * 1.2, length = 20)# profiles = [fit(pk_model, pop, merge(coef(base_fit), (tvCL = cl,)), FOCEI();# constantcoef = (tvCL = cl,)) for cl in cl_range]# ll_values = loglikelihood.(profiles)
3.5 Diagnostics Summary
insp =inspect(base_fit)insp_df =DataFrame(insp)obs =@rsubset(insp_df, !ismissing(:dv))fig =Figure(size = (800, 600))ax1 =Axis(fig[1, 1], xlabel ="PRED", ylabel ="DV", title ="DV vs PRED")scatter!(ax1, obs.dv_pred, obs.dv, color =:navy, markersize =4, alpha =0.5)ablines!(ax1, 0, 1, color =:black)ax2 =Axis(fig[1, 2], xlabel ="IPRED", ylabel ="DV", title ="DV vs IPRED")scatter!(ax2, obs.dv_ipred, obs.dv, color =:navy, markersize =4, alpha =0.5)ablines!(ax2, 0, 1, color =:black)ax3 =Axis(fig[2, 1], xlabel ="PRED", ylabel ="CWRES", title ="CWRES vs PRED")scatter!(ax3, obs.dv_pred, obs.dv_wres, color =:navy, markersize =4, alpha =0.5)hlines!(ax3, 0, color =:black)ax4 =Axis(fig[2, 2], xlabel ="Time (hr)", ylabel ="CWRES", title ="CWRES vs TIME")scatter!(ax4, obs.time, obs.dv_wres, color =:navy, markersize =4, alpha =0.5)hlines!(ax4, 0, color =:black)fig
---title: "Chapter 6: Model Qualification"subtitle: "MI-210 Essentials of Population PKPD M&S — Pumas Edition"author: "Adapted from Marc R. Gastonguay, Ph.D. (Metrum Institute)"date: todayformat: html: toc: true toc-depth: 3 number-sections: true code-fold: false fig-width: 8 fig-height: 5execute: warning: false error: falseengine: julia---```{julia}#| label: setup#| echo: falseusingPumasusingPumasUtilitiesusingDataFramesMetausingCSVusingCairoMakieusingAlgebraOfGraphicsusingStatisticsusingLinearAlgebradata_dir =joinpath(@__DIR__, "../data")set_aog_theme!()```# OverviewModel qualification (or evaluation) methods help assess how well a model describes the observed data and whether it is suitable for its intended purpose:- Assumption Checking- Test Data Sets- Log-Likelihood Profile- Bootstrap- Leverage Analysis- Predictive Performance (VPC)- Posterior Predictive Check# A Risk-Based Approach to Model Qualification- The level of qualification should match the intended use of the model- Exploratory models require less rigorous qualification than models used for regulatory decision-making- All models should pass basic assumption checks and diagnostic evaluation# Model Qualification Methods## Assumption Checking- Distributional assumptions on random effects (ETAs should be approximately normal)- Residual error assumptions (CWRES should be approximately N(0,1))- Structural model assumptions (systematic trends in residuals indicate misspecification)::: {.callout-note title="Interpreting Diagnostic Plots: What Each Panel Reveals"}Standard goodness-of-fit diagnostics each target a specific aspect of model adequacy:1. **DV vs PRED** — Assesses population-level structural fit. Systematic deviations from the line of identity indicate structural model misspecification (e.g., wrong number of compartments or incorrect absorption model).2. **DV vs IPRED** — Assesses individual-level fit after incorporating empirical Bayes estimates. Scatter should be tighter than DV vs PRED; if not, the random effects structure may be inadequate.3. **CWRES vs PRED** — Evaluates residual error model adequacy. A fan-shaped (heteroscedastic) pattern suggests proportional error is needed; a U-shaped trend suggests structural misspecification persists even after accounting for random effects.4. **CWRES vs TIME** — Detects time-dependent model misspecification, such as missing absorption lag time, autoinduction, or time-varying clearance.If the model is correctly specified, CWRES should be approximately $N(0,1)$ with no systematic trends. Deviations from this expectation guide targeted model refinement.:::## Bootstrap: Qualification of Parameter Estimates::: {.callout-note title="Bootstrap vs. Asymptotic Standard Errors"}Asymptotic standard errors derived from the Fisher information matrix assume that the likelihood surface is approximately **quadratic** (i.e., the parameter estimates are normally distributed) near the minimum. This assumption can fail for small datasets, when variance parameters are estimated near their boundary (e.g., $\omega^2 \approx 0$), or when the likelihood surface is flat or irregular. In such cases, asymptotic confidence intervals may be misleading. **Bootstrap resampling** makes no distributional assumptions: by repeatedly resampling subjects with replacement and re-estimating the model, it constructs empirical confidence intervals that reflect the actual sampling distribution of the estimator. However, bootstrap is not without limitations — if the convergence rate across resamples falls below approximately 80%, this signals model instability or overparameterization, and the bootstrap results themselves become unreliable.:::Bootstrap provides non-parametric confidence intervals for parameter estimates by resampling subjects with replacement.### Base PK ModelThe book uses a 1-compartment IV model with combined error (ADVAN1 TRANS2):```{julia}#| label: ch6-datapk_df = CSV.read(joinpath(data_dir, "prob_5_1.csv"), DataFrame)rename!(pk_df,:ID =>:id, :DV =>:dv, :AMT =>:amt, :TIME =>:time,:II =>:ii, :ADDL =>:addl, :RATE =>:rate,)# Prepare for Pumaspk_df.evid =ifelse.(pk_df.amt .>0, 1, 0)pk_df.cmt =fill(1, nrow(pk_df))pk_df.dv =ifelse.(pk_df.evid .==1, missing, pk_df.dv)pop =read_pumas(pk_df; covariates = [:HT, :WT, :CLCR, :SEX, :AGE])println("Subjects: ", length(pop))``````{julia}#| label: ch6-model# 1-cpt IV model with BLOCK(2) OMEGA and combined error# From 501.ctl: ADVAN1 TRANS2, Y=F + F*ERR(1) + ERR(2)pk_model =@modelbegin@metadatabegin desc ="1-Cpt IV PopPK (Bootstrap Base Model)"end@parambegin tvCL ∈RealDomain(lower =0.0, init =13.0) tvV ∈RealDomain(lower =0.0, init =75.0) Ω ∈PSDDomain(2) σ_prop ∈RealDomain(lower =0.0, init =0.2) σ_add ∈RealDomain(lower =0.0, init =1.0)end@randombegin η ~MvNormal(Ω)end@covariates WT CLCR SEX AGE HT@prebegin CL = tvCL *exp(η[1]) Vc = tvV *exp(η[2])end@dynamics Central1@derivedbegin cp := @. Central / Vc dv ~ @. Normal(cp, sqrt((cp * σ_prop)^2+ σ_add^2))endend``````{julia}#| label: ch6-fitinit_params = ( tvCL =13.0, tvV =75.0, Ω = [0.040.02; 0.020.04], σ_prop =0.2, σ_add =1.0,)base_fit =fit(pk_model, pop, init_params, Pumas.FOCEI())base_fit``````{julia}#| label: ch6-inferbase_infer =infer(base_fit)base_infer```### Bootstrap AnalysisIn Pumas, bootstrap is performed via `infer(fit, Bootstrap())`:```{julia}#| label: ch6-bootstrap# Bootstrap with 200 replicates (use more for production — e.g., 1000)boot_result =infer(base_fit, Pumas.Bootstrap(samples =200))boot_result```::: {.callout-note}In NONMEM, bootstrap requires external tools (PsN, metrumrg) to resample datasets and re-run the model hundreds of times. In Pumas, `infer(fit, Bootstrap())` handles everything in a single call.:::## Visual Predictive Check (VPC)VPC compares the distribution of observed data to simulated data from the model. It assesses whether the model can reproduce the key features of the observed data.In NONMEM, VPC requires `$SIMULATION` and post-processing with R/PsN. In Pumas, use `vpc()` and `vpc_plot()`:```{julia}#| label: ch6-vpcvpc_result =vpc(base_fit, 200) # 200 simulations``````{julia}#| label: fig-ch6-vpc#| fig-cap: "Visual Predictive Check"vpc_plot(vpc_result)```## Log-Likelihood ProfileLog-likelihood profiling provides confidence intervals for individual parameters by fixing one parameter at a range of values and re-estimating the rest:```{julia}#| label: ch6-ll-profile#| eval: false# Profile tvCL over a range around the estimate# (computationally intensive — commented for rendering speed)# cl_range = range(coef(base_fit).tvCL * 0.8, coef(base_fit).tvCL * 1.2, length = 20)# profiles = [fit(pk_model, pop, merge(coef(base_fit), (tvCL = cl,)), FOCEI();# constantcoef = (tvCL = cl,)) for cl in cl_range]# ll_values = loglikelihood.(profiles)```## Diagnostics Summary```{julia}#| label: fig-ch6-gof#| fig-cap: "GOF Diagnostic Plots"insp =inspect(base_fit)insp_df =DataFrame(insp)obs =@rsubset(insp_df, !ismissing(:dv))fig =Figure(size = (800, 600))ax1 =Axis(fig[1, 1], xlabel ="PRED", ylabel ="DV", title ="DV vs PRED")scatter!(ax1, obs.dv_pred, obs.dv, color =:navy, markersize =4, alpha =0.5)ablines!(ax1, 0, 1, color =:black)ax2 =Axis(fig[1, 2], xlabel ="IPRED", ylabel ="DV", title ="DV vs IPRED")scatter!(ax2, obs.dv_ipred, obs.dv, color =:navy, markersize =4, alpha =0.5)ablines!(ax2, 0, 1, color =:black)ax3 =Axis(fig[2, 1], xlabel ="PRED", ylabel ="CWRES", title ="CWRES vs PRED")scatter!(ax3, obs.dv_pred, obs.dv_wres, color =:navy, markersize =4, alpha =0.5)hlines!(ax3, 0, color =:black)ax4 =Axis(fig[2, 2], xlabel ="Time (hr)", ylabel ="CWRES", title ="CWRES vs TIME")scatter!(ax4, obs.time, obs.dv_wres, color =:navy, markersize =4, alpha =0.5)hlines!(ax4, 0, color =:black)fig```# Sensitivity Analysis- Evaluate the impact of model assumptions and data exclusion on conclusions- Re-estimate model with subsets of data removed (e.g., influential subjects)- Compare results when assumptions are relaxed (e.g., different error models)# EDA-Driven Model SelectionBefore evaluating a model's adequacy, the right model structure must be selected. Exploratory data analysis provides the first line of evidence:## Hysteresis DetectionA concentration-effect (CE) plot reveals whether the response is in equilibrium with plasma concentrations:| CE Plot Pattern | Interpretation | Model Implication ||-----------------|---------------|-------------------|| No loop (single curve) | Equilibrium — effect tracks concentration | **Direct response** (Emax, sigmoid Emax) || Counter-clockwise loop | Effect lags behind concentration | **Effect compartment** (ke0 delay) || Clockwise loop | Tolerance, sensitization, or indirect mechanism | **Indirect response** (IDR Types I–IV) or tolerance model |::: {.callout-tip title="Systematic Model Selection Framework"}1. **Exploratory Data Analysis** — Plot effect vs. time, concentration-effect loops, identify temporal patterns2. **Mechanism-Based Selection** — Match drug pharmacology to model structure: - Receptor binding → Direct or effect compartment - Enzyme inhibition → IDR Type I or II - Signal transduction cascade → IDR with transit or effect compartment - Covalent binding → IDR Type IV or K-PD3. **Statistical Comparison** — Among mechanistically plausible candidates, use AIC/BIC and GOF to select the best fit4. **Qualification** — Bootstrap, VPC, sensitivity analysis for the selected model:::## Multi-Model ComparisonWhen comparing more than two candidate models:```{julia}#| label: ch6-multi-compare#| eval: false# Compare multiple models systematicallyfits = [fit1, fit2, fit3]for (i, f) inenumerate(fits)println("Model $i — AIC: ", round(aic(f), digits=1)," BIC: ", round(bic(f), digits=1)," -2LL: ", round(-2*loglikelihood(f), digits=1))end# Or use metrics_table for side-by-side comparisonmetrics_table(fit1, fit2, fit3)# LRT for nested pairs onlylrtest(fit1, fit2) # only valid when fit1 is nested within fit2```# Study Guide Questions1. What are the key differences between model evaluation and model qualification?2. When would you use a bootstrap analysis instead of asymptotic standard errors?3. What does a VPC tell you that GOF plots do not?4. When is model qualification less important?5. What are the limitations of the likelihood ratio test for model comparison?# Supplementary Material| Topic | Tutorial | Key Additions ||-------|----------|---------------|| **Lecture: Graphical Diagnostics** |[PKPD W6](../lectures/pkpd/W6-graphical-diagnostics-and-residual-analysis.qmd)| DV vs PRED/IPRED interpretation, CWRES patterns, time-dependent misspecification || **Lecture: Residual Diagnostics & Error Models** |[PKPD W7](../lectures/pkpd/W7-residual-diagnostics-and-error-model-specification.qmd)| Additive vs proportional vs combined error, residual analysis methodology || **Lecture: Base Model & Likelihood Comparison** |[PKPD W5](../lectures/pkpd/W5-base-model-diagnostics-and-likelihood-comparison.qmd)| -2LL, LRT, AIC/BIC theory, model comparison workflow || PD model selection framework |[PD Model Selection](https://tutorials.pumas.ai/html/PDModels/05-model-selection.html)| EDA → mechanism → statistics workflow, hysteresis detection, warfarin case study || Bayesian model comparison |[Bayesian Model Comparison](https://tutorials.pumas.ai/html/bayesian/05-model_comparison.html)| WAIC, LOO-CV, Bayes factors for non-nested models || VPC customization |[Continuous VPC](https://tutorials.pumas.ai/html/LearningPaths/04-LP/11-Module/ContinuousVPC.html)| Stratified VPC, prediction-corrected VPC, log-scale |