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 .ferx model, or a ferx_model object. Omit when config is given.
  • data: Path to the dataset. Defaults to the model’s [data] block. Names the dataset the pipeline runs on, so like model it cannot be given beside config.
  • search_space: MFL search space, as a string or a character vector of lines. Required in the inline form.
  • config: Path to a .ferxsearch file. Mutually exclusive with the arguments that state the search.
  • strategy: Step order: "default", "reevaluation", "SIR", "SRI" or "RSI". NULL keeps the engine default ("default").
  • retries_on: Which selected models get the perturbed-restart pass: "all_final", "final" or "skip". NULL keeps 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] type the ranking steps use, e.g. "bic" or "ofv". NULL keeps each tool’s own default, which is a BIC.
  • cutoff: The [rank] cutoff. NULL keeps the default.
  • threads: Total worker threads. NULL lets the runner choose.
  • retries: Perturbed restarts per candidate on top of the fit from the exact initials. NULL keeps the engine default.
  • directory: Where the per-step directories, steps.csv, candidates.csv and final.ferx are written. NULL runs 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 in directory.
  • progress: Print the engine’s step progress to the console.
  • x: A ferx_amd object.
  • digits: Significant digits for the printed tables.
  • ...: Ignored.
  • object: A ferx_amd object.

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 reevaluation run has two rows called iivsearch): 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, passed and notes. converged and passed are the termination status and the strictness verdict of the model the step selected, taken from that model’s row in candidates; they are NA for 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. criterion names what value is 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. tool is "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 of candidates. When the run kept its directory, the tool’s own record is nested beside that, read back from the step’s directory with [ferx_search_results](ferx_search_results.qmd): models or steps (whichever table that tool writes), input_model_path and final_model_path, and model_paths for every candidate model it kept. These are the engine’s own tables rather than ferx_modelsearch / ferx_iivsearch objects: 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, or NULL when 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_on and skip.
  • summary_text: The engine’s own report, as ferx amd prints 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"
)