Skip to contents

We generate data using the CULTA model with two latent profiles, where profile membership depends on a covariate and profile transitions follow a multinomial structure. However, for model fitting, we impose a simpler structure by fitting a CUTS (1 Profile) model with autoregressive effects, ignoring the latent profiles during estimation. We then compare this misspecified model to the correctly specified two-profile CULTA model.

Data Generation

# complete list of R function arguments

# random seed for reproducibility
set.seed(42)

# dimensions
n # number of individuals
#> [1] 10000
m # measurement occasions
#> [1] 6
p # number of items
#> [1] 4
q # common trait dimension
#> [1] 1

# covariate parameters
mu_x 
#> [1] 11.4009
sigma_x
#> [1] 24.67566

# profile membership and transition parameters
nu_0
#> [1] -3.563
kappa_0
#> [1] 0.122
alpha_0
#> [1] -3.586
beta_00
#> [1] 2.25
gamma_00
#> [1] 0.063
gamma_10
#> [1] 0.094

# trait parameters
psi_t
#>      [,1]
#> [1,]  0.1
mu_t
#> [1] 0
psi_p
#>      [,1] [,2] [,3] [,4]
#> [1,]  0.1  0.0  0.0  0.0
#> [2,]  0.0  0.1  0.0  0.0
#> [3,]  0.0  0.0  0.5  0.0
#> [4,]  0.0  0.0  0.0  0.5
mu_p
#> [1] 0 0 0 0
common_trait_loading
#>      [,1]
#> [1,]    1
#> [2,]    1
#> [3,]    1
#> [4,]    1

# state parameters
common_state_loading
#>      [,1]
#> [1,]    1
#> [2,]    1
#> [3,]    1
#> [4,]    1
phi_0
#> [1] 0
phi_1
#> [1] 0.311
psi_s0
#> [1] 1
psi_s
#> [1] 0.25
theta
#>      [,1] [,2] [,3] [,4]
#> [1,] 0.15 0.00 0.00 0.00
#> [2,] 0.00 0.15 0.00 0.00
#> [3,] 0.00 0.00 0.15 0.00
#> [4,] 0.00 0.00 0.00 0.15

# profile-specific means
mu_profile
#>       [,1]   [,2]
#> [1,] 2.253 -0.278
#> [2,] 1.493 -0.165
#> [3,] 1.574 -0.199
#> [4,] 1.117 -0.148
data <- GenCULTA2Profiles(
  n = n,
  m = m,
  mu_x = mu_x,
  sigma_x = sigma_x,
  nu_0 = nu_0,
  kappa_0 = kappa_0,
  alpha_0 = alpha_0,
  beta_00 = beta_00,
  gamma_00 = gamma_00,
  gamma_10 = gamma_10,
  mu_t = mu_t,
  psi_t = psi_t,
  mu_p = mu_p,
  psi_p = psi_p,
  common_trait_loading = common_trait_loading,
  common_state_loading = common_state_loading,
  phi_0 = phi_0,
  phi_1 = phi_1,
  psi_s0 = psi_s0,
  psi_s = psi_s,
  theta = theta, 
  mu_profile = mu_profile
)

Model Fitting

The FitCULTA1Profiles function fits the misspecified one-profile model using Mplus. Note: This function requires that Mplus is already installed on the system.

one_profile <- FitCULTA1Profile(data = data)

The FitCULTA2Profiles function fits the correct two-profile model using Mplus. Note: This function requires that Mplus is already installed on the system. To speed up model fitting, consider using the ncores argument to leverage multiple cores.

two_profiles <- FitCULTA2Profiles(data = data)

Model Comparison

The anova function can be used to compare the two fitted models.

anova(one_profile, two_profiles)
#> $fit
#>                    logLik df correction      AIC      BIC     aBIC   entropy
#> 1-profile CULTA -246042.9 22   1.083395 492129.8 492288.5 492218.5 0.0000000
#> 2-profile CULTA -237508.2 33   1.000768 475082.4 475320.3 475215.5 0.9367669
#> 
#> $test
#> chi_diff  df_diff  p_value 
#> 20429.88    11.00     0.00

Mplus Script Used

The one-profile model was estimated using the following Mplus script.

TITLE:
  CUTS with AR;

DATA:
  FILE = cutsar_data.dat;

VARIABLE:
  NAMES =
    id
    x
    y1t0
    y2t0
    y3t0
    y4t0
    y1t1
    y2t1
    y3t1
    y4t1
    y1t2
    y2t2
    y3t2
    y4t2
    y1t3
    y2t3
    y3t3
    y4t3
    y1t4
    y2t4
    y3t4
    y4t4
    y1t5
    y2t5
    y3t5
    y4t5
  ;
  USEVARIABLES =
    y1t0
    y2t0
    y3t0
    y4t0
    y1t1
    y2t1
    y3t1
    y4t1
    y1t2
    y2t2
    y3t2
    y4t2
    y1t3
    y2t3
    y3t3
    y4t3
    y1t4
    y2t4
    y3t4
    y4t4
    y1t5
    y2t5
    y3t5
    y4t5
  ;

ANALYSIS:
  TYPE = GENERAL;
  ESTIMATOR = MLR;
  STARTS = 10;
  MODEL = NOCOV;

MODEL:
  ! common trait ------------------------------------------------------

  !! factor loadings
  !!! t = 0
  t BY y1t0@1;
  t BY y2t0 (lambdat2);
  t BY y3t0 (lambdat3);
  t BY y4t0 (lambdat4);
  !!! t = 1
  t BY y1t1@1;
  t BY y2t1 (lambdat2);
  t BY y3t1 (lambdat3);
  t BY y4t1 (lambdat4);
  !!! t = 2
  t BY y1t2@1;
  t BY y2t2 (lambdat2);
  t BY y3t2 (lambdat3);
  t BY y4t2 (lambdat4);
  !!! t = 3
  t BY y1t3@1;
  t BY y2t3 (lambdat2);
  t BY y3t3 (lambdat3);
  t BY y4t3 (lambdat4);
  !!! t = 4
  t BY y1t4@1;
  t BY y2t4 (lambdat2);
  t BY y3t4 (lambdat3);
  t BY y4t4 (lambdat4);
  !!! t = 5
  t BY y1t5@1;
  t BY y2t5 (lambdat2);
  t BY y3t5 (lambdat3);
  t BY y4t5 (lambdat4);

  !! latent mean
  [ t@0 ];

  !! latent variance
  t (psit);

  ! unique traits -----------------------------------------------------

  !! factor loadings
  !!! k = 1
  u1 BY y1t0@1;
  u1 BY y1t1@1;
  u1 BY y1t2@1;
  u1 BY y1t3@1;
  u1 BY y1t4@1;
  u1 BY y1t5@1;
  !!! k = 2
  u2 BY y2t0@1;
  u2 BY y2t1@1;
  u2 BY y2t2@1;
  u2 BY y2t3@1;
  u2 BY y2t4@1;
  u2 BY y2t5@1;
  !!! k = 3
  u3 BY y3t0@1;
  u3 BY y3t1@1;
  u3 BY y3t2@1;
  u3 BY y3t3@1;
  u3 BY y3t4@1;
  u3 BY y3t5@1;
  !!! k = 4
  u4 BY y4t0@1;
  u4 BY y4t1@1;
  u4 BY y4t2@1;
  u4 BY y4t3@1;
  u4 BY y4t4@1;
  u4 BY y4t5@1;

  !! latent means
  [ u1@0 ];
  [ u2@0 ];
  [ u3@0 ];
  [ u4@0 ];

  !! latent variances
  u1 (psip1);
  u2 (psip2);
  u3 (psip3);
  u4 (psip4);

  ! common states -----------------------------------------------------

  !! factor loadings
  !!! t = 0
  s0 BY y1t0@1;
  s0 BY y2t0 (lambdas2);
  s0 BY y3t0 (lambdas3);
  s0 BY y4t0 (lambdas4);
  !!! t = 1
  s1 BY y1t1@1;
  s1 BY y2t1 (lambdas2);
  s1 BY y3t1 (lambdas3);
  s1 BY y4t1 (lambdas4);
  !!! t = 2
  s2 BY y1t2@1;
  s2 BY y2t2 (lambdas2);
  s2 BY y3t2 (lambdas3);
  s2 BY y4t2 (lambdas4);
  !!! t = 3
  s3 BY y1t3@1;
  s3 BY y2t3 (lambdas2);
  s3 BY y3t3 (lambdas3);
  s3 BY y4t3 (lambdas4);
  !!! t = 4
  s4 BY y1t4@1;
  s4 BY y2t4 (lambdas2);
  s4 BY y3t4 (lambdas3);
  s4 BY y4t4 (lambdas4);
  !!! t = 5
  s5 BY y1t5@1;
  s5 BY y2t5 (lambdas2);
  s5 BY y3t5 (lambdas3);
  s5 BY y4t5 (lambdas4);

  !! latent means
  [ s0@0 ];
  [ s1@0 ];
  [ s2@0 ];
  [ s3@0 ];
  [ s4@0 ];
  [ s5@0 ];

  !! latent variance of s0
  s0 (psis0);

  !! variance of the process noise
  s1 (psis);
  s2 (psis);
  s3 (psis);
  s4 (psis);
  s5 (psis);

  ! unique states -----------------------------------------------------

  !! variances
  !!! t = 0
  y1t0 (theta11);
  y2t0 (theta22);
  y3t0 (theta33);
  y4t0 (theta44);
  !!! t = 1
  y1t1 (theta11);
  y2t1 (theta22);
  y3t1 (theta33);
  y4t1 (theta44);
  !!! t = 2
  y1t2 (theta11);
  y2t2 (theta22);
  y3t2 (theta33);
  y4t2 (theta44);
  !!! t = 3
  y1t3 (theta11);
  y2t3 (theta22);
  y3t3 (theta33);
  y4t3 (theta44);
  !!! t = 4
  y1t4 (theta11);
  y2t4 (theta22);
  y3t4 (theta33);
  y4t4 (theta44);
  !!! t = 5
  y1t5 (theta11);
  y2t5 (theta22);
  y3t5 (theta33);
  y4t5 (theta44);

  ! grand means -------------------------------------------------------

  !! t = 0
  [ y1t0 ] (mu1);
  [ y2t0 ] (mu2);
  [ y3t0 ] (mu3);
  [ y4t0 ] (mu4);
  !! t = 1
  [ y1t1 ] (mu1);
  [ y2t1 ] (mu2);
  [ y3t1 ] (mu3);
  [ y4t1 ] (mu4);
  !! t = 2
  [ y1t2 ] (mu1);
  [ y2t2 ] (mu2);
  [ y3t2 ] (mu3);
  [ y4t2 ] (mu4);
  !! t = 3
  [ y1t3 ] (mu1);
  [ y2t3 ] (mu2);
  [ y3t3 ] (mu3);
  [ y4t3 ] (mu4);
  !! t = 4
  [ y1t4 ] (mu1);
  [ y2t4 ] (mu2);
  [ y3t4 ] (mu3);
  [ y4t4 ] (mu4);
  !! t = 5
  [ y1t5 ] (mu1);
  [ y2t5 ] (mu2);
  [ y3t5 ] (mu3);
  [ y4t5 ] (mu4);

  ! inertia -----------------------------------------------------------

  s0 ON s1 (phi);
  s1 ON s2 (phi);
  s2 ON s3 (phi);
  s3 ON s4 (phi);
  s4 ON s5 (phi);

MODEL CONSTRAINT:
  ! variance constraints
  psit > 0;
  psip1 > 0;
  psip2 > 0;
  psip3 > 0;
  psip4 > 0;
  psis0 > 0;
  psis > 0;
  theta11 > 0;
  theta22 > 0;
  theta33 > 0;
  theta44 > 0;

OUTPUT:
  TECH1
  TECH3
  TECH4;

SAVEDATA:
  ESTIMATES = cutsar_TBpjfDc7G4UC5Z7eY3PN_estimates.dat;
  RESULTS = cutsar_TBpjfDc7G4UC5Z7eY3PN_results.dat;
  TECH3 = cutsar_TBpjfDc7G4UC5Z7eY3PN_tech3.dat;
  TECH4 = cutsar_TBpjfDc7G4UC5Z7eY3PN_tech4.dat;