Search code examples
rfor-loopr-lavaanpsych

R for-loop reverting back to previous values


I am attempting to simulate data using the simstudy package and then calculate coefficient omega with the psych package. I am using for-loops to run through different values for within cluster variation, inter-item correlation, and a number of iterations.

I began testing this with 3-10 iterations and kept getting an error from lavaan saying the model did not converge. When I opened up the output, I could see the for loop was actually reverting back to previous values then stopping. For example, with 10 iterations per condition here is what happened:

 var = 0 + all values for rho - ran successfully
    var = 0.5 + all values for rho - ran successfully
    var = 1.0 + all values for rho - ran successfully
    var = 1.5 + rho = 0.1 - 7 successful iterations, then reverted back to var = 1.0 + rho = 0.6 for the remaining 3 iterations in that loop then entire loop stopped prematurely.

I tried updating R, R studio, and R packages. I ran it with and without the tryCatch for errors with Omega. I also tried adjusting the number of iterations and found with more iterations the issue occurs later in the simulations, however, when I put iterations to 1000 (my end goal) and all the output became NAs.

library(simstudy)
library(dirmult)
library(tidyverse)
library(dplyr)
library(readr)
library(psych)
library(GPArotation)
library(multilevel)
library(lavaan)

## creating an empty data frame for results ##
results_df <- data.frame(iteration=numeric(),
                         within_cluster_variance=numeric(),
                         inter_item_rho=numeric(),
                         SL_Omega_raw=numeric()) 
set.seed(123)

var_value <- c(0.0, 0.5, 1.0, 1.5, 2.0, 2.5)
rho_value <- c(0.1, 0.2, 0.3, 0.4, 0.5, 0.6)
for(v in var_value){
  for(r in rho_value){
    for(i in 1:5){
      # LEVEL 2 #
      class.level <- defData(varname = "class_zscore", dist = "normal", 
                             formula = 0, variance = 1, id = "Class_ID")
      class.level <- defData(class.level, varname = "Student_Count", dist = "noZeroPoisson", formula = 20)
      class.data <- genData(100, class.level)
      
      # LEVEL 1 #
      gen.student <- defDataAdd(varname = "student_EXTERNALIZE_score", dist = "normal", 
                                formula = "class_zscore", variance = v)
      dtClass <- genCluster(class.data, "Class_ID", numIndsVar = "Student_Count", level1ID = "Student_ID")
      dtClass <- addColumns(gen.student, dtClass)
      
      baseprobs <- matrix(c(
        0.973, 0.018, .006, 0.003,
        0.829, 0.095, .050, 0.026,
        0.765, 0.115, .069, 0.051,
        0.882, 0.068, .032, 0.018,
        0.717, 0.106, .081, 0.096,
        0.880, 0.062, .038, 0.020,
        0.905, 0.045, .034, 0.016),
        nrow = 7, byrow = TRUE)
      
      student.items <- genOrdCat(dtClass , adjVar = "student_EXTERNALIZE_score", 
                                 baseprobs, prefix = "Item", 
                                 asFactor=FALSE, idname = "Student_ID",
                                 corstr = "cs", rho = r)
      
      student.items->SIM_DATA
      SIM_DATA[,6:12]->ITEMS
      
      # Single-level Continuous Omega #
      # Initialize SL_Omega_values with "Convergence failed" #
      SL_Omega_values <- data.frame(omega.tot = "Convergence failed")
      
      # Attempt to calculate omega total reliability coefficients #
      tryCatch({
        psych::omega(ITEMS, nfactors = 1, poly = FALSE, plot = FALSE, lavaan = TRUE) -> SL_omega
        
        SL_Omega_values <- as.data.frame(SL_omega$omega.tot)
      }, error = function(e) {
        # If convergence fails, assign "Convergence failed" to SL_Omega_values[1,1] #
        SL_Omega_values[1,1] <- "Convergence failed"
      })
      
      results_df[i,] <- (c(i, v, r, SL_Omega_values[1,1]))
      
      
      write.csv(results_df, paste0("results_df","_",v,"_",r,"_",".csv"))
      results_df}}}```

Solution

  • I think the problem is that your tryCatch() isn't saving the values you want in the right way. You need SL_Omega_values to be the output from tryCatch() rather than trying to set that value within the function. Try this:

    library(simstudy)
    library(dirmult)
    library(tidyverse)
    library(dplyr)
    library(readr)
    library(psych)
    library(GPArotation)
    library(multilevel)
    library(lavaan)
    
    ## creating an empty data frame for results ##
    results_df <- data.frame(iteration=numeric(),
                             within_cluster_variance=numeric(),
                             inter_item_rho=numeric(),
                             SL_Omega_raw=numeric()) 
    set.seed(123)
    
    var_value <- c(0.0, 0.5, 1.0, 1.5, 2.0, 2.5)
    rho_value <- c(0.1, 0.2, 0.3, 0.4, 0.5, 0.6)
    for(v in var_value){
      for(r in rho_value){
        for(i in 1:5){
          # LEVEL 2 #
          class.level <- defData(varname = "class_zscore", dist = "normal", 
                                 formula = 0, variance = 1, id = "Class_ID")
          class.level <- defData(class.level, varname = "Student_Count", dist = "noZeroPoisson", formula = 20)
          class.data <- genData(100, class.level)
          
          # LEVEL 1 #
          gen.student <- defDataAdd(varname = "student_EXTERNALIZE_score", dist = "normal", 
                                    formula = "class_zscore", variance = v)
          dtClass <- genCluster(class.data, "Class_ID", numIndsVar = "Student_Count", level1ID = "Student_ID")
          dtClass <- addColumns(gen.student, dtClass)
          
          baseprobs <- matrix(c(
            0.973, 0.018, .006, 0.003,
            0.829, 0.095, .050, 0.026,
            0.765, 0.115, .069, 0.051,
            0.882, 0.068, .032, 0.018,
            0.717, 0.106, .081, 0.096,
            0.880, 0.062, .038, 0.020,
            0.905, 0.045, .034, 0.016),
            nrow = 7, byrow = TRUE)
          
          student.items <- genOrdCat(dtClass , adjVar = "student_EXTERNALIZE_score", 
                                     baseprobs, prefix = "Item", 
                                     asFactor=FALSE, idname = "Student_ID",
                                     corstr = "cs", rho = r)
          
          student.items->SIM_DATA
          SIM_DATA[,6:12]->ITEMS
          
          # Single-level Continuous Omega #
          # Initialize SL_Omega_values with "Convergence failed" #
          SL_Omega_values <- data.frame(omega.tot = "Convergence failed")
          
          # Attempt to calculate omega total reliability coefficients #
          SL_Omega_values <- tryCatch({
            psych::omega(ITEMS, nfactors = 1, poly = FALSE, plot = FALSE, lavaan = TRUE) -> SL_omega
            
            as.data.frame(SL_omega$omega.tot)
          }, error = function(e) {
            # If convergence fails, assign "Convergence failed" to SL_Omega_values[1,1] #
            "Convergence failed"
          })
          
          results_df[i,] <- (c(i, v, r, SL_Omega_values[1,1]))
          
          
          write.csv(results_df, paste0("results_df","_",v,"_",r,"_",".csv"))
          results_df}}}