Impute missing covariate values
imputeMissingCovariates.RdReplaces user-defined sentinel values (default -99) in covariate
columns with values that the NLME engine can consume, leaving the
PML model code untouched. Within a reset block, masked rows are
left as NA so the engine performs row-level propagation via
fcovariate() / covariate() / interpolate(); only blocks (and
subjects) where the engine has nothing to propagate receive an
externally-computed fallback value.
Arguments
- model
NlmePmlModelobject. Must already have its covariate list populated (viaaddCovariate()for API-built models ortextualmodel()for textual ones) andidmapped viacolMapping().- data
Optional
data.frameto impute. Defaults tomodel@inputData. Never mutated by reference; an internal deep copy is used throughout.- missingToken
Vector of sentinel values. Default
c(-99). Supports numeric,NA, and character (e.g.c(-99, NA, ".")). Treated as a single missing-value predicate: a row is "missing" if its value matches any configured token. Tokens are not inferred: realNAvalues,".", and blank cells are only imputed when you list them here. Leaving them undeclared is an error rather than a silent no-op, because the NLME engine reads all three as missing.- method
"subject"(default) uses the cascade described in Details;"population"skips subject-level lookups and fills every masked row from the population or stratum central value.- continuousFn
Function applied to a non-empty numeric vector returning a single value. Default
median. Must return a length-1 finite numeric.- categoricalFn
Function applied to a non-empty vector (character, factor, or numeric for occasion / numeric-coded categorical) returning a single value. Default
imputeMode()– the package's exported modal-value helper with deterministic tie-breaking by first appearance and factor-level preservation. Pass a custom function (e.g.function(x) sort(unique(x))[1]) to override. Validation is type-driven, not model-driven:For factor columns, the returned value must already be a level of the input factor; factor levels are never extended implicitly. This is a technical R constraint (factor codes cannot encode an unknown label), not a model-semantic rule.
For character / numeric columns, the returned value is written into the data verbatim, even when it is not among the categories declared in
model@covariateList[[name]]. NLME treats out-of-declaration values per the model's default category semantics; the function does not second-guess that behaviour. If you need strict membership, supply acategoricalFnthat enforces it.
- centralValueWeighting
How the population / stratum central value is pooled.
"subject"(default) is two-stage: the aggregator is applied to each subject's values, then to the resulting vector of subject-level summaries, so every subject carries equal weight."row"applies the aggregator once across all non-missing rows, so subjects with more records count more."subject"is the default because it matches how the NLME engine pools covariate values formean()/median()centering (one summary per subject, then combined across subjects), and because row weighting otherwise tracks sampling density – a study-design artifact – rather than the population.Under
"subject"a customcontinuousFn/categoricalFnis invoked once per contributing subject and once across the subject summaries; a trimmed mean, for instance, then trims subject means rather than raw rows. The setting does not affect the"propagated"donor value, which is by definition computed within a single subject.- stratifyBy
Optional character vector of categorical column names. Population fallback is then computed within each stratum.
- minStratumFraction
Minimum acceptable stratum size as a fraction of total subjects; a warning is issued if any stratum is smaller. Default
0.1.- keepOriginal
If
TRUE(default), the raw pre-imputation values of each modified data column are preserved as<dataCol>_orig. A pre-existing backup column triggers an error to prevent corrupting traceability with stale data.- logFile
Path to write the imputation log. Default
NULLresolves tofile.path(model@modelInfo@workingDir, "imputeMissingCovariates.log"), creating the working directory if it does not exist yet (it usually will not, since the model has not been run). If the directory cannot be created, the log falls back totempdir()with a warning. An explicitlogFileis never given this treatment: its parent directory must already exist, so a typo fails loudly instead of scattering directories.The returned path uses forward slashes on every platform so it can be copied straight out of the console.
Value
A list with elements:
model– clone of inputNlmePmlModelwith@inputDatareplaced by the imputeddata.frame.data– imputeddata.frame(same object asresult$model@inputData).summary–data.framewith one row per (covariate, column, imputation_source, stratum) combination. Columns:covariate,column,type,imputation_source,stratum,imputed_value,n_imputed,n_subjects_affected.imputed_valueisNAfor"engine"(no value written; the engine fills at run time), a truncated list of distinct per-subject donors for"propagated", and the pooled central value for"stratum"/"population".logFile– absolute path of the written log file.
Details
The function returns a modified clone of the input NlmePmlModel
(with @inputData replaced by the imputed data.frame), along with
the imputed data, a traceability summary, and a log file. All other
model slots (@columnMapping, @covariateList, @statements,
@hasResetInfo, @resetInfo, etc.) are preserved verbatim so custom
mappings like WT -> BodyWeight survive the round-trip.
Imputation cascade (method = "subject", default). The NLME engine
propagates covariate values within a reset block but cannot carry
them across blocks, so the cascade classifies each (subject, reset
block):
Block has at least one non-missing value – masked rows are left as
NA(source"engine"). The engine fills them viafcovariate()/covariate()/interpolate().Block is fully missing but the subject has non-missing values in other blocks – the masked rows are filled with the subject aggregate computed by
continuousFn/categoricalFnover the subject's non-missing values across all blocks (source"propagated").Subject is fully missing across every block – the masked rows are filled with the population (or stratum) central value (source
"population"or"stratum").
method = "population" skips subject-level lookups and replaces
every masked row with the population (or stratum) central value.
Note the two methods differ in their effect on covariate centering.
method = "subject" leaves masked rows as NA, and the engine
excludes missing rows when it computes mean() / median()
centering values, so centering is unaffected. method = "population" writes a value into every masked row, and those values
do take part in centering.
Examples
if (FALSE) { # \dontrun{
model <- pkmodel(...)
model <- addCovariate(model, "WT", type = "Continuous")
model <- colMapping(model, c(WT = "BodyWeight"))
result <- imputeMissingCovariates(model)
model <- result$model
fit <- fitmodel(model)
print(result$summary)
} # }