library(CLCM)
N <- 80
item.type <- c('Ordinal', 'Nominal', 'Poisson', 'Neg_Binom', 'ZINB', 'ZIP', 'Normal', 'Beta')
sim.categories.j <- c(4, 4, 30, 30, 30, 30, NA, NA)
J <- length(item.type)
item.names <- paste0('Item_', 1:J)
Q <- matrix(1, nrow = length(item.type), ncol = 1, dimnames = list(paste0('Item_', 1:length(item.type)), NULL))
K= ncol(Q) The next step is to specify the posterior distribution proportions
that will be generated. Here we specify the latent class proportions at
Timepoint 1, and the transition matrix, tau. This is
sufficient to completely specify the latent class assignment of each
subject at each timepoint.
Pass everything to the simulate_clcm() function and
generate the item responses:
Estimate the latent class model, using the correct Q-matrix. The data
is in long format and has a variable Time, a factor with
two levels, Time_1 and Time_2 to distinguish
timepoints.
mod1 <- clcm(dat = sim.dat$dat,
item.type = sim.dat$item.type,
item.names = sim.dat$item.names,
Q = sim.dat$Q,
max.diff = 0.001)
#> iteration: 1 max diff in item parameter estimates: 4.161119
#> iteration: 2 max diff in item parameter estimates: 2.653271
#> iteration: 3 max diff in item parameter estimates: 1.111018
#> iteration: 4 max diff in item parameter estimates: 0.718995
#> iteration: 5 max diff in item parameter estimates: 0.105633
#> iteration: 6 max diff in item parameter estimates: 0.001951
#> iteration: 7 max diff in item parameter estimates: 0.000112We are going to compare this model to a second model with a constraint imposed on the latent classes. However, before do that, let’s quickly examine the transition matrix and the classification accuracy.
Check the classification accuracy of this model comparing the true/generating latent class assignments (lca) to the estimated lca.
Estimate mod2, this time with the first latent class
constrained to equal zero at timepoint 1. This is done through the use
of the lc.con function call.
mod2 <- clcm(dat = sim.dat$dat,
lc.con = list('Time_1' = c(NA, 1), 'Time_2' = c(1, 1)),
item.type = sim.dat$item.type,
item.names = sim.dat$item.names,
Q = sim.dat$Q,
max.diff = 0.001)
#> iteration: 1 max diff in item parameter estimates: 5.285171
#> iteration: 2 max diff in item parameter estimates: 4.131888
#> iteration: 3 max diff in item parameter estimates: 0.479707
#> iteration: 4 max diff in item parameter estimates: 0.001841
#> iteration: 5 max diff in item parameter estimates: 6.9e-05Check the model fit of the second model, which has one fewer parameter estimated compared to mod1.
unlist( aic_bic_clcm(mod = mod1) )
#> neg_2LL npar AIC BIC
#> 3940.353 30.000 4000.353 4092.608
unlist( aic_bic_clcm(mod = mod2) )
#> neg_2LL npar AIC BIC
#> 3940.353 29.000 3998.353 4087.533We can see that imposing the constraint yields slightly lower AIC/BIC values. Hence, we keep the constraint.
Examine the transition matrix as well.
transition_matrix_clcm(mod = mod1)
#> post_LC_0 post_LC_1
#> post_LC_0 0.007247412 0.9927526
#> post_LC_1 0.274893948 0.7251061
transition_matrix_clcm(mod = mod2)
#> post_LC_0 post_LC_1
#> post_LC_0 NaN NaN
#> post_LC_1 0.2748942 0.7251058Compare the true classifications with the estimates from Model 2, with constraint imposed:
lca.hat <- mod2$dat$lca
lca.true <- mod2$dat$true_lca
table(lca.true == lca.hat)
#>
#> TRUE
#> 160
prop.table(table(lca.true == lca.hat))
#>
#> TRUE
#> 1
xtabs( ~ lca.true + lca.hat)
#> lca.hat
#> lca.true 1 2
#> 1 22 0
#> 2 0 138Classification accuracy is high: hypothesize that this is due to the relatively few number of latent classes, the relatively large number of items per latent classes estimated, and the fact that we fit a correctly specified model with a correctly specified Q-matrix. Overall ideal model fitting scenario, even with only n=80.
More full simulation studies should dig into this!