Skip to contents

sim_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 trt if it has more than two observed values. Values greater than or equal to trt_cut are coded 1. If trt already has exactly two observed values, the larger value is coded as 1 and trt_cut is 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" applies var_discretize() only when the pooled SIM has more than 12 observed levels. "yes" always applies var_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, call set.seed() before calling sim_mic_lcfa().

report_every

Integer. Print bootstrap progress every report_every attempted 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