lavaan
lavaan copied to clipboard
Randomly perturb the starting values and try again
(From this thread in Google group: https://groups.google.com/g/lavaan/c/KzPT7VdHpb8/m/Xl9jUd9pAAAJ)
I sometimes use OpenMx. It has the function mxTryHard()
which will fit a model several times with randomly perturbed starting values, to see if a solution can be found. Maybe a similar function can be developed for lavaan? This is a draft one to illustrate the idea:
try_more <- function(object, attempts = 3, seed = NULL, rmin = .5, rmax = 1) {
set.seed(seed)
ptable <- lavaan::parameterTable(object)
i_free <- ptable$free > 0
i_free_p <- i_free & (ptable$op != "~~")
k <- sum(i_free_p)
ptable$est <- ptable$start
# Generate a list of vectors of randomly perturbed starting values
x <- replicate(attempts, stats::runif(k, rmin, rmax), simplify = FALSE)
out0 <- lapply(x, function(x) {
ptable_i <- ptable
ptable_i[i_free_p, "est"] <- ptable[i_free_p, "est"] * x
# Should do something to reject "bad" starting values
stats::update(object, start = ptable_i,
check.start = FALSE)
})
out0 <- c(list(object), out0)
# Need to add some error catching code. It is possible that all of them fail the check.
fit_ok <- sapply(out0, lavaan::lavInspect, what = "post.check")
out1 <- out0[fit_ok]
fit_fmin <- sapply(out1, lavaan::fitMeasures, fit.measures = "fmin")
out2 <- out1[which(fit_fmin == min(fit_fmin))]
# Should have the option to return more diagnostic information
out2[[1]]
}
The version above is certainly not yet ready for use (e.g., error checking need to be added, need a more robust way to change the starting values, etc.) but is sufficient to illustrate the idea, I think.
If a model does not take a long time to fit, maybe this function can be run whenever a model is fitted, to check automatically whether the objective function can be further minimized. If yes, returned the new solution with smallest objective function value.
If convergence failed when fitting a model, maybe this function can also be run automatically to see if convergence can be achieved by changing the starting values.
Or, just like OpenMx, this can be a standalone function for users who would like to do this.