Simulation & VPC
Overview
ferx_simulate() generates replicated datasets from the fitted model. The primary use case is the Visual Predictive Check (VPC): overlay observed data on simulation-based prediction intervals to assess model adequacy visually.
fit <- ferx_fit(ex$model, ex$data, method = "foce", covariance = TRUE,
verbose = FALSE)Mu-referencing detected for: ETA_CL, ETA_KA, ETA_V
Simulating from the fitted model
The typical VPC workflow passes fit to ferx_simulate() so that simulation uses the fitted theta, omega, and sigma rather than the model file’s initial values:
sim <- ferx_simulate(
model = ex$model,
data = ex$data,
n_sim = 500,
seed = 42,
fit = fit
)
head(sim) DRAW SIM ID TIME IPRED DV_SIM
1 1 1 1 0.5 4.392110 4.381504
2 1 1 1 1.0 7.228551 7.177091
3 1 1 1 2.0 10.200605 10.177057
4 1 1 1 4.0 11.726456 11.750829
5 1 1 1 8.0 11.342447 11.521931
6 1 1 1 12.0 10.603030 10.454153
n_sim = 500 replicates is sufficient for a standard VPC. Set seed for reproducibility.
What the simulation returns
| Column | Meaning |
|---|---|
SIM |
Replicate index (1 to n_sim) |
ID |
Subject ID (same population structure as observed data) |
TIME |
Time (matched to observation schedule in data) |
IPRED |
Individual prediction for this replicate (no residual error) |
DV_SIM |
Simulated observation (IPRED + residual noise) |
To propagate parameter uncertainty across draws, use ferx_simulate_with_uncertainty(), which adds a DRAW column indexing the population-parameter draw — see Overview.
Simulating at initial values (without a fit)
Omit fit to simulate at the initial estimates in the model file. Useful for a prior predictive check:
sim_prior <- ferx_simulate(ex$model, ex$data, n_sim = 200, seed = 1)Propensity-score-matched simulation (RWD / pmVPC)
VPCs built from real-world data (RWD) can be biased by treatment adaptation: a subject’s observed dosing and sampling design is often a response to that subject’s own disposition. For example, high-clearance patients may be given longer dosing intervals. A naïve simulation draws etas independently of the design, so the simulated and observed populations no longer share the design–disposition coupling, and the VPC misleads.
The match = TRUE argument to ferx_simulate() addresses this. For each replicate, the drawn etas are reassigned to subjects by optimal Mahalanobis matching (under the model omega) against the subjects’ fitted (posthoc) etas. Each subject’s observed dosing/sampling design is thereby paired with a similar drawn eta, restoring the design–disposition coupling and producing a propensity-matched VPC (pmVPC). This requires data to be real observed data — every subject must have observations so its posthoc eta can be computed. When a fit is supplied, the posthoc etas are computed at the fitted parameters; otherwise at the model file’s initial values.
sim_pm <- ferx_simulate(
model = ex$model,
data = ex$data,
n_sim = 500,
seed = 42,
fit = fit,
match = TRUE
)The returned columns are identical to the unmatched call (SIM, ID, TIME, IPRED, DV_SIM); feed sim_pm into the same VPC construction below.
Building a VPC
Using the vpc package
(The vpc package is an optional dependency; install with install.packages("vpc").)
Population predictions
ferx_predict() computes population predictions (ETA = 0) without residual noise. Useful for overlaying the typical profile on observed data:
preds <- ferx_predict(ex$model, ex$data, fit = fit)
head(preds) ID TIME PRED
1 1 0.5 3.917754
2 1 1.0 6.609725
3 1 2.0 9.695979
4 1 4.0 11.639355
5 1 8.0 11.504506
6 1 12.0 10.775094
ferx_predict() returns a data frame with ID, TIME, and PRED (population prediction at ETA = 0). For uncertainty-propagated predictions, see ferx_simulate_with_uncertainty() in Overview.
[simulation] block
For CLI-driven simulation without an external dataset, the .ferx model file can embed a trial design via the [simulation] block. This is a DSL feature rather than an R workflow — see the Model file reference in the ferx-core book for syntax and usage.