lavaan icon indicating copy to clipboard operation
lavaan copied to clipboard

Randomly perturb the starting values and try again

Open sfcheung opened this issue 2 years ago • 0 comments

(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.

sfcheung avatar Jun 18 '22 03:06 sfcheung