The hardware and bandwidth for this mirror is donated by dogado GmbH, the Webhosting and Full Service-Cloud Provider. Check out our Wordpress Tutorial.
If you wish to report a bug, or if you are interested in having us mirror your free-software or open-source project, please feel free to contact us at mirror[@]dogado.de.
This vignette illustrates slightly different data generation. specifically, we extend the data to two attributes/factors. This introduces additional complexity that should be addressed. This extension is the main focus. Second, we use only ordinal items, which allows us to demonstrate the use of the C2 fit statistic.
First load the CLCM package. Next, specify the data generation details. Here we generate 6 ordinal items, each with 4 categories (0, 1, 2, 3).
library(CLCM)
N <- 200
number.timepoints <- 1
item.type <- rep('Ordinal', 6)
categories.j <- rep(4, 6)
J <- length(item.type)
item.names <- paste0('Item_', 1:J)alpha, eta and Condensation
Rules - The Nitty GrittyNext, K is set to 2 to indicate 2 factors/attributes. The object
alpha is the relationship between the latent classes and
the attributes/factors.
Examine alpha:
#> Factor_1 Factor_2
#> Latent_Class_1 0 0
#> Latent_Class_2 1 0
#> Latent_Class_3 0 1
#> Latent_Class_4 1 1
The Q-matrix, which can be thought of as a factor-loading matrix, is a crucial part of the confirmatory latent class model. This pre-specified loading structure is what makes this a confirmatory approach. This Q-matrix contains 6 rows, 1 for each item, and 2 columns, 1 for each factor/attribute. Each items loads on only 1 factor. This is done for simplicity and to ensure the model is identified.
Examine the Q-matrix:
#> Factor_1 Factor_2
#> Item_1 1 0
#> Item_2 1 0
#> Item_3 1 0
#> Item_4 0 1
#> Item_5 0 1
#> Item_6 0 1
The eta object specifies the relationship between the
latent classes, alpha and the Q-matrix, Q.
This is referred to the literature as the Condensation Rule. Here the
conjunctive item condensation rule is implemented. See the literature
for more details.
Examine eta:
#> Item_1 Item_2 Item_3 Item_4 Item_5 Item_6
#> Latent_Class_1 0 0 0 0 0 0
#> Latent_Class_2 1 1 1 0 0 0
#> Latent_Class_3 0 0 0 1 1 1
#> Latent_Class_4 1 1 1 1 1 1
Broadly, the combination of the Q-matrix (and, when K>1, the condensation rules), dramatically reduces the number of parameters required to be estimated. This is of crucial importance, and should be highlighted: a substantial decrease in the number of parameters that are estimated is accomplished by the following:
Prespecifying which items load on which factors/attributes
Implementing the conjunctive condensation rule, where subjects are grouped into either Latent Class 0 or Latent Class 1 for each item.
eta specifies this grouping - for example, looking
at item 1, we can see that Latent classes 2 and 4 are set to 1, where as
latent classes 1 and 3 are set to 0:
#> Item_1
#> Latent_Class_1 0
#> Latent_Class_2 1
#> Latent_Class_3 0
#> Latent_Class_4 1
This means that, when estimating item j, the CLCM
reduces the 2^K = 4 latent classes into 2.
Why latent classes 2 and 4? Well, refer back to the Q-matrix
(Q) and alpha.
#> Factor_1 Factor_2
#> Item_1 1 0
#> Factor_1 Factor_2
#> Latent_Class_1 0 0
#> Latent_Class_2 1 0
#> Latent_Class_3 0 1
#> Latent_Class_4 1 1
We can see that the first row of the Q-matrix indicates that the
first item evaluates attribute/factor 1. Referring to the
alpha matrix, we can see that latent classes 2 and 4 are a
1 on attribute/factor 1. Thus, latent classes 2 and 4 are grouped
together for any item evaluating attribute/factor 1 by itself.
The final part to specify are the latent class proportions
lc.prop at the first (and only) timepoint. This is a
uniform distribution, where the subjects are distributed equally
throughout the latent classes.
The next step is to simulate data and briefly examine the item responses and posterior distributions.
set.seed(03062021)
X <- simulate_clcm(N = N, Q = Q, number.timepoints = number.timepoints,
item.type = item.type,
categories.j = categories.j,
lc.prop = lc.prop)
apply(X$item.responses, 2, table)
#> Item_1 Item_2 Item_3 Item_4 Item_5 Item_6
#> 0 21 36 32 35 39 38
#> 1 53 46 47 43 45 35
#> 2 67 53 66 68 58 60
#> 3 59 65 55 54 58 67
apply(X$item.responses, 2, function(x) prop.table(table(x)))
#> Item_1 Item_2 Item_3 Item_4 Item_5 Item_6
#> 0 0.105 0.180 0.160 0.175 0.195 0.190
#> 1 0.265 0.230 0.235 0.215 0.225 0.175
#> 2 0.335 0.265 0.330 0.340 0.290 0.300
#> 3 0.295 0.325 0.275 0.270 0.290 0.335
prop.table(table(apply(X$post, 1, which.max)))
#>
#> 1 2 3 4
#> 0.235 0.285 0.210 0.270Alright, we are all set to fit the CLCM to the data. We pass the dataframe containing the item responses, the item types, and the item names. Importantly, we also pass the Q-matrix, which specifies the relationship between the items and the attributes/factors. This implicitly also specifies the number of factors!
Next step is to estimate the model. Note the option
verbose = FALSE can be used to stop the function from
printing estimation progress.
mod1 <- clcm(dat = X$dat, max.diff = 0.001,
item.type = X$item.type,
item.names = X$item.names,
Q = X$Q)
#> iteration: 1 max diff in item parameter estimates: 1.697956
#> iteration: 2 max diff in item parameter estimates: 0.231256
#> iteration: 3 max diff in item parameter estimates: 0.158072
#> iteration: 4 max diff in item parameter estimates: 0.106419
#> iteration: 5 max diff in item parameter estimates: 0.077773
#> iteration: 6 max diff in item parameter estimates: 0.062811
#> iteration: 7 max diff in item parameter estimates: 0.052859
#> iteration: 8 max diff in item parameter estimates: 0.045653
#> iteration: 9 max diff in item parameter estimates: 0.039968
#> iteration: 10 max diff in item parameter estimates: 0.035197
#> iteration: 11 max diff in item parameter estimates: 0.031045
#> iteration: 12 max diff in item parameter estimates: 0.027366
#> iteration: 13 max diff in item parameter estimates: 0.024085
#> iteration: 14 max diff in item parameter estimates: 0.021156
#> iteration: 15 max diff in item parameter estimates: 0.018548
#> iteration: 16 max diff in item parameter estimates: 0.016233
#> iteration: 17 max diff in item parameter estimates: 0.014185
#> iteration: 18 max diff in item parameter estimates: 0.012468
#> iteration: 19 max diff in item parameter estimates: 0.01117
#> iteration: 20 max diff in item parameter estimates: 0.009996
#> iteration: 21 max diff in item parameter estimates: 0.008938
#> iteration: 22 max diff in item parameter estimates: 0.007988
#> iteration: 23 max diff in item parameter estimates: 0.007137
#> iteration: 24 max diff in item parameter estimates: 0.006375
#> iteration: 25 max diff in item parameter estimates: 0.005694
#> iteration: 26 max diff in item parameter estimates: 0.005087
#> iteration: 27 max diff in item parameter estimates: 0.005076
#> iteration: 28 max diff in item parameter estimates: 0.00451
#> iteration: 29 max diff in item parameter estimates: 0.004062
#> iteration: 30 max diff in item parameter estimates: 0.003242
#> iteration: 31 max diff in item parameter estimates: 0.002847
#> iteration: 32 max diff in item parameter estimates: 0.003364
#> iteration: 33 max diff in item parameter estimates: 0.002656
#> iteration: 34 max diff in item parameter estimates: 0.00283
#> iteration: 35 max diff in item parameter estimates: 0.001887
#> iteration: 36 max diff in item parameter estimates: 0.002293
#> iteration: 37 max diff in item parameter estimates: 0.002202
#> iteration: 38 max diff in item parameter estimates: 0.001651
#> iteration: 39 max diff in item parameter estimates: 0.001949
#> iteration: 40 max diff in item parameter estimates: 0.002198
#> iteration: 41 max diff in item parameter estimates: 0.001291
#> iteration: 42 max diff in item parameter estimates: 0.002152
#> iteration: 43 max diff in item parameter estimates: 0.000693For comparison, let’s also fit a misspecified model with only 2 latent classes instead of 4. First we specify the Q-matrix, which is just a single column of ones, and then we fit the model.
Q_2 <- matrix(1, nrow = J, ncol = 1)
mod2 <- clcm(dat = X$dat, max.diff = 0.001,
item.type = X$item.type,
item.names = X$item.names,
Q = Q_2)
#> iteration: 1 max diff in item parameter estimates: 1.808699
#> iteration: 2 max diff in item parameter estimates: 0.213192
#> iteration: 3 max diff in item parameter estimates: 0.13506
#> iteration: 4 max diff in item parameter estimates: 0.127485
#> iteration: 5 max diff in item parameter estimates: 0.140938
#> iteration: 6 max diff in item parameter estimates: 0.139188
#> iteration: 7 max diff in item parameter estimates: 0.133497
#> iteration: 8 max diff in item parameter estimates: 0.118784
#> iteration: 9 max diff in item parameter estimates: 0.100016
#> iteration: 10 max diff in item parameter estimates: 0.081611
#> iteration: 11 max diff in item parameter estimates: 0.065912
#> iteration: 12 max diff in item parameter estimates: 0.053485
#> iteration: 13 max diff in item parameter estimates: 0.043981
#> iteration: 14 max diff in item parameter estimates: 0.036764
#> iteration: 15 max diff in item parameter estimates: 0.031894
#> iteration: 16 max diff in item parameter estimates: 0.030385
#> iteration: 17 max diff in item parameter estimates: 0.028981
#> iteration: 18 max diff in item parameter estimates: 0.027584
#> iteration: 19 max diff in item parameter estimates: 0.026161
#> iteration: 20 max diff in item parameter estimates: 0.024728
#> iteration: 21 max diff in item parameter estimates: 0.023303
#> iteration: 22 max diff in item parameter estimates: 0.021836
#> iteration: 23 max diff in item parameter estimates: 0.020443
#> iteration: 24 max diff in item parameter estimates: 0.019166
#> iteration: 25 max diff in item parameter estimates: 0.018129
#> iteration: 26 max diff in item parameter estimates: 0.017103
#> iteration: 27 max diff in item parameter estimates: 0.016097
#> iteration: 28 max diff in item parameter estimates: 0.015041
#> iteration: 29 max diff in item parameter estimates: 0.014166
#> iteration: 30 max diff in item parameter estimates: 0.013194
#> iteration: 31 max diff in item parameter estimates: 0.012391
#> iteration: 32 max diff in item parameter estimates: 0.011476
#> iteration: 33 max diff in item parameter estimates: 0.010816
#> iteration: 34 max diff in item parameter estimates: 0.009972
#> iteration: 35 max diff in item parameter estimates: 0.010168
#> iteration: 36 max diff in item parameter estimates: 0.008686
#> iteration: 37 max diff in item parameter estimates: 0.008045
#> iteration: 38 max diff in item parameter estimates: 0.007397
#> iteration: 39 max diff in item parameter estimates: 0.006784
#> iteration: 40 max diff in item parameter estimates: 0.006232
#> iteration: 41 max diff in item parameter estimates: 0.005856
#> iteration: 42 max diff in item parameter estimates: 0.005482
#> iteration: 43 max diff in item parameter estimates: 0.005055
#> iteration: 44 max diff in item parameter estimates: 0.004787
#> iteration: 45 max diff in item parameter estimates: 0.004225
#> iteration: 46 max diff in item parameter estimates: 0.002742
#> iteration: 47 max diff in item parameter estimates: 0.004882
#> iteration: 48 max diff in item parameter estimates: 0.003592
#> iteration: 49 max diff in item parameter estimates: 0.003284
#> iteration: 50 max diff in item parameter estimates: 0.002952
#> iteration: 51 max diff in item parameter estimates: 0.002782
#> iteration: 52 max diff in item parameter estimates: 0.001804
#> iteration: 53 max diff in item parameter estimates: 0.003024
#> iteration: 54 max diff in item parameter estimates: 0.002244
#> iteration: 55 max diff in item parameter estimates: 0.001642
#> iteration: 56 max diff in item parameter estimates: 0.002523
#> iteration: 57 max diff in item parameter estimates: 0.00199
#> iteration: 58 max diff in item parameter estimates: 0.002158
#> iteration: 59 max diff in item parameter estimates: 0.001739
#> iteration: 60 max diff in item parameter estimates: 0.002093
#> iteration: 61 max diff in item parameter estimates: 0.002012
#> iteration: 62 max diff in item parameter estimates: 0.00155
#> iteration: 63 max diff in item parameter estimates: 0.000674First, compute the absolute fit statistic, C2. Note that this is slow - not run in this vignette.
The C2 statistic is expected to fail to reject the first model (correctly specified) and reject the second model (incorrectly specified).
Second, compute the relative fit statistics, AIC & BIC:
mod.fit.rel.1 <- aic_bic_clcm(mod1)
mod.fit.rel.2 <- aic_bic_clcm(mod2)
unlist(mod.fit.rel.1)
#> neg_2LL npar AIC BIC
#> 3175.487 27.000 3229.487 3318.542
unlist(mod.fit.rel.2)
#> neg_2LL npar AIC BIC
#> 3204.255 25.000 3254.255 3336.713As we would expect, the incorrectly specified model (
mod2) has the larger AIC and BIC values.
Finally, use the correctly specified model (mod1) and
compare the true classifications with estimates:
lca.hat <- mod1$dat$lca
lca.true <- mod1$dat$true_lca
table(lca.true == lca.hat)
#>
#> FALSE TRUE
#> 75 125
prop.table(table(lca.true == lca.hat))
#>
#> FALSE TRUE
#> 0.375 0.625
xtabs( ~ lca.true + lca.hat)
#> lca.hat
#> lca.true 1 2 3 4
#> 1 17 8 17 5
#> 2 0 38 1 18
#> 3 1 0 30 11
#> 4 0 4 10 40We can see that the classification accuracy tends to decrease as additional latent classes are added. This makes sense, given that the probability of randomly assigning a subject to the correct latent class decreases as the number of classes increases.
These binaries (installable software) and packages are in development.
They may not be fully stable and should be used with caution. We make no claims about them.
Health stats visible at Monitor.