Automatic model development (AMD)
Description
Runs the whole model-development pipeline - Pharmpy’s amd - over one model and one search space: the structural model, the variability structure, the residual-error model, inter-occasion variability, allometric scaling and the covariate model, each decided by the tool that decides it ([ferx_modelsearch](ferx_modelsearch.qmd), [ferx_iivsearch](ferx_iivsearch.qmd), [ferx_ruvsearch](ferx_ruvsearch.qmd), [ferx_iovsearch](ferx_iovsearch.qmd), [ferx_allometry](ferx_allometry.qmd), [ferx_covsearch](ferx_covsearch.qmd)).
Usage
ferx_amd(
model = NULL,
data = NULL,
search_space = NULL,
config = NULL,
strategy = NULL,
retries_on = NULL,
skip = NULL,
rank = NULL,
cutoff = NULL,
threads = NULL,
retries = NULL,
directory = NULL,
resume = FALSE,
progress = interactive()
)
# S3 method for ferx_amd
print(x, digits = 4, ...)
# S3 method for ferx_amd
summary(object, digits = 4, ...)Arguments
model: Path to a.ferxmodel, or aferx_modelobject. Omit whenconfigis given.data: Path to the dataset. Defaults to the model’s[data]block. Names the dataset the pipeline runs on, so likemodelit cannot be given besideconfig.search_space: MFL search space, as a string or a character vector of lines. Required in the inline form.config: Path to a.ferxsearchfile. Mutually exclusive with the arguments that state the search.strategy: Step order:"default","reevaluation","SIR","SRI"or"RSI".NULLkeeps the engine default ("default").retries_on: Which selected models get the perturbed-restart pass:"all_final","final"or"skip".NULLkeeps the engine default ("all_final").skip: Steps left out of the pipeline, any of"structural","iivsearch","residual","iovsearch","allometry","covariates". A step the space says nothing about is skipped anyway; this is for one the space does describe.rank: The[rank] typethe ranking steps use, e.g."bic"or"ofv".NULLkeeps each tool’s own default, which is a BIC.cutoff: The[rank] cutoff.NULLkeeps the default.threads: Total worker threads.NULLlets the runner choose.retries: Perturbed restarts per candidate on top of the fit from the exact initials.NULLkeeps the engine default.directory: Where the per-step directories,steps.csv,candidates.csvandfinal.ferxare written.NULLruns the pipeline in a temporary directory that is removed when the call returns - the tables come back on the object either way, but nothing is left to read afterwards and the run cannot be resumed.resume: Reuse the fits already journalled indirectory.progress: Print the engine’s step progress to the console.x: Aferx_amdobject.digits: Significant digits for the printed tables....: Ignored.object: Aferx_amdobject.
Details
Every step starts from the model the previous step selected, seeded with its estimates, so a step never re-derives what the one before it decided. One search space describes them all: the engine partitions it by statement kind and hands each tool only the statements it can read (ABSORPTION / PERIPHERALS / LAGTIME to the structural step, IIV / COVARIANCE(IIV, ...) to the variability step, IOV to the occasion step, ALLOMETRY to the scaling step, COVARIATE to the covariate step). A step the space says nothing about is skipped, and the step table says so in as many words. A [rank] criterion is narrowed the same way: the two steps that select by a likelihood-ratio test (ruvsearch, covsearch) keep their own p-values, and the steps that rank candidates get the criterion.
The report is the product
A pipeline that shows only its final model cannot be audited: a step whose winner beat its siblings because they stalled reads exactly like a step that found a real improvement. So the strictness verdict (passed / failures) and the termination status (converged) are columns at both levels - on every candidate of every step, and on the model each step selected - beside the criterion, the dOFV and the wall clock. print() shows the step table; summary() adds every step’s candidates. The same two tables are written to directory as steps.csv and candidates.csv, with one subdirectory per step holding that tool’s own fuller record, and final.ferx at the top.
Strategies
"default": structural, IIV, residual, IOV, allometry, covariates - Pharmpy’s own order."reevaluation": the default order, then IIV and residual again: both were decided before the model had its covariates."SIR": structural, IIV, residual."SRI": structural, residual, IIV."RSI": residual, structural, IIV.
skip leaves a named step out of whichever order is chosen.
Retries
retries says how many perturbed restarts every candidate of every step gets on top of the fit from its exact initial estimates. retries_on is the separate pass over a model a step has already selected, which refits it from perturbed starts to check that its optimum is the one it landed on: "all_final" (the default) runs that pass after each step, "final" only on the pipeline’s final model, and "skip" not at all. The pass never adopts a fit the strictness gate rejected, and its row is in the candidate table with tool = "retries".
Two entry forms
Pass either config - a .ferxsearch file, which is the reproducible artifact - or the inline arguments. The inline form is rendered into the same configuration and handed to the engine’s own loader, so the two cannot disagree. Only the file can carry a per-tool section ([modelsearch], [iivsearch], [covsearch], …); the inline form runs each step at its own defaults. The run arguments (threads, retries, resume, directory, progress) say how to run a pipeline rather than what to search, and are available to both forms.
Seealso
[ferx_amd_plan](ferx_amd_plan.qmd) for the pipeline without the fitting, [ferx_search_config](ferx_search_config.qmd), [ferx_modelsearch](ferx_modelsearch.qmd), [ferx_iivsearch](ferx_iivsearch.qmd), [ferx_ruvsearch](ferx_ruvsearch.qmd), [ferx_iovsearch](ferx_iovsearch.qmd), [ferx_allometry](ferx_allometry.qmd), [ferx_covsearch](ferx_covsearch.qmd)Other search: [ferx_allometry](ferx_allometry.qmd), [ferx_amd_plan](ferx_amd_plan.qmd), [ferx_covsearch](ferx_covsearch.qmd), [ferx_globalsearch](ferx_globalsearch.qmd), [ferx_iivsearch](ferx_iivsearch.qmd), [ferx_iovsearch](ferx_iovsearch.qmd), [ferx_modelsearch](ferx_modelsearch.qmd), [ferx_ruvsearch](ferx_ruvsearch.qmd), [ferx_search_config](ferx_search_config.qmd), [ferx_search_coverage](ferx_search_coverage.qmd), [ferx_search_results](ferx_search_results.qmd), [ferx_search_space](ferx_search_space.qmd)
Concept
search
Value
An object of class ferx_amd:
- steps: The step table, one row per planned step - skipped ones included - in the engine’s own column order, with the pipeline position beside the step name (a
reevaluationrun has two rows callediivsearch):index,step,tool,rerun,directory,status(ran/skipped/failed),reason,criterion,value_before,value_after,d_value,ofv_before,ofv_after,d_ofv,candidates,selected,seconds,converged,passedandnotes.convergedandpassedare the termination status and the strictness verdict of the model the step selected, taken from that model’s row incandidates; they areNAfor a step that selected no candidate of its own and carried the model it was handed forward, whose verdict is on the row of the step that produced it. - candidates: Every candidate of every step, in the engine’s own column order:
step,tool,id,parent,description,criterion,value,d_value,ofv,d_ofv,rank,converged,passed,failures,error,note,seconds,selected.criterionnames whatvalueis on, which is not always the step’s own: a ruvsearch pre-screen candidate is fitted to the parent’s CWRES, so its number is on the CWRES scale and must not be compared with a data OFV.toolis"start"for the pipeline’s own first fit and"retries"for a perturbed-restart pass. - tools: One entry per step that ran - a step that failed included, carrying its reason and an empty candidate table - named by position and step. Each holds what the step decided (
status,reason,criterion,selected,seconds) and its own slice ofcandidates. When the run kept itsdirectory, the tool’s own record is nested beside that, read back from the step’s directory with[ferx_search_results](ferx_search_results.qmd):modelsorsteps(whichever table that tool writes),input_model_pathandfinal_model_path, andmodel_pathsfor every candidate model it kept. These are the engine’s own tables rather thanferx_modelsearch/ferx_iivsearchobjects: the pipeline returns each step’s candidates adapted to one shape and leaves the tool’s fuller record on disk, so a classed object would have to be rebuilt in R from those files - a second construction path, and still without the fit and the options only a direct call returns. Run the tool on its own when you want its object. - fit: The final model’s fit as a
ferx_fit, orNULLwhen the pipeline ended with no fit in hand. - input_model, input_ofv: The model the pipeline started from, and its objective function value.
- final_model, final_model_path, final_ofv, d_ofv: The model it ended on - already seeded from its own estimates - the file it was written to, its objective function value, and the change against the starting model (negative is an improvement).
- options: The pipeline as the engine read it:
strategy,retries_onandskip. - summary_text: The engine’s own report, as
ferx amdprints it. - notes, cancelled: What the pipeline wants said once (a step that failed, a retries pass that could not run), and whether it was stopped early.
Examples
ex <- ferx_example("warfarin_amd")
# What would run, before paying for it
ferx_amd_plan(model = ex$model, data = ex$data,
search_space = "ABSORPTION(FO); PERIPHERALS(0..1); IIV?(@PK, exp)")
# Reproducible: the .ferxsearch file is the artifact
res <- ferx_amd(config = ex$search, directory = "amd-run")
res
res$steps[, c("index", "step", "status", "d_value", "passed", "selected")]
summary(res)
# Inline, with the residual step left out
res2 <- ferx_amd(
model = ex$model,
data = ex$data,
search_space = "ABSORPTION(FO); PERIPHERALS(0..1); IIV?(@PK, exp)",
strategy = "SIR",
skip = "residual",
directory = "amd-run-2"
)