---
title: "Tutorial PMC"
output: rmarkdown::html_vignette
vignette: >
%\VignetteIndexEntry{tutorial_pmc}
%\VignetteEngine{knitr::rmarkdown}
%\VignetteEncoding{UTF-8}
---
```{r, include = FALSE}
run_everything = suppressWarnings(tryCatch({isTRUE(as.logical(readLines("run_everything.txt")))}, error = function(e){FALSE}))
knitr::opts_chunk$set(
collapse = TRUE,
message = FALSE,
warning = FALSE,
eval = run_everything,
comment = "#>"
)
```
This tutorial requires `tidySEM` version `0.2.11` or higher and `OpenMx`. Make sure both packages are
installed and loaded.
```{r }
library(tidySEM)
library(OpenMx)
```
## Example Data
We simulate a dataset with two continuous indicators, and two latent classes.
```{r}
set.seed(10)
n <- 200
# Set class-specific means
class_means <- c(rep(0, floor(0.3 * n)), rep(2, ceiling(0.7 * n)))
# Simulate continuous indicators
df <- rnorm(2 * n, mean = rep(class_means, 2))
df <- data.frame(matrix(df, nrow = n))
names(df) <- paste0("X", 1:2)
```
Next, we estimate 1-3 class solutions:
```{r}
res <- mx_profiles(data = df, classes = 1:3)
```
Optionally, one can perform the bootstrapped likelihood ratio test.
This takes a long time to run, so we conduct only 100 replications, rather than a more sensible number like 1000.
To accelerate computations, we can use the `future` package for parallel computing (see `?plan` to select the appropriate back-end for your system).
```{r eval = FALSE}
library(future)
plan(multisession)
res_blrt <- BLRT(res, replications = 100)
res_blrt
```
```{r eval = run_everything, echo = FALSE}
library(future)
plan(multisession)
res_blrt <- BLRT(res, replications = 100)
write.csv(res_blrt, "pmc_res_blrt.csv", row.names = FALSE)
```
```{r eval = TRUE, echo=FALSE}
res_blrt <- read.csv("pmc_res_blrt.csv", stringsAsFactors = FALSE)
class(res_blrt) <- c("LRT", "data.frame")
attr(res_blrt, "type") <- "Bootstrapped"
res_blrt
```
This test confirms that the 2-class solution is significantly better than the 1-class solution - but the 3-class solution offers no further significant improvement.
Next, we use predictive model comparison. If all variables are continuous,
the function `pmc()` uses the `srmr()` function to compare the standardized root mean squared (SRMR) difference between the correlation matrices of the real and model-implied data:
```{r eval = FALSE}
set.seed(1)
res_pmc <- pmc(res)
```
```{r eval = run_everything, echo = FALSE}
set.seed(1)
res_pmc <- pmc(res)
write.csv(res_pmc, "pmc_res_pmc.csv", row.names = FALSE)
```
```{r eval = TRUE, echo=FALSE}
res_pmc <- read.csv("pmc_res_pmc.csv", stringsAsFactors = FALSE)
class(res_pmc) <- c("pmc_df", "data.frame")
attr(res_pmc, "stat") <- "SRMR"
res_pmc
```
This test, too, confirms that the 2-class solution is significantly better than the 1-class solution - but the 3-class solution offers no further significant improvement.
If we conduct an LCA with ordinal indicators, the function uses a chi squared statistic instead of SRMR.
To demonstrate this, first, we convert the data to ordinal.
Note that real research data should not be polytomized like this.
Then, we estimate a model for ordinal indicators using `mx_lca()`.
We specify a custom function that references `x` and `y`, where both are of type `data.frame`,
and we supply it as an argument to `pmc()`:
```{r eval = FALSE}
# Convert the indicators to ordinal
df[] <- lapply(df, cut, breaks = 3, labels = FALSE)
df[] <- lapply(df, mxFactor, levels = 1:3)
res_cat <- mx_lca(df, classes = 1:3)
pmc(res_cat, reps = 20)
```
```{r eval = run_everything, echo = FALSE}
df[] <- lapply(df, cut, breaks = 3, labels = FALSE)
df[] <- lapply(df, mxFactor, levels = 1:3)
res_cat <- mx_lca(df, classes = 1:3)
chisq_function <- function(x, y){
tab_obs <- table(x)
tab_sim <- table(y)
tab_sim[tab_sim == 0] <- NA
sum((tab_obs - tab_sim)^2 / tab_sim, na.rm = TRUE)
}
res_pmc <- pmc(res_cat, reps = 20)
write.csv(res_pmc, "pmc_res_chi2.csv", row.names = FALSE)
```
```{r eval = TRUE, echo=FALSE}
res_pmc <- read.csv("pmc_res_chi2.csv", stringsAsFactors = FALSE)
class(res_pmc) <- c("pmc_df", "data.frame")
attr(res_pmc, "stat") <- "chi squared"
res_pmc
```
The argument `FUN` allows users to override these defaults, and specify any custom function to compare the observed data (`x`) and model-implied data (`y`).
## References
Van Lissa, C. J., Garnier-Villarreal, M., & Anadria, D. (2023).
*Recommended Practices in Latent Class Analysis using the Open-Source R-Package
tidySEM.* Structural Equation Modeling.
[https://doi.org/10.1080/10705511.2023.2250920](https://doi.org/10.1080/10705511.2023.2250920)