1

I want to do a structural equation model with several latent variables with item parcels. Some parcels shall be created randomly. I am currently struggling with the "parcelAllocation" function (semTools) and hope that someone can help me out!

My main dataset is called "Mydata". I have three latent variables (MAAS, PFS and SFS) for which I want to create random item parcels.

  • MAAS has 15 items (Mydata$MAAS_1 to Mydata$MAAS_15), I want 3 parcel with 5 items per parcel
  • PFS has 7 items (Mydata$PFS_1 to Mydata$PFS_7), I want 3 parcels with 2-3 items per parcel
  • SFS has 7 items (Mydata$SFS_1 to Mydata$SFS_7), I want 3 parcels with 2-3 items per parcel

I've been trying to use the parcelAllocation function as explained by the authors but I seem to have difficulties understanding it (or its output).

This is the code I tried:

# Specify item-level models for each variable
item.syntaxMaas <- paste0("MAAS = ~ MAAS_", 1:15)
item.syntaxPfs <- paste0("PFS = ~ PFS_", 1:7)
item.syntaxSfs <- paste0("SFS = ~ SFS_", 1:7)

cat(item.syntax, sep = "\n")

# Create parcels for MAAS variable

maas.parcel.names <- paste0("maas.par", 1:3)
maas.mod.parcels <- 'MAAS = ~ maas.par1 + maas.par2 + maas.par3'

# Create parcels for PFS variable
pfs.parcel.names <- paste0("pfs.par", 1:3)
pfs.mod.parcels <- 'PFS =~ pfs.par1 + pfs.par2 + pfs.par3'

# Create parcels for SFS variable
sfs.parcel.names <- paste0("sfs.par", 1:3)
sfs.mod.parcels <- 'SFS =~ sfs.par1 + sfs.par2 + sfs.par3'


# Allocate indicators to parcels using parallel computing
maas.parcels <- parcelAllocation(maas.mod.parcels, data = Mydata, 
                  nAlloc = 100, parcel.names = maas.parcel.names, 
                  item.syntax = item.syntaxMaas, std.lv = TRUE)
                              

pfs.parcels <- parcelAllocation(pfs.mod.parcels, data = Mydata, 
                                nAlloc = 100, parcel.names = 
                                pfs.parcel.names, 
                                item.syntax = item.syntaxPfs, 
                                std.lv = TRUE, parallel = "snow")

sfs.parcels <- parcelAllocation(sfs.mod.parcels, data = Mydata, 
                    nAlloc = 100, parcel.names = sfs.parcel.names, 
                    item.syntax = item.syntaxSfs, std.lv = TRUE, 
                    parallel = "snow")

I just want to know which items were allocated to which parcel, but when I run

maas.parcels

I get this Output:

Output.

I do not get what the output means. Where can I see which items were allocated to which parcel? Is there another function for that? Or did I do something wrong?

Ah and I want the parcels to be average scores of the items going into them. I did not find an argument for that. Is there a possibility to get that?

kjetil b halvorsen
  • 1,206
  • 2
  • 18
  • 28
Chrissie
  • 11
  • 2

1 Answers1

0

I just want to know which items were allocated to which parcel

You requested nAlloc = 100 allocations, so there are 100 answers to that question. And none of them are informative because the allocations are random. But if you have a purely academic interest in the algorithm, you can print(parcelAllocation) at the R Console to see the contents of the function. The section beginning assignments <- list() creates the random allocation schemes, so you could write your own function that simply returns that object.

getAlloc <- function (model, data, parcel.names, item.syntax,
                      nAlloc = 100, fun = "sem", ...) {
    if (nAlloc < 2) 
        stop("Minimum of two allocations required.")
    if (!fun %in% c("sem", "cfa", "growth", "lavaan")) 
        stop("'fun' argument must be either 'lavaan', 'cfa', 'sem', or 'growth'")
    lavArgs <- list(...)
    lavArgs$model <- item.syntax
    lavArgs$data <- data
    lavArgs$do.fit <- FALSE
    item.fit <- do.call(fun, lavArgs)
    item.PT <- parTable(item.fit)
    if (is.character(model)) {
        ptArgs <- formals(lavaanify)
        fitArgs <- lavInspect(item.fit, "call")[-1]
        sameArgs <- intersect(names(ptArgs), names(fitArgs))
        ptArgs[sameArgs] <- fitArgs[sameArgs]
        ptArgs$model <- model
        if (is.null(ptArgs$model.type)) 
            ptArgs$model.type <- "sem"
        if (ptArgs$model.type != "growth") 
            ptArgs$model.type <- "sem"
        ptArgs$ngroups <- lavInspect(item.fit, "ngroups")
        PT <- do.call("lavaanify", ptArgs)
    }
    else if (is.data.frame(model)) {
        PT <- model
    }
    else stop("'model' argument must be a character string of lavaan model", 
        " syntax or a lavaan parameter table.  See ?lavaanify help page.")
    factorNames <- lavNames(PT, type = "lv")
    if (!all(sort(lavNames(item.PT, type = "lv")) == sort(factorNames))) {
        stop("'model' and 'item.syntax' arguments specify different factors.\n", 
            "'model' specifies: ", paste(sort(factorNames), collapse = ", "), 
            "\n", "'item.syntax' specifies: ", paste(sort(lavNames(item.PT, 
                type = "lv")), collapse = ", "))
    }
    assignments <- list()
    for (i in factorNames) {
        parcels <- PT$rhs[PT$lhs == i & PT$op == "=~"]
        items <- item.PT$rhs[item.PT$lhs == i & item.PT$op == 
            "=~"]
        assignments[[i]]$parcels <- setdiff(parcels, names(data))
        assignments[[i]]$items <- setdiff(items, parcels)
        if (length(assignments[[i]]$parcels) == 0L) {
            factorNames <- factorNames[-which(factorNames == 
                i)]
            next
        }
        nItems <- length(assignments[[i]]$items)
        nParcels <- length(assignments[[i]]$parcels)
        assignments[[i]]$nPerParcel <- rep(nItems%/%nParcels, 
            nParcels)
        if (nItems%%nParcels > 0) 
            for (j in 1:(nItems%%nParcels)) {
                assignments[[i]]$nPerParcel[j] <- assignments[[i]]$nPerParcel[j] + 
                  1
            }
        names(assignments[[i]]$nPerParcel) <- assignments[[i]]$parcels
    }
  return(assignments)
}

## run it, on all your data rather than 1 factor at a time
allItems   <- c(item.syntaxMaas, item.syntaxPfs, item.syntaxSfs)
allParcels <- c(maas.parcel.names, pfs.parcel.names, sfs.parcel.names)
allModels <- c(maas.mod.parcels, pfs.mod.parcels, sfs.mod.parcels)
getAlloc(allModels, data = Mydata,
         nAlloc = 3, # short, for an example
         parcel.names = allParcels,
         item.syntax  = allItems)

I do not get what the output means

Have you already read the papers in the help-page References section?
That would inform you about the content of the output, which is just to show how much variability you can expect from results across different random allocations. That is the purpose of the function.

If you want to get a solution / fitted model for drawing inferences from your data, which takes parcel-allocation uncertainty into account, then you can use cfa.mi() or sem.mi() to pool the results across allocations, as shown in the help-page Examples and discussed in the 2016 paper.

I want the parcels to be average scores of the items going into them

That is what the function does internally.

Terrence
  • 780
  • 4
  • 7