# Note: The following syntax for Internalizing Problems was applied identically to Externalizing Problems by replacing 'internal_r' with the respective 
variable name.


#-----------------------------------------------------------------------------------------------------------------------------------------------------------
# Analytical Code: Latent Growth Mixture Modelling (LGMM)
# Project: Predicting Mental Health Trajectories After Potentially Traumatic Events: A Machine Learning Approach
# Software: R Version 4.4.0
# Packages: lcmm, tidyLPA
#-----------------------------------------------------------------------------------------------------------------------------------------------------------


library(foreign)
library(lcmm)
library(tidyLPA)

# Set working directory (adjust to your local path)
# setwd("path/to/your/data")

# Load data (ensure the SPSS file is in the working directory)
data1 <- read.spss("YSR_LGMM.sav", use.value.label=FALSE, to.data.frame = TRUE)

# Example for Internalizing Problems (internal_r)
# ----------------------------------------------------------------------------------------------------------------------------------------------------------
# 1. Model Estimation: LGMM with random intercept and quadratic slope
# ----------------------------------------------------------------------------------------------------------------------------------------------------------

# 1-Class Model (Reference)
gmm1_2q <- hlme(internal_r ~ poly(time, degree = 2, raw = TRUE), subject = "ID_numeric", random=~1 + time, ng = 1, data = data1)

# 2-5 Class Models using Grid Search (100 repetitions)
gmm2_2q <- gridsearch(rep = 100, maxiter = 10, minit = gmm1_2q, hlme(internal_r ~ poly(time, degree = 2, raw = TRUE), subject = "ID_numeric", random=~1 + time, ng = 2, data = data1, mixture = ~ poly(time, degree = 2, raw = TRUE), nwg=TRUE)) 
gmm3_2q <- gridsearch(rep = 100, maxiter = 10, minit = gmm1_2q, hlme(internal_r ~ poly(time, degree = 2, raw = TRUE), subject = "ID_numeric", random=~1 + time, ng = 3, data = data1, mixture = ~ poly(time, degree = 2, raw = TRUE), nwg=TRUE)) 
gmm4_2q <- gridsearch(rep = 100, maxiter = 10, minit = gmm1_2q, hlme(internal_r ~ poly(time, degree = 2, raw = TRUE), subject = "ID_numeric", random=~1 + time, ng = 4, data = data1, mixture = ~ poly(time, degree = 2, raw = TRUE), nwg=TRUE))
gmm5_2q <- gridsearch(rep = 100, maxiter = 10, minit = gmm1_2q, hlme(internal_r ~ poly(time, degree = 2, raw = TRUE), subject = "ID_numeric", random=~1 + time, ng = 5, data = data1, mixture = ~ poly(time, degree = 2, raw = TRUE), nwg=TRUE)) 
 
# Generate Summary Table of Fit Indices
summarytable(gmm1_2q, gmm2_2q, gmm3_2q, gmm4_2q, gmm5_2q, which = c("G", "loglik", "conv", "npm", "AIC", "BIC", "SABIC", "entropy", "%class"))

# ----------------------------------------------------------------------------------------------------------------------------------------------------------
# 2. Lo-Mendell-Rubin Likelihood Ratio Test (LMR-LRT) via tidyLPA
# ----------------------------------------------------------------------------------------------------------------------------------------------------------
# Formula: calc_lrt(sample_size, null_ll, null_param, null_classes, alt_ll, alt_param, alt_classes)
calc_lrt(4141, -50468.06, 7, 1, -49429.87, 12, 2) 
calc_lrt(4141, -49429.87, 12, 2, -49110.18, 17, 3) 
calc_lrt(4141, -49110.18, 17, 3, -48838.31, 22, 4) 
calc_lrt(4141, -48838.31, 22, 4, -48838.57, 27, 5)

# ----------------------------------------------------------------------------------------------------------------------------------------------------------
# 3. Bootstrap Likelihood Ratio Test (BLRT) - Example for K3 vs K4
# ---------------------------------------------------------------------------------------------------------------------------------------------------------- 
original_data <- data1
LL_k3 <- gmm3_2q$loglik
LL_k4 <- gmm4_2q$loglik
LRT_obs <- -2 * (LL_k3 - LL_k4)

nboot <- 500            
lrt_boot_values <- numeric(nboot)
cat("Starting Bootstrapping with", nboot, "simulations.\n")

for (i in 1:nboot) {

# Simulation under the Null Hypothesis (K=3)
simulated_data <- simulate(gmm3_2q, times = original_data)
boot_model_k3 <- try(
    lcmm(
      fixed = gmm3_2q$call$fixed, mixture = gmm3_2q$call$mixture,
      random = gmm3_2q$call$random, subject = gmm3_2q$call$subject,
      ng = 3, data = simulated_data, B = gmm3_2q$best),
    silent = TRUE
  )
  
  boot_model_k4 <- try(
    lcmm(
      fixed = gmm4_2q$call$fixed, mixture = gmm4_2q$call$mixture,
      random = gmm4_2q$call$random, subject = gmm4_2q$call$subject,
      ng = 4, data = simulated_data, B = gmm4_2q$best),
    silent = TRUE
  )
     if (!inherits(boot_model_k3, "try-error") && !inherits(boot_model_k4, "try-error")) {
    lrt_boot_values[i] <- -2 * (boot_model_k3$loglik - boot_model_k4$loglik)
  } else {
    lrt_boot_values[i] <- NA
  }
  
  if (i %% 50 == 0) cat(paste("Bootstrap sample", i, "of", nboot, "completed.\n"))
}

lrt_boot_values <- na.omit(lrt_boot_values)
p_value <- mean(lrt_boot_values >= LRT_obs)

cat("\n--- BLRT Results ---\n")
cat("Observed LRT Statistic:", LRT_obs, "\n")
cat("Bootstrapped P-Value:", p_value, "\n")

