specifying syntax programmatically

435 views
Skip to first unread message

Eric Green

unread,
Dec 23, 2013, 4:21:39 PM12/23/13
to lav...@googlegroups.com
I have a bunch of lists that define scale make-up. For instance, here's a simple example of a fictional "scale1" with a total factor and two subscales:

myList1 <- list(scale1.tot=c("s1.item1", "s1.item2", "s1.item3", "s1.item4", "s1.item5", "s1.item6"),
                      scale1.sub1=c("s1.item1", "s1.item2", "s1.item3"),
                      scale1.sub2=c("s1.item4", "s1.item5", "s1.item6"))

I've already defined these lists because I am using the score.items() function of the psych package, and these lists instruct R how to calculate scale scores. Now I would like to transform these lists into model specifications:

mod1 <- '
  scale1.tot =~ s1.item1+s1.item2+s1.item3+s1.item4+s1.item5+s1.item6
'

I want to loop through all of my lists a vector called scales and go from myList1 to mod1 as shown. Here's what I've tried.

# data
s1.item1 <- sample(1:10, 50, replace=TRUE)
s1.item2 <- sample(1:10, 50, replace=TRUE)
s1.item3 <- sample(1:10, 50, replace=TRUE)
s1.item4 <- sample(1:10, 50, replace=TRUE)
s1.item5 <- sample(1:10, 50, replace=TRUE)
s1.item6 <- sample(1:10, 50, replace=TRUE)
dat.test <- as.data.frame(cbind(s1.item1, s1.item2, s1.item3, s1.item4, 
                                s1.item5, s1.item6))

# list
myList1 <- list(scale1.tot=c("s1.item1", "s1.item2", "s1.item3", "s1.item4", "s1.item5", "s1.item6"),
                      scale1.sub1=c("s1.item1", "s1.item2", "s1.item3"),
                      scale1.sub2=c("s1.item4", "s1.item5", "s1.item6"))

# vector of lists
scales <- c("myList1", "myList2", "myList3")  # other lists not shown

# loop over scale lists
for (s in scales) {
  myList <- get(s)
  # loop over elements of list
  for (i in 1:length(myList)) {
    lhs <- names(myList)[i]
    rhs <- paste(myList[[i]], collapse="+")
    mod <- as.name(paste0("'", lhs, "=~", rhs, "'", sep=" "))
    assign(paste("mod", names(myList)[i], sep="."), mod)
  }
  remove(myList)
  remove(lhs)
  remove(rhs)
  remove(mod)
}

This gives me several objects, including mod.scale1.tot. It prints as:

`'scale1.tot=~s1.item1+s1.item2+s1.item3+s1.item4+s1.item5+s1.item6' `

If I assign this object to mod.test, I can try to fit the model. I want to do this as part of the loop as well, but it's easier to show just one iteration.

mod.test <- mod.scale1.tot
fit.test <- cfa(mod.test, data = dat.test)

When I run this, I get the following error:

object 'FLAT' not found

Any idea what I am doing wrong? Is there a better approach to the task?

Eric Green

unread,
Dec 24, 2013, 11:48:54 AM12/24/13
to lav...@googlegroups.com

yrosseel

unread,
Dec 26, 2013, 2:48:23 AM12/26/13
to lav...@googlegroups.com
On 12/24/2013 05:48 PM, Eric Green wrote:
> resolved
> here: http://stackoverflow.com/questions/20763741/assigning-a-string-to-an-object-without-double-quotes

Two comments:

1) the lavaan model syntax is just a string; whatever method you use to
create a string will work

2) the reason for the single quotes (instead of double quotes) is that
with single quotes, you can embed double quotes (as in
equal("f1=~x2")*x3) within the model syntax; this was crucial for the
early versions of lavaan (where label() and equal() were needed to
impose equality constraints); not so important anymore nowadays.

But single quotes still create a string.

Yves.

Eric Green

unread,
Dec 27, 2013, 8:55:11 AM12/27/13
to lav...@googlegroups.com
Thanks, Yves. That's helpful.
Reply all
Reply to author
Forward
0 new messages