
Longitudinal confirmatory factor analysis-based MIC for a Single-Item Measure
Source:R/sim_mic_lcfa.R
sim_mic_lcfa.Rdsim_mic_lcfa() estimates the minimal important change (MIC) for a
single-item measure (SIM) using longitudinal confirmatory factor analysis (LCFA)
with an auxiliary variable. The SIM is measured
at Time 1 and Time 2, an auxiliary variable is measured at Time 1 and Time 2,
and a transition rating is included as an anchor.
Usage
sim_mic_lcfa(
mydata,
sim,
aux,
trt,
trt_cut = 1,
sim_levels = 10L,
sim_discretize = c("auto", "yes", "no"),
min_resp = 1L,
aux_ordered = FALSE,
B = 0L,
report_every = 50L,
add_lmodel = NULL,
print_model = FALSE,
verbose = FALSE,
...
)Arguments
- mydata
Data frame.
- sim
Character vector of length 2. Names of the SIM variable at Time 1 and Time 2.
- aux
Character vector of length 2. Names of the auxiliary variable at Time 1 and Time 2.
- trt
Character. Name of the transition rating / anchor variable.
- trt_cut
Numeric. Cutpoint used to binarize
trtif it has more than two observed values. Values greater than or equal totrt_cutare coded 1. Iftrtalready has exactly two observed values, the larger value is coded as 1 andtrt_cutis ignored.- sim_levels
Integer. Number of ordered levels used when discretizing the SIM with
var_discretize(). Must be between 2 and 12. Default is 10.- sim_discretize
Character. One of
"auto","yes", or"no"."auto"appliesvar_discretize()only when the pooled SIM has more than 12 observed levels."yes"always appliesvar_discretize()."no"never discretizes and errors if the pooled SIM has more than 12 observed levels.- min_resp
Integer. Minimum response count per category used by
equalize_levels()when equalizing SIM response levels across time.- aux_ordered
Logical. If
TRUE, treats the auxiliary variables as ordered indicators in lavaan. Auxiliary variable loadings and thresholds are freely estimated over time.- B
Integer. Number of nonparametric bootstrap samples. Bootstrap confidence intervals are computed only when
B >= 100.For reproducible simulations or bootstrap confidence intervals, callset.seed()before callingsim_mic_lcfa().- report_every
Integer. Print bootstrap progress every
report_everyattempted bootstrap fits.- add_lmodel
Optional lavaan syntax appended to the generated model.
- print_model
Logical. If
TRUE, prints the generated lavaan model.- verbose
Logical. If
TRUE, prints progress messages.- ...
Additional arguments passed to
lavaan::cfa().
Value
A sim_mic_lcfa object with elements including:
MIC.theta: MIC on the latent-change scale;MIC.sim.transformed: MIC on the transformed SIM scale;MIC.sim: MIC on the original SIM metric;rel_SIM1: model R-squared / reliability of SIM at Time 1;rel_trt: model R-squared / reliability of the transition rating;psb: estimated present-state bias;ci: bootstrap confidence intervals, if requested;sim_prepared: information about discretization, equalization, and back-transformation.
Details
If the pooled SIM values across Time 1 and Time 2 have 12 or fewer observed
levels, the original SIM values are used as ordered categories. If the pooled
SIM values have more than 12 observed levels, the SIM is discretized using
var_discretize() with common equal-width bins across Time 1 and Time 2.
In both cases, SIM response levels are equalized across time before fitting
the LCFA model.
The SIM loading and SIM thresholds are constrained equal over time so that the Time 1 and Time 2 latent factors are on the same measurement scale.
The latent MIC is estimated as MIC.theta = tau_trt / f2, where tau_trt is
the transition-rating threshold and f2 is the transition-rating loading on
the Time 2 factor.
The SIM-scale MIC is first calculated on the transformed SIM scale as
sqrt(var(SIM_T1_transformed) * Rel_SIM_T1) * MIC.theta, where
Rel_SIM_T1 is the model R-squared of the Time 1 SIM. If var_discretize()
is used, the transformed-scale MIC is then back-transformed to the original
SIM metric using the equal-width bin width.
Continuous SIMs with many distinct values are not used directly as ordered
indicators. When discretization is needed, sim_mic_lcfa() applies
var_discretize() to the pooled Time 1 and Time 2 SIM values. This ensures
that the same equal-width binning rule is applied at both time points.
The LCFA model is fitted to the discretized/equalized ordered SIM variables.
Therefore, the reliability of the SIM, Rel_SIM_T1, is the reliability of
the transformed SIM used in the CFA model. For this reason, the SIM MIC is
first computed on the transformed SIM scale:
MIC_SIM_transformed = sqrt(var(SIM_T1_transformed) * Rel_SIM_T1) * MIC.theta.
If discretization was used, this transformed-scale MIC is then converted back to the original SIM metric using:
MIC_SIM_original = MIC_SIM_transformed * backtransform_factor,
where backtransform_factor is the equal-width bin width, calculated as the
pooled original SIM range divided by the number of requested discretized
levels. If no discretization is used, backtransform_factor = 1.
References
Terluin B, Pua YH, Fromy P, Trigg A, van der Zwaard B, Bjorner JB. Estimating the minimal important change of single-item measures using the adjusted predictive modeling method or the longitudinal confirmatory factor analysis method. Quality of Life Research. 2026. doi:10.1007/s11136-025-04134-3
Terluin B, Trigg A, Fromy P, Schuller W, Terwee CB, Bjorner JB. Estimating anchor-based minimal important change using longitudinal confirmatory factor analysis. Qual Life Res. 2024;33:963-973. doi:10.1007/s11136-023-03577-w
Examples
set.seed(123)
sim <- simdat(N = 500, add_change = TRUE)
dat <- sim$datw
# Create a toy single-item measure from several items
dat$sim_t1 <- rowSums(dat[, paste0("item", 1:8), drop = FALSE])
dat$sim_t2 <- rowSums(dat[, paste0("item", 1:8, ".1"), drop = FALSE])
out <- sim_mic_lcfa(
mydata = dat,
sim = c("sim_t1", "sim_t2"),
aux = c("item9", "item9.1"),
trt = "trat",
sim_discretize = "auto",
sim_levels = 10,
aux_ordered = TRUE,
B = 0,
print_model = TRUE
)
#>
#> ================ SIM MIC LCFA MODEL ================
#>
#> # Factors
#> F1 =~ a_sim*SIM1 + aux1 + f1*trt
#> F2 =~ a_sim*SIM2 + aux2 + f2*trt
#>
#> # Equal SIM thresholds over time
#> SIM1 | b1*t1 + b2*t2 + b3*t3 + b4*t4 + b5*t5 + b6*t6 + b7*t7 + b8*t8 + b9*t9
#> SIM2 | b1*t1 + b2*t2 + b3*t3 + b4*t4 + b5*t5 + b6*t6 + b7*t7 + b8*t8 + b9*t9
#>
#> # Correlated residuals over time
#> SIM1 ~~ SIM2
#> aux1 ~~ aux2
#>
#> # Variances/covariances
#> F1 ~~ 1*F1
#> F2 ~~ NA*F2 + var_F2*F2
#> F1 ~~ cov_F1F2*F2
#>
#> # Free residual variance of SIM2 under theta parameterization
#> SIM2 ~~ NA*SIM2
#>
#> # Means
#> F1 ~ 0*1
#> F2 ~ mn_ch*1
#>
#> # Transition-rating threshold
#> trt | tau_trt*t1
#>
#> # Derived values
#> mn_change := mn_ch
#> sd_change := sqrt(1 + var_F2 - 2*cov_F1F2)
#> MIC.theta := tau_trt / f2
#> psb := f1 / f2 + 1
#>
#> ====================================================
out
#> LCFA-based MIC for a single-item measure
#> ----------------------------------------
#> MIC theta: 0.369
#> MIC SIM, transformed scale: 0.835
#> MIC SIM, original scale: 2.004
#> Reliability SIM T1: 0.854
#> Reliability transition rating: 0.727
#> Present-state bias: 0.015
#> Mean latent change: 0.282
#> SD latent change: 0.991
#> Discretization used: TRUE
#> Back-transform factor: 2.400
#>
#> Fit measures
#> ------------
#> cfi.scaled tli.scaled rmsea.scaled srmr
#> 1.000 1.002 0.000 0.012
# Inspect how the SIM was prepared
out$sim_prepared$used_discretization
#> [1] TRUE
out$sim_prepared$backtransform_factor
#> [1] 2.4
out$sim_prepared$original_levels
#> [1] 1 2 3 4 5 6 7 8 9 10