Specify a model using a parameter table?

48 views
Skip to first unread message

Edward Rigdon

unread,
Nov 25, 2021, 11:02:03 AM11/25/21
to lav...@googlegroups.com
I'd like to estimate a model that lavaan won't like as a whole, and I'd like to do it by estimating the model's parameters in an alternating fashion--estimate these parameters while leaving those parameters fixed, then estimating those parameters while leaving these parameters fixed--until estimates stop changing.
From the documentation, it seems like I can specify a lavaan model using a parameter table. But I do not find an actual example in the documentation of using a table of parameter estimates as model specification, only assertions that it can be done.
If I could specify a model using a parameter table, then I would just need to change the status of parameters from free to fixed, and vice versa, and the code would not have to be terribly complex.
--Ed Rigdon

Shu Fai Cheung

unread,
Nov 25, 2021, 12:31:34 PM11/25/21
to lavaan
I believe others can give a more official way to do this. The following is my attempt:

```
library(lavaan) #> This is lavaan 0.6-9 #> lavaan is FREE software! Please report any bugs. mod_pop <- " m ~ .3*x y ~ .4*m " dat <- simulateData(mod_pop, sample.nobs = 100, seed = 43525) mod <- " m ~ x y ~ m " fit <- sem(mod, dat) ptable <- parameterTable(fit) # Original parameter table ptable #> id lhs op rhs user block group free ustart exo label plabel start est se #> 1 1 m ~ x 1 1 1 1 NA 0 .p1. 0.000 0.362 0.098 #> 2 2 y ~ m 1 1 1 2 NA 0 .p2. 0.000 0.499 0.095 #> 3 3 m ~~ m 0 1 1 3 NA 0 .p3. 0.506 0.889 0.126 #> 4 4 y ~~ y 0 1 1 4 NA 0 .p4. 0.579 0.905 0.128 #> 5 5 x ~~ x 0 1 1 0 NA 1 .p5. 0.931 0.931 0.000 ptable_new <- ptable ptable_new[1, "free"] <- 0 ptable_new[1, "est"] <- .3 # Modified parameter table ptable_new #> id lhs op rhs user block group free ustart exo label plabel start est se #> 1 1 m ~ x 1 1 1 0 NA 0 .p1. 0.000 0.300 0.098 #> 2 2 y ~ m 1 1 1 2 NA 0 .p2. 0.000 0.499 0.095 #> 3 3 m ~~ m 0 1 1 3 NA 0 .p3. 0.506 0.889 0.126 #> 4 4 y ~~ y 0 1 1 4 NA 0 .p4. 0.579 0.905 0.128 #> 5 5 x ~~ x 0 1 1 0 NA 1 .p5. 0.931 0.931 0.000 # Use the modified parameter table as input fit2 <- sem(ptable_new, dat) parameterTable(fit2) #> id lhs op rhs block user free ustart exo label group plabel start est se #> 1 1 m ~ x 1 1 0 NA 0 1 .p1. 0.300 0.300 0.000 #> 2 2 y ~ m 1 1 1 NA 0 1 .p2. 0.499 0.499 0.096 #> 3 3 m ~~ m 1 0 2 NA 0 1 .p3. 0.889 0.893 0.126 #> 4 4 y ~~ y 1 0 3 NA 0 1 .p4. 0.905 0.905 0.128 #> 5 5 x ~~ x 1 0 0 NA 1 1 .p5. 0.931 0.931 0.000 summary(fit2) #> lavaan 0.6-9 ended normally after 5 iterations #> #> Estimator ML #> Optimization method NLMINB #> Number of model parameters 3 #> #> Number of observations 100 #> #> Model Test User Model: #> #> Test statistic 0.667 #> Degrees of freedom 2 #> P-value (Chi-square) 0.716 #> #> Parameter Estimates: #> #> Standard errors Standard #> Information Expected #> Information saturated (h1) model Structured #> #> Regressions: #> Estimate Std.Err z-value P(>|z|) #> m ~ #> x 0.300 #> y ~ #> m 0.499 0.096 5.187 0.000 #> #> Variances: #> Estimate Std.Err z-value P(>|z|) #> .m 0.893 0.126 7.071 0.000 #> .y 0.905 0.128 7.071 0.000
```

Although the non-zero values in the modified parameter table are 2, 3, 4, it seems that lavaan will automatically change them to 1, 2, 3.

It may not be easy to create the parameter table from scratch. Nevertheless, we can specify the model as usual, call lavaan, get the generated parameter table, and then modify it, as shown above. We can also use lavaanify():

```
lavaanify(mod) #> id lhs op rhs user block group free ustart exo label plabel #> 1 1 m ~ x 1 1 1 1 NA 0 .p1. #> 2 2 y ~ m 1 1 1 2 NA 0 .p2. #> 3 3 m ~~ m 0 1 1 0 0 0 .p3. #> 4 4 y ~~ y 0 1 1 0 0 0 .p4. #> 5 5 x ~~ x 0 1 1 0 0 0 .p5.
```

However, the default values of the arguments in lavaanify() may be different from those of sem() or cfa(). The parameter table above is not identical to that from sem() (only two free parameters). If we use lavaanify(), we need to override some of the default values.

Alternatively, we can call sem() (or cfa(), I believe) and set do.fit = FALSE.

```
parameterTable(sem(mod, dat, do.fit = FALSE)) #> id lhs op rhs user block group free ustart exo label plabel start est se #> 1 1 m ~ x 1 1 1 1 NA 0 .p1. 0.000 0.000 NA #> 2 2 y ~ m 1 1 1 2 NA 0 .p2. 0.000 0.000 NA #> 3 3 m ~~ m 0 1 1 3 NA 0 .p3. 0.506 0.506 NA #> 4 4 y ~~ y 0 1 1 4 NA 0 .p4. 0.579 0.579 NA #> 5 5 x ~~ x 0 1 1 0 NA 1 .p5. 0.931 0.931 0
```

But what I did above is not official. I just tried and found the above methods work. Maybe others can provide an official and safe way to do what you want to do.

-- Shu Fai

Shu Fai Cheung

unread,
Nov 25, 2021, 12:33:08 PM11/25/21
to lavaan
> Although the non-zero values in the modified parameter table are 2, 3, 4, it seems that lavaan will automatically change them to 1, 2, 3.

Correction. It should be:

> Although the non-zero values in column "free" of the modified parameter table are 2, 3, 4, it seems that lavaan will automatically change them to 1, 2, 3.

-- Shu Fai

Edward Rigdon

unread,
Nov 25, 2021, 2:23:37 PM11/25/21
to lav...@googlegroups.com
Thank you! That is a perfect demo. I am trying to understand connections between factor-based and composite / quasi-factor based methods. I am going to use this approach to sidestep some identification problems.
--Ed Rigdon 

--
You received this message because you are subscribed to the Google Groups "lavaan" group.
To unsubscribe from this group and stop receiving emails from it, send an email to lavaan+un...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/lavaan/fa6aca0e-e6fe-4b14-93b0-d7aa835a25adn%40googlegroups.com.
Reply all
Reply to author
Forward
0 new messages