Search code examples
riterationsimulationr-lavaan

Creating lavaan and mirt models permuations of varying size and length


hoping someone can offer some guidance here.

I'm creating a multivariate simulation using the simDesign package, I am varying the number of factors as well as items that load on each factor. I would like to write a command that identifies the number of factors present in factornumbers and assigns the appropriate items to them (no cross loading). I will be testing all combinations of the conditions below and more, and I would like to have a model command that acknowledge the iterations of differing models, so I don't have to write multiple model statements.

factornumbers<-c(1,2,3,5)
itemsperfactor<-c(5,10,30)

What lavaan and mirt are looking for is below:

mirtmodel<-mirt.model('
                    F1=1-15
                    F2=16-30
                    MEAN=F1,F2
                    COV=F1*F2')

lavmodel <- ' F1=~ Item_1 + Item_2 + Item_3 + Item_4 + Item_5 + Item_6 + Item_7 + Item_8 + Item_9 + Item_10 + Item_11 + Item_12 + Item_13 + Item_14 + Item_15
              F2=~ Item_16 + Item_17 + Item_18 + Item_19 + Item_20 + Item_21 + Item_22 + Item_23 + Item_24 + Item_25 + Item_26 + Item_27 + Item_28 + Item_29 + Item_30'

The simDesign package offers this example, I would like to expand on it but I'm not sure I have the know-how:

lavmodel<-paste0('F=~ ', paste0(colnames(dat)[1L], ' + '),
               paste0(colnames(dat)[-1L], collapse = ' + '))

What I would like is a single mirt and lavaan command that finds the number of factors specified in the factornumbers command and assigns the correct items specified in the data as well as itemsperfactor.

EDIT: I would like the model identification to pick up on which factor & item structure is in use for that condition and fill in the model identification with the correct information.

For Example:

mirtmodel<-mirt.model('
                    F1=1-1
                    F2=6-10
                    F3=11-15
                    F4=16-20
                    F5=21-25
                    MEAN=F1,F2,F3,F4,F5
                    COV=F1*F2*F3*F4*F5')

Or

 mirtmodel<-mirt.model('
                    F1=1-30
                    F2=31-60
                    MEAN=F1,F2
                    COV=F1*F2')

And also the corresponding lavaan models.


Solution

  • The idea here is to paste different strings together so that the condition input (row of the respective Design object) is all that is required to construct a suitable model specification string. Generating syntax for simulations is arguably the most annoying part of simulations, but at least in R there are a good number of helpful string operations (plus, packages like stringr).

    Here's my interpretation of what you are currently looking for using base R functions.

    library(SimDesign)
    library(mirt)
    
    Design <- createDesign(factornumbers = c(1,2,3,5),
                           itemsperfactor = c(5,10,30))
    
    gen_syntax_mirt <- function(condition){
        fn <- with(condition, factornumbers)
        ipf <- with(condition, itemsperfactor)
        nitems <- fn * ipf
        maxloads <- sort(seq(nitems, ipf, length.out = fn))
        minloads <- c(1, maxloads[-length(maxloads)] + 1)
        fnames <- paste0('F', 1:fn)
        df <- cbind(fnames, ' = ', minloads, '-', maxloads)
        s1 <- apply(df, 1, paste0, collapse = '')
        s2 <- paste0('MEAN = ', paste0(fnames, collapse = ','))
        s3 <- paste0('COV = ', paste0(fnames, collapse = '*'))
        ret <- paste0(c(s1, s2, s3), collapse = '\n')
        mirt.model(ret)
    }
    
    gen_syntax_mirt(Design[1,])
    gen_syntax_mirt(Design[10,])
    

    The input to this function is a single row from the Design input to runSimulation(), so you can see here that it will work just fine. Do something similar for lavaan's syntax and you'll be set.