Inter-Occasion Variability
Overview
Inter-occasion variability (IOV) captures variability in PK parameters that changes between dosing occasions within the same subject — for example, day 1 vs day 7 clearance after a multi-dose study.
In the ferx DSL, IOV is expressed with the kappa keyword. Kappas are analogous to ETAs, but they are re-drawn for each occasion rather than being fixed per subject.
The individual parameter on occasion \(k\) for subject \(i\):
\[CL_{ik} = \text{TVCL} \times \exp(\eta_i^{CL} + \kappa_{ik}^{CL})\]
where \(\eta_i^{CL} \sim N(0, \omega_{CL}^2)\) is the between-subject component (constant across occasions) and \(\kappa_{ik}^{CL} \sim N(0, \omega_{IOV}^2)\) is the occasion-specific component.
Dataset requirements
Add an OCC column (integer occasion index per row). Convention: OCC = 1 for the first occasion, OCC = 2 for the second, etc.
ID TIME DV EVID AMT OCC
1 0.0 NA 1 70 1
1 1.0 5.2 0 0 1
...
1 24.0 NA 1 70 2 <- second dose, new occasion
1 25.0 4.8 0 0 2
The kappa keyword (diagonal IOV)
Declare IOV parameters with kappa in [parameters]:
[parameters]
theta TVCL(0.2, 0.001, 10.0)
theta TVV(10.0, 0.1, 500.0)
theta TVKA(1.5, 0.01, 50.0)
omega ETA_CL ~ 0.09 # between-subject variance (constant per subject)
omega ETA_V ~ 0.04
omega ETA_KA ~ 0.30
kappa KAPPA_CL ~ 0.01 # IOV variance (re-drawn each occasion)
sigma PROP_ERR ~ 0.02
Reference KAPPA_CL in [individual_parameters] just like an ETA:
[individual_parameters]
CL = TVCL * exp(ETA_CL + KAPPA_CL)
V = TVV * exp(ETA_V)
KA = TVKA * exp(ETA_KA)
Enable the IOV column in [fit_options]:
[fit_options]
method = foce
iov_column = OCC
covariance = false
Fitting an IOV model
ferx ships two bundled IOV examples:
| Example | Method | Notes |
|---|---|---|
warfarin_iov |
FOCE | Diagonal kappa on CL |
warfarin_iov_saem |
SAEM | Same structural model fit with SAEM |
ex_iov <- ferx_example("warfarin_iov")
fit_iov <- ferx_fit(ex_iov$model, ex_iov$data, method = "foce",
verbose = FALSE)Mu-referencing detected for: ETA_CL, ETA_KA, ETA_V
The printed fit shows a dedicated OMEGA_IOV (inter-occasion variability) section with per-kappa CV%, SE, and shrinkage, followed by per-occasion shrinkage in a --- Shrinkage by occasion --- sub-table:
print(fit_iov)============================================================
NONLINEAR MIXED EFFECTS MODEL ESTIMATION
============================================================
Model: warfarin_iov Dataset: warfarin_iov
Method: FOCE | Gradient: FD | Subjects: 10 | Obs: 220
STATUS: CONVERGED 314 iterations 9.4s
OFV: 263.3865 AIC: 279.3865 BIC: 306.5355
MODEL STRUCTURE (auto-derived)
------------------------------------------------------------
Structural: 1-cpt oral (TVCL, TVV, TVKA)
IIV: ETA_CL, ETA_V, ETA_KA
IOV: KAPPA_CL
Residual: proportional
THETA
------------------------------------------------------------
Parameter Estimate SE %RSE
----------------------------------------------------
TVCL 0.237869 0.018501 7.8
TVV 8.609892 0.390722 4.5
TVKA 3.144902 0.923031 29.4
OMEGA (between-subject variability)
------------------------------------------------------------
ETA_CL [log-normal] = 0.165782 CV% = 42.5 SE = 0.104478
ETA_V [log-normal] = 0.013723 CV% = 11.8 SE = 0.007995
ETA_KA [log-normal] = 1.302141 CV% = 163.6 SE = 0.924616
OMEGA_IOV (inter-occasion variability)
------------------------------------------------------------
KAPPA_CL = 0.063194 (CV% = 25.5) SE = 0.029893 Shrinkage = 35.5%
--- Shrinkage by occasion ---
Occasion 1: KAPPA_CL 21.5%
Occasion 2: KAPPA_CL 53.5%
SIGMA (residual error)
------------------------------------------------------------
PROP_ERR [proportional] = 0.175093 (var = 0.030658, CV% = 17.5) SE = 0.016939 [initial specified as SD]
SHRINKAGE
------------------------------------------------------------
ETA_CL: 14.5% ETA_V: 21.0% ETA_KA: 14.5% EPS: 2.1%
DIAGNOSTICS
------------------------------------------------------------
Covariance: computed Cond: 19.1 DW: 0.50 [positive autocorrelation] IWRES lag-1 r: 0.738
RUN INFO
------------------------------------------------------------
Gradient (requested): auto (used: fd)
ferx v0.1.6 (core v0.1.6)
SETTINGS (model file / call-time override)
------------------------------------------------------------
method foce [model only]
iov_column OCC [model only]
covariance false [model only]
------------------------------------------------------------
1 warning 1 info -- call ferx_warnings(fit) for details
============================================================
The kappa omega is stored separately from fit_iov$omega:
fit_iov$model_structure$iov # names of kappa parameters[1] "KAPPA_CL"
fit_iov$shrinkage_kappa # per-kappa shrinkage (pooled across occasions) KAPPA_CL
0.3549592
fit_iov$shrinkage_kappa_by_occ # per-occasion shrinkage data frame occ KAPPA_CL
1 1 0.2150276
2 2 0.5352706
shrinkage_kappa_by_occ is a data frame with one row per occasion and one column per kappa parameter. The occ column holds a 1-based occasion index:
# Print the per-occasion shrinkage table
fit_iov$shrinkage_kappa_by_occ
# occ KAPPA_CL
# 1 1 0.182
# 2 2 0.153
# (values are illustrative; run the model to get exact numbers)High shrinkage (> 30%) on a particular occasion indicates that the data for that occasion are too sparse to estimate per-occasion kappa EBEs reliably. If shrinkage is high on all occasions, consider removing IOV from that parameter or using a sparser model (fewer kappas).
SAEM with IOV
warfarin_iov_saem uses the same DSL with method = saem in [fit_options]. SAEM estimates kappa parameters directly — no FOCE pre-fit is required:
ex_saem <- ferx_example("warfarin_iov_saem")
fit_saem <- ferx_fit(ex_saem$model, ex_saem$data)Interpreting IOV results
Partitioning variability
The total clearance variance (on the log scale) is:
\[\text{Var}(\log CL_i) = \omega_{CL}^2 + \omega_{IOV}^2\]
The fraction of total variability attributable to IOV:
IOV shrinkage
Two shrinkage summaries are available after fitting:
-
fit$shrinkage_kappa— pooled shrinkage (scalar per kappa parameter) -
fit$shrinkage_kappa_by_occ— per-occasion shrinkage data frame (one row per occasion, one column per kappa)
High shrinkage (> 30%) means the data cannot reliably estimate per-occasion kappas — consider removing IOV from that parameter. The per-occasion table is especially useful when occasions differ in sampling density: an early rich-sampling occasion may have low shrinkage while a later sparse occasion has high shrinkage, pointing to where the IOV is not supported by the data.
When to add IOV
Add IOV when:
- The study has multiple distinct dosing occasions with washout between them
- You see residual correlation in ETA-vs-time plots that suggests within-subject variation across occasions
- A model comparison (OFV difference) shows significant improvement with IOV included
Do not add IOV to studies with sparse sampling where the data cannot support additional random effects.