Residual-error model search

Description

Runs a residual-error search - Pharmpy’s ruvsearch - over a model’s [error_model] block. Each iteration adds one residual-error feature to the model the last iteration kept, fits every candidate, and accepts the largest improvement the likelihood-ratio test calls significant at p_value. Up to max_iter features are stacked this way.

Usage

ferx_ruvsearch(
  model = NULL,
  data = NULL,
  config = NULL,
  groups = NULL,
  p_value = NULL,
  skip = NULL,
  max_iter = NULL,
  cwres_prescreen = NULL,
  threads = NULL,
  retries = NULL,
  directory = NULL,
  resume = FALSE,
  progress = interactive()
)

# S3 method for ferx_ruvsearch
print(x, digits = 4, ...)

# S3 method for ferx_ruvsearch
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 search runs on, so like model it cannot be given beside config - the file’s own data key says which dataset that file searches.
  • config: Path to a .ferxsearch file. Mutually exclusive with the arguments that state the search.
  • groups: Time-after-dose bins the time-varying candidates cut at: groups - 1 candidates, at the i / groups quantiles. NULL keeps the engine default (4).
  • p_value: The likelihood-ratio level a candidate must reach. NULL keeps the engine default (0.001).
  • skip: Families never tested, any of "IIV_on_RUV", "power", "combined", "time_varying". NULL tests them all.
  • max_iter: Iterations, 1 to 3 as in Pharmpy. NULL keeps the engine default (3).
  • cwres_prescreen: Screen the candidates on the parent’s CWRES first and refit only the winner - Pharmpy’s own path, and much cheaper than fitting every candidate to the data. NULL keeps the engine default (FALSE: every candidate is fitted).
  • threads: Total worker threads. NULL lets the runner choose.
  • retries: Perturbed restarts per candidate on top of the exact one. NULL keeps the engine default.
  • directory: Where the per-iteration journals, steps.csv, models/<id>.ferx and final.ferx are written. NULL keeps the run in memory, which also means it cannot be resumed.
  • resume: Reuse the fits already journalled in directory.
  • progress: Print the engine’s iteration progress to the console.
  • x: A ferx_ruvsearch object.
  • digits: Significant digits for the printed tables.
  • ...: Ignored.
  • object: A ferx_ruvsearch object.

Details

There is no search space to state: the candidates are the four families Pharmpy tests, and skip is what narrows them.

  • IIV_on_RUV: A log-normal per-subject scale on the residual SD (ETA_RUV). Needs an estimation method with eta-epsilon interaction (focei, imp, impmap, saem); on a foce model it is not tested, and the run says so in $notes.
  • power: The proportional loading raised to an estimated exponent, power(sigma, P).
  • combined: An additive component beside the proportional one.
  • time_varying: Every sigma scaled by a theta for records below a time-after-dose cutoff - groups - 1 candidates, at the i / groups quantiles of time after dose.

power and combined are tested together or not at all, as in Pharmpy, and accepting one of them retires both. The search always starts from a plain proportional error model: when the input is not one, its proportional counterpart is fitted first and becomes the parent of iteration one (base_model_id says which). The final comparison then checks the accepted stack against the input as well, so a search can return the model it started from. A candidate has to pass the strictness gate before it can be accepted, and the step table always carries the termination status and the gate verdict beside the p-value - a candidate that stalled at its initial estimates carries a dOFV that says nothing about the error model it was testing.

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. The run arguments (threads, retries, resume, directory, progress) say how to run a search rather than what to search, and are available to both forms. A [space] section, or a [rank] asking for a BIC or a cutoff, is refused by name when the file is read: ruvsearch selects on the likelihood-ratio test at p_value, not on a ranking criterion.

Seealso

[ferx_search_config](ferx_search_config.qmd), [ferx_search_results](ferx_search_results.qmd), [ferx_covsearch](ferx_covsearch.qmd), [ferx_modelsearch](ferx_modelsearch.qmd)Other search: [ferx_allometry](ferx_allometry.qmd), [ferx_amd](ferx_amd.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_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_ruvsearch:

  • steps: The step table, one row per fitted model, in the engine’s own column order: iteration, candidate, feature, screened, parent_ofv, ofv, dofv, df, p_value, alpha, significant, cwres_dofv, selected, converged, passed, failures, seconds - followed by family (the feature’s family, which is what skip names and what a selection retires) and note (why a row could not be compared, on its own; failures carries it too when the gate had nothing to say). A row with screened = TRUE is a CWRES pre-screen fit: its ofv is on the CWRES scale rather than the data’s, and cwres_dofv is its improvement over the CWRES base - only the feature the screen picked was refitted to the data.
  • fit: The final model’s fit as a ferx_fit, or NULL when a degraded resume could not recover it.
  • model_text: Every fitted model’s text, named by candidate id, so a form the search rejected can be read or refitted without re-running it. final_model_path is the final.ferx written beside the run.
  • final_features, final_families: The features the final model carries beyond the base, in the order they were accepted. Empty when the search returned the input or the proportional base.
  • input_model, input_ofv: The model file’s own error model, fitted as given.
  • base_model_id, base_ofv: The parent of iteration one: "input", or "base" when a proportional base had to be derived.
  • final_model, final_model_id, final_ofv: The winning model’s text, its id, and its objective function value.
  • options: The search as the engine read it: groups, p_value, skip, max_iter, cwres_prescreen and cutoff (the df = 1 chi-square cutoff at p_value).
  • n_iterations: Iterations actually run.
  • candidates: The runner’s candidate table when the run wrote one - see [ferx_search_results](ferx_search_results.qmd).
  • notes, cancelled: What the search wants said once (a family not tested and why, a reversion), and whether it was stopped early.

Examples

ex <- ferx_example("one_cpt_iv")

# Inline: no file to author for a one-off
res <- ferx_ruvsearch(
  model     = ex$model,
  data      = ex$data,
  p_value   = 0.05,
  max_iter  = 2,
  directory = "ruvsearch-run-1"
)
res
res$steps[, c("iteration", "feature", "family", "dofv", "p_value", "passed")]
summary(res)

# Reproducible: the .ferxsearch file is the artifact
res2 <- ferx_ruvsearch(config = ex$search, directory = "ruvsearch-run-2")