New multistart() re-estimates a model from many
perturbed starting points, so a fit that settled in a local optimum can
be recognized. It takes either a fit or a model plus data, works with
any estimation method, and returns a nlmixr2Multistart
object holding every start’s objective function and parameter estimates
alongside the best fit.
plot() on the result gives the objective-function
waterfall (type = "waterfall", the default) and the
parameter-stability plot (type = "parameters").
Starting points are drawn around the initial estimates by
"uniform" (the default), "lhs" (Latin
hypercube) or "normal" sampling, respecting fixed
parameters and declared bounds. By default the candidates are
pre-screened with a cheap empirical-Bayes objective evaluation so that
only the most promising ones are fully estimated, and each start is
cached to disk so that an interrupted run resumes where it left off. See
multistartControl() for the options.
covarSearchAuto() selects unit-scale covariates
again. A candidate coefficient is added at exactly 0;
‘nlmixr2est’ (>= 7.0.2) nudges such a parameter to
foceiControl(zeroTheta) (0.001) and FOCEi then
steps it by that amount, so a numeric covariate on a unit scale (e.g. a
z-score) never left zero and was never selected. Each new coefficient
now starts at 0.1/max(|covariate|), a step matched to the
covariate’s units that keeps the starting effect within 0.1
for every subject.
linearize() no longer diverges when re-estimating a
model whose residual error parameters are small. In the linearized model
those parameters are ordinary thetas, so FOCEi scaled them as linear
parameters (1/|estimate|) rather than as residual errors
(0.5*|estimate|); for a combined1() model this
drove add.sd into its lower bound and left the objective
function 33 points above where the refit started. They now keep their
residual scaling, which also converges in far fewer iterations.
preconditionFit() accepts a decorated covariance
method. nlmixr2est reports the sandwich as
"|r|,|s|" when a matrix needed the absolute-value
correction (or "r+,s+" when it was nudged
positive-definite), but the retry loop compared against the bare
"r,s", so a good result read as a failure. It then
re-preconditioned the already-preconditioned fit until the R matrix was
numerically singular and solve() gave up with “system is
computationally singular”. A singular preconditioning matrix is now also
reported as a preconditioning failure naming the try, rather than as a
bare solve() error (#128).
The same applies to the " (full)" scope suffix
nlmixr2est appends when the installed covariance spans
theta + residual sigma + Omega rather than the structural-theta block
alone (foceiControl(covFull=), TRUE by
default), so "r,s (full)" is recognized as the sandwich
too. The shape does not matter to preconditionFit(): the
preconditioner is widened to whatever parameter space the returned
covariance spans.
preconditionFit() works again. It built the
reparameterized model lines through symengine, which cannot
parse an identifier containing a ., so a conventional
residual name like add.sd (as
nlmixr2Pre_add.sd) raised “SymEngine exception: Parse
error” and made the function unusable for most models. The lines are now
assembled directly from the preconditioning matrix, which also drops the
symengine dependency from this path (#124).
preconditionFit() no longer fails with
“non-conformable arguments” on a model with random effects.
fit$R spans only the population parameters while the fit
covariance also carries the omega elements, so the preconditioner is now
widened to the covariance’s own parameter space – identity off the theta
block – which keeps the theta/omega cross-covariances correct.
linearize() works on a model with a correlated eta
block. The generated model was built by pasting each entry of
ui$eta into a model line, but for a correlated block that
property also carries the off-diagonal entry – e.g.
(eta.cl,eta.v) – which produced
mu_(eta.cl,eta.v) = ... and failed to parse. The eta names
are now taken from the diagonal of the ini data frame (#126).
Regenerate the stored theoFitOde fit. It was built
against an older ‘nlmixr2est’, and its saved $control no
longer matched what the current estimator expects, so anything that
re-ran the model through that control – bootstrapFit(),
profile(), or a plain
nlmixr2(fit$finalUiEnv, ..., control = fit$control) –
failed with “attempt access index 130/129 in VECTOR_ELT”.
addorremoveCovariate() no longer turns the
iniDf neta1/neta2 columns into
character (#110). The row it adds set them to
NA_character_, and rbind() promotes the whole
column to match, so max() and order() on those
columns became lexicographic further downstream – with ten or more etas
max() returned "9" rather than
10, so the next eta index collided with an existing
one.
Ini rows that are built by hand (adding a covariate in
addorremoveCovariate(), adding thetas during linearization)
no longer hard-code their column list, so they still
rbind() with an iniDf that carries the
prior column newer versions of lotri add for
prior distributions (#109). Both shapes of the data frame are handled,
so this works with lotri versions that have the column and
versions that do not.
getMinAICFit() returns the fit with the lowest AIC,
listModelsTested() builds a
Description/AIC/dAIC table ready
for pander::pander(), and isBoundaryFit()
reports whether a fit has a parameter at its boundary. By default both
selection helpers exclude boundary fits. See the new “reporting helpers”
article.Fix bootstrapFit(stratVar=), which did not actually
resample. The stratified branch called
sample(list(uids), ...), and since list(uids)
has length one every draw returned the whole vector of subject ids, so
the bootstrap datasets did not depend on the seed (#99). Three further
problems in the same code are fixed with it: the new subject ids
restarted at 1 in each stratum, so subjects from different strata were
merged under a shared id; the sample was split across strata by the
number of observations rather than the number of
subjects, over-weighting strata whose subjects have more
records; and rounding each stratum up could return more subjects than
nSampIndiv asked for.
A stratified bootstrap now always draws whole subjects. When
stratVar changed within a subject, that subject’s records
were split between strata and resampled as separate (partial) subjects;
each subject is now stratified by its first value, with a
warning.
nlmixr2extra:::sampling() now resolves its
uid_colname default before using it. Called without one it
sampled ncol(data) subjects instead of the number of
subjects in the data. It also accepts a tibble, which previously
produced a one column tibble where a vector of subject ids was
expected.
Fix covarSearchAuto() crashing with “wrong arguments
for subsetting an environment” when a covariate is selected; the best
model is now re-fit to recover its fit object. Also corrected the
forward inclusion test, which had an inverted sign so improving
covariates were never selected (#103)
bootstrapFit() now works for models with a single
estimated population parameter, a single random effect, or no random
effects at all. Previously the bootstrap summary collapsed 1-row / 1x1
quantile arrays to vectors (and could not summarize a NULL
omega), causing bootstrapFit() to error with
dim(X) must have a positive length,
incorrect number of dimensions, or
'data' must be of a vector type, was 'NULL'. Printing the
bootstrap summary of a model with no random effects no longer errors
either.
optimUnisampling() now keeps N and
floorT when it retries internally. Before, the recursive
call reset them to the defaults, so asking for a sample size other than
1000, or for un-floored values, could silently return 1000 integer
samples instead (#97)
The bundled theoFitOde fit was regenerated and can
now be read without the qs2 package. Its
origData and parHistData had been serialized
with qs2, so without that package installed those slots
could not be decoded and fit$dataMergeInner() – and
anything built on it, such as the nlmixr2rpt figures –
failed.
Add focei/foce linearization
Add formula interface
Add vignettes on linearization, formula interface, log-likelihood profiling and preconditioning.
profile() method for likelihood profiling (Issue
#1)bootstrapFit() fixes se option (Issue
#66)bootstrapFit() now will be more careful handling
NA values so they do not completely affect results (Issue
#59)
bootstrapFit() will now only take the correlation of
the non-zero diagonals (Issue #59).
New method for knit_print() will generate model
equations for LaTeX reporting automatically.
Tests are now skipped if they contain linear compartment models that need gradients when the gradients are not compiled (as in the case of intel c++).
Use assignInMyNamespace() instead of using the
global assignment operator for the horseshoe prior
Be specific in version requirements (as requested by CRAN checks)
Move the theoFitOde.rda data build to
devtools::document() to reduce CRAN build time (could add
more standard models like warfarin for package developers which takes
way too much time for CRAN)
Fix cli issues with the new cli 3.4+
release that will allow bootstrapping to run again (before
cli would error, this fixes the donttest
issues on CRAN).
Fixed step-wise covariate selection to work a bit better with the updated UI, thanks to Vishal Sarsani
Added lasso covariate selection (thanks to Vishal Sarsani)
Added horseshoe prior covarite selecion (thanks to Vishal Sarsani)
Added a NEWS.md file to track changes to the
package.