How to specify a Latent Change Score Model with three variables and two timepoints

282 views Asked by At

For a research project, I'm currently trying to fit an LCSM to longitudinal data, using three variables that change over time (PM_event; PM_base; SP_total). All have been measured at two timepoints. The underlying dataset has six corresponding columns (PM_event_base, PM_event_fu etc.).

So far, this is the code I came up with, but lavaan keeps throwing a warning (and parameter estimates are completely unrealistic):

Warning message: In lavaan(lcm_1, data = data.full, estimator = "ML", missing = "FIML") : lavaan WARNING: the optimizer (NLMINB) claimed the model converged, but not all elements of the gradient are (near) zero; the optimizer may not have found a local solution use check.gradient = FALSE to skip this check.

Ideally, the model should predict the change between time 0 (baseline) and time 1 (follow up) based on baseline values.

E.g. the change in PM_event from baseline to follow-up should be predicted by baseline PM_event, baseline PM_time and baseline SP_total. Same for the other two variables.

Does anyone know what's going on here? This is my first time using lavaan, so sorry if it's an obvious one.

This is my code:

#define phantom endogeneous variables
#variance of phantom variables is 0 as all residual is accounted for in #exogeneous factor
PM_event_base_p =~ 1 * PM_event_base 
PM_event_base ~ 0
PM_event_base ~~ PM_event_base
PM_event_base_p ~~ 0* PM_event_base_p

PM_event_fu_p =~ 1 * PM_event_fu 
PM_event_fu ~ 0
PM_event_fu ~~ PM_event_fu
PM_event_fu_p ~~ 0*PM_event_fu_p

PM_time_base_p =~ 1 * PM_time_base
PM_time_base ~ 0
PM_time_base ~~ PM_time_base
PM_time_base_p ~~ 0*PM_time_base_p

PM_time_fu_p =~ 1 * PM_time_fu
PM_time_fu ~ 0
PM_time_fu ~~ PM_time_fu
PM_time_fu_p ~~ 0*PM_time_fu_p

SP_total_base_p =~ 1 * SP_total_base 
SP_total_base ~ 0 
SP_total_base ~~ SP_total_base
SP_total_base_p ~~ 0*SP_total_base_p

SP_total_fu_p =~ 1 * SP_total_fu
SP_total_fu ~ 0
SP_total_fu ~~ SP_total_fu;
SP_total_fu_p ~~ 0*SP_total_fu_p

#covariances of baseline scores
PM_time_base_p ~~ PM_event_base_p
PM_time_base_p ~~ SP_total_base_p
PM_event_base_p ~~ SP_total_base_p

#set regressions of adjacent timepoints to 1
PM_time_base_p ~ 1*PM_time_fu_p
PM_event_base_p ~ 1*PM_event_fu_p
SP_total_base_p ~ 1*SP_total_fu_p

#define latent change variables
delta_PM_event =~ 1*PM_event_base_p
delta_PM_time =~ 1*PM_time_base_p
delta_SP =~ 1*SP_total_p

#set variance of change scores to 0
#delta_PM_event ~~ 0*delta_PM_event
#delta_PM_time ~~ 0*delta_PM_time
#delta_SP ~~ 0*delta_SP

#regress latent change variables on baseline scores
delta_PM_event ~ PM_event_base_p + PM_time_base_p + SP_total_base_p
delta_PM_time ~ PM_event_base_p + PM_time_base_p + SP_total_base_p
delta_SP ~ PM_event_base_p + PM_time_base_p + SP_total_base_p

#covariances between change scores
delta_PM_event ~~ delta_PM_time
delta_PM_event ~~ delta_SP
delta_PM_time ~~ delta_SP

#define paths through time
#follow-up = baseline + delta
#already fully determined by the change score and baseline, so no regression coefficients included
PM_event_fu_p ~ 1* delta_PM_event + 1 * PM_event_base_p
PM_time_fu_p ~ 1* delta_PM_time + 1* PM_time_base_p
SP_total_fu_p ~ 1* delta_SP + 1* SP_total_base_p

#remove unwanted covariances
#these should not be needed as follow-up data is already fully determined by change scores
PM_event_fu_p ~~ 0*PM_time_fu_p
PM_event_fu_p ~~ 0* SP_total_fu_p
PM_time_fu_p ~~ 0*SP_total_fu_p`here

I have tried going over several tutorials (see below) on lcsm and have tried to adapt my syntax accordingly, but to no avail: https://longitudinalresearchinstitute.com/tutorials/chapter-17-multivariate-latent-change-score-models/ https://e-m-mccormick.github.io/static/longitudinal-primer/

1

There are 1 answers

0
JSK On

It took several edit runs and a few more tutorials but I wound up with code that does what it should (I think). I thought I just share the correct code on here:

SP_total_base_p =~ 1*SP_total_base  
SP_total_base_p ~ 1               
SP_total_base_p ~~ SP_total_base_p 
SP_total_base ~~ 0*SP_total_base  
SP_total_base ~ 0*1                 

SP_total_fu_p =~ 1*SP_total_fu     
SP_total_fu_p ~ 0*1                 
SP_total_fu_p ~~ 0*SP_total_fu      
SP_total_fu ~~ 0*SP_total_fu      
SP_total_fu ~ 0*1                 

SP_total_fu_p ~ 1*SP_total_base    

dSP_total_base =~ 1*SP_total_fu_p   
dSP_total_base ~~ dSP_total_base  
dSP_total_base ~ 1                


PM_event_base_p =~ 1*PM_event_base  
PM_event_base_p ~ 1               
PM_event_base_p ~~ PM_event_base_p 
PM_event_base ~~ 0*PM_event_base  
PM_event_base ~ 0*1                

PM_event_fu_p =~ 1*PM_event_fu    
PM_event_fu_p ~ 0*1                 
PM_event_fu_p ~~ 0*PM_event_fu     
PM_event_fu ~~ 0*PM_event_fu      
PM_event_fu ~ 0*1                 

PM_event_fu_p ~ 1*PM_event_base    

dPM_event_base =~ 1*PM_event_fu_p 
dPM_event_base ~~ dPM_event_base  
dPM_event_base ~ 1                

PM_time_base_p =~ 1*PM_time_base  
PM_time_base_p ~ 1               
PM_time_base_p ~~ PM_time_base_p 
PM_time_base ~~ 0*PM_time_base  
PM_time_base ~ 0*1                 

PM_time_fu_p =~ 1*PM_time_fu     
PM_time_fu_p ~ 0*1                 
PM_time_fu_p ~~ 0*PM_time_fu      
PM_time_fu ~~ 0*PM_time_fu      
PM_time_fu ~ 0*1                 

PM_time_fu_p ~ 1*PM_time_base    

dPM_time_base =~ 1*PM_time_fu_p   
dPM_time_base ~~ dPM_time_base  
dPM_time_base ~ 1               


dPM_event_base ~ SP_total_base_p + PM_time_base_p + PM_event_base_p   
dSP_total_base ~ PM_event_base_p + PM_time_base_p + SP_total_base_p   
dPM_time_base ~ PM_event_base_p + SP_total_base_p + PM_time_base_p   

SP_total_base_p ~~  PM_event_base_p                
SP_total_base_p ~~ PM_time_base_p
PM_event_base_p ~~ PM_time_base_p

dSP_total_base ~~ dPM_event_base             
dSP_total_base ~~ dPM_time_base
dPM_time_base ~~ dPM_event_base

For anyone struggling with this I can recommend the excellent introduction by: Kievit et al. (2018) https://doi.org/10.1016/j.dcn.2017.11.007