Inter-Occasion Variability (IOV)
Inter-Occasion Variability (IOV) models the fact that a subject’s PK parameters may shift between occasions (study periods, visits, dosing intervals). Unlike between-subject variability (BSV), which is fixed for a subject across the whole study, IOV is a random effect that is re-drawn independently for each occasion.
Concepts
An occasion is a distinct time window during which the same random effect applies. Occasions are identified by an integer OCC column in the dataset (any column name may be used; configure it via iov_column).
A kappa (κ) is the IOV random effect, analogous to eta (η) for BSV. Each kappa is drawn independently per occasion:
\[\kappa_{ik} \sim \mathcal{N}(0, \Omega_\text{IOV})\]
where \(i\) indexes subjects and \(k\) indexes occasions.
DSL syntax
Diagonal IOV (independent kappas)
kappa NAME ~ value # value is a variance (default)
kappa NAME ~ value (sd) # value is a standard deviation
kappa NAME ~ value FIX # hold fixed during estimation
Each kappa line adds one diagonal element to \(\Omega_\text{IOV}\). Occasions are independent across kappas.
kappa KAPPA_CL ~ 0.05
kappa KAPPA_V ~ 0.03
Mixing diagonal and block
kappa and block_kappa can be freely combined:
block_kappa (KAPPA_CL, KAPPA_V) = [0.05, 0.01, 0.03]
kappa KAPPA_KA ~ 0.10
A name may not appear in both kappa and block_kappa — this is a parse error.
Wiring kappas into individual parameters
Reference kappa names exactly like BSV etas:
[individual_parameters]
CL = TVCL * exp(ETA_CL + KAPPA_CL)
V = TVV * exp(ETA_V + KAPPA_V)
KA = TVKA * exp(ETA_KA) # no IOV on absorption
At each occasion \(k\), the effective individual CL is \(\text{TVCL} \cdot \exp(\eta_\text{CL} + \kappa_{\text{CL},ik})\). The BSV eta captures stable between-subject differences; the kappa captures occasion-to-occasion fluctuation within a subject.
Fit options
Set iov_column to the name of the occasion column in the dataset:
[fit_options]
method = focei
iov_column = OCC
covariance = true
Dataset format
ID,TIME,DV,EVID,AMT,CMT,MDV,OCC
1,0,.,1,100,1,1,1
1,1,9.49,0,.,.,0,1
1,24,.,1,100,1,1,2
1,25,10.1,0,.,.,0,2
Dose and observation rows in the same period share the same OCC value. Occasion indices can be any positive integers and do not need to be consecutive.
Interpreting output
print(fit) gains an OMEGA_IOV (inter-occasion variability) section after the standard omega block. For a block_kappa with off-diagonal correlations, a correlations sub-block follows.
Shrinkage for kappa parameters is reported at two levels of detail:
fit$shrinkage_kappa— pooled shrinkage (named numeric vector, one value per kappa parameter)fit$shrinkage_kappa_by_occ— per-occasion shrinkage (data frame with columnoccand one column per kappa)
fit$shrinkage_kappa
# KAPPA_CL
# 0.167
fit$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 kappa indicates the data cannot reliably estimate per-occasion random effects for that parameter.
Per-occasion kappa EBEs are available in fit$ebe_kappas (a data frame with columns ID, OCC, and one column per kappa parameter).
Estimation notes
- SAEM fully supports IOV. A
c("saem", "focei")chain is the most robust workflow: SAEM finds the basin, FOCEI polishes to the marginal minimum. - The inner optimizer jointly solves all BSV etas and all per-occasion kappas simultaneously (no separate kappa solve step).
- The outer gradient for IOV models uses reconverged finite differences to correctly identify the IOV variance parameters. This costs more per outer iteration than the fixed-EBE gradient used for BSV-only models.
- The most robust workflow for IOV models is a SAEM → FOCEI chain: SAEM finds the basin, FOCEI polishes to the marginal minimum.
Complete example
[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
omega ETA_V ~ 0.04
omega ETA_KA ~ 0.30
kappa KAPPA_CL ~ 0.05
sigma PROP_ERR ~ 0.02
[individual_parameters]
CL = TVCL * exp(ETA_CL + KAPPA_CL)
V = TVV * exp(ETA_V)
KA = TVKA * exp(ETA_KA)
[structural_model]
pk one_cpt_oral(cl=CL, v=V, ka=KA)
[error_model]
DV ~ proportional(PROP_ERR)
[fit_options]
method = focei
iov_column = OCC
covariance = true
See also
- Example: IOV — worked example with R code
- Parameters — Kappa
- IOV (ferx-core book)