Skip to contents

Make a function on lavaan object usable in a lavaan model syntax.

Usage

gen_userp(func, sem_out)

gen_sem_out_userp(
  userp,
  sem_out,
  userp_name = "semlbciuserp1234",
  fix = TRUE,
  control_args = list(),
  iter.max = 10000,
  max_attempts = 5
)

Arguments

func

A function that receives a lavaan-object and returns a scalar. See Details on the restriction on this function.

sem_out

A lavaan-class object to be modified.

userp

A function that is generated by gen_userp().

userp_name

The name of the function userp to be used in the lavaan model. It does not have to be the name of the function in userp. Should be changed only if it conflicts with another object in the parent environment, which should not happen if the model is always fitted in a clean R session.

fix

If TRUE, the default, the function generated is used to fix the value of userp to a target value using an equality constraint. If FALSE, then the function simply fits the model to the data.

control_args

To be passed to the argument of the same name in lavaan::lavaan(). Default is list(). Can be used to set the default values of this argument in the generated function.

iter.max

The maximum number of iteration when the generated function fit the model. Default is 10000.

max_attempts

If the initial fit with the equality constraint fails, how many more attempts will be made by the generated function. Default is 5.

Value

gen_userp

It returns a function that accepts a numeric vector of length equals to the number of free parameters in sem_out, and returns a scalar which is the output of func. If this vector is not supplied, it will try to find it in the parent.frame(). This is how it works inside a lavaan model.

gen_sem_out_userp

If fix is TRUE, it returns a function with these arguments:

  • target: The value to which the user-defined parameter will be fixed to.

  • verbose: If TRUE, additional information will be printed when fitting the model.

  • control: The values to be passed as a list to the argument of the same name in lavaan::lavaan().

  • seed: Numeric. If supplied, it will be used in set.seed() to initialize the random number generator. Necessary to reproduce some results because random numbers are used in some steps in lavaan. If NULL, the default, set.seed() will not be called.

If fix is `FALSE, then it returns a function with optional arguments that will be ignored, Calling it will simply fit the modified model to the data. Useful for getting the value of the user-defined parameter.

Details

gen_userp

There are cases in which we want to create a user parameter which is a function of other free parameters, computed by a function. However such a function may work only on a lavaan object.

If the target function works by extracting parameter estimates stored in the Model slot and/or the implied slot, then gen_userp() can be used to convert it to a function that retrieves the parameter estimates when being called by lavaan::lavaan() or its wrappers, modifies the stored lavaan object using lavaan::lav_model_set_parameters() and lavaan::lav_model_implied() to change the estimates, and call the target function.

Note that this is an unconventional way to define a user parameter and the generated function should always be checked to see whether it works as expected.

As shown in the examples, the parameter computed this may not have standard error nor p-value.

The main purpose is for the point estimate, for searching the likelihood-based confidence bound using ci_bound_ur() and ci_bound_ur_i().

Note that the target function specified in func should work directly on the parameter estimates stored in the Model slot and then get the estimates using lavaan::lav_model_get_parameters(). Functions that work on the unmodified output generated by lavaan::lavaan() usually do not work.

Users are not recommended to use gen_userp() and gen_sem_out_userp() directly because they require unconventional way to extract parameter estimates from a lavaan model. However, developers may use them to include functions they wrote in a lavaan model. This is the technique used by ci_bound_ur_i() to constrain any parameter in a model to an arbitrary value.

gen_sem_out_userp

The function gen_sem_out_userp() is to be used internally for generating a function for searching a likelihood-based confidence bound. It is exported because it needs to be run in an fresh external R process, usually created by callr in other internal functions.

Examples


library(lavaan)

data(simple_med)
dat <- simple_med
mod <-
"
m ~ a*x
y ~ b*m
ab := a*b
"
fit_med <- sem(mod, simple_med, fixed.x = FALSE)
parameterEstimates(fit_med)
#>   lhs op rhs label    est    se      z pvalue ci.lower ci.upper
#> 1   m  ~   x     a  1.676 0.431  3.891  0.000    0.832    2.520
#> 2   y  ~   m     b  0.535 0.073  7.300  0.000    0.391    0.679
#> 3   m ~~   m       34.710 3.471 10.000  0.000   27.907   41.513
#> 4   y ~~   y       40.119 4.012 10.000  0.000   32.256   47.982
#> 5   x ~~   x        0.935 0.094 10.000  0.000    0.752    1.118
#> 6  ab := a*b    ab  0.897 0.261  3.434  0.001    0.385    1.409

# A trivial example for verifying the results
my_ab <- function(object) {
    # Need to use lav_model_get_parameters()
    # because the object is only a modified
    # lavaan-object, not one directly
    # generated by lavaan function
    est <- lavaan::lav_model_get_parameters(object@Model, type = "user")
    unname(est[1] * est[2])
  }

# Check the function
my_ab(fit_med)
#> [1] 0.8968668
coef(fit_med, type = "user")["ab"]
#>        ab 
#> 0.8968668 

# Create the function
my_userp <- gen_userp(func = my_ab,
                      sem_out = fit_med)
# Try it on the vector of free parameters
my_userp(coef(fit_med))
#> [1] 0.8968668

# Generate a modified lavaan model
fit_userp <- gen_sem_out_userp(userp = my_userp,
                               userp_name = "my_userp",
                               sem_out = fit_med)

# This function can then be used in the model syntax.

# Note that the following example only work when called inside the
# workspace or inside other functions such as ci_bound_ur()`
# and `ci_bound_ur_i()` because `lavaan::sem()` will
# search `my_userp()` in the global environment.

# Therefore, the following lines are commented out.
# They should be run only in a "TRUE" interactive
# session.

# mod2 <-
# "
# m ~ x
# y ~ m
# ab := my_userp()
# "
# fit_med2 <- sem(mod2, simple_med, fixed.x = FALSE)
# parameterEstimates(fit_med2)
#
# # Fit the model with the output of the function, a*b
# # fixed to .50
#
# fit_new <- fit_userp(.50)
#
# # Check if the parameter ab is fixed to .50
# parameterEstimates(fit_new)