Below you can find the code for installing and loading the required
package `lavaan`

(Rosseel
2012), as well as for reading in the data for the Random
Intercept Cross-Lagged Panel Model (RI-CLPM) and its 3 extensions. You
can specify the path to the data yourself, or through a menu by using
the `file.choose()`

-function. You can download the simulated
example datasets here.

```
# If necessary, install the 'Lavaan' package.
# install.packages('lavaan', dependencies = T)
# Load the required packages.
require(lavaan)
# Load in the data.
## Traditional RI-CLPM
dat <- read.table("/Users/jeroenmulder/Git/RICLPM/data/RICLPM.dat",
col.names = c("x1", "x2", "x3", "x4", "x5", "y1", "y2", "y3", "y4", "y5"))
## Extension 1
datZ <- read.table("C:\\Users\\5879167\\Documents\\GitHub\\RI-CLPM\\data\\RICLPM-Z.dat",
col.names = c("x1", "x2", "x3", "x4", "x5", "y1", "y2", "y3", "y4", "y5", "z2", "z1"))
## Extension 2
datMG <- read.table("/Users/jeroenmulder/Git/RICLPM/data/RICLPM-MG.dat",
col.names = c("x1", "x2", "x3", "x4", "x5", "y1", "y2", "y3", "y4", "y5", "G"))
## Extension 3
datMI <- read.table("/Users/jeroenmulder/GitHub/RI-CLPM/data/RICLPM-MI.dat",
col.names = c("x11", "x12", "x13",
"x21", "x22", "x23",
"x31", "x32", "x33",
"x41", "x42", "x43",
"x51", "x52", "x53",
"y11", "y12", "y13",
"y21", "y22", "y23",
"y31", "y32", "y33",
"y41", "y42", "y43",
"y51", "y52", "y53"))
```

To specify the RI-CLPM we need four parts.

- A
*between part*, consisting of the random intercepts. It is specified using the`=~`

command,`RIx =~ 1*x1 1*x2 ...`

, where`1*`

fixes the factor loading to one. - A
*within part*, consisting of within-unit fluctuations. It is also specified using the`=~`

command,`wx1 =~ 1*x1; wx2 =~ 1*x2; ...`

. - The
*lagged regressions*between the within-unit components, using`wx2 ~ wx1 wy1; wx3 ~ wx2 wy2; ...`

. - Relevant
*covariances*in both the between and within part. In the within part the components at wave 1, and their residuals at waves 2 and further are correlated within each wave, using`wx1 ~~ wy1; wx2 ~~ wy2;...`

. We also need to specify their (residual) variances here using`wx1 ~~ wx1; wx2 ~~ wx2; ...`

. For the between part we have to specify the variances and covariance of the random intercepts using`RIx ~~ RIy;`

.

Note that the models below are fitted using the `lavaan()`

function. Other functions for fitting SEM models using
`lavaan`

include `sem()`

and `cfa()`

.
These functions rely on different defaults than `lavaan()`

and fitting the below models with these functions can result in model
misspecification and subsequently convergence issues.

The code for specifying the basic RI-CLPM is given below.

```
RICLPM <- '
# Create between components (random intercepts)
RIx =~ 1*x1 + 1*x2 + 1*x3 + 1*x4 + 1*x5
RIy =~ 1*y1 + 1*y2 + 1*y3 + 1*y4 + 1*y5
# Create within-person centered variables
wx1 =~ 1*x1
wx2 =~ 1*x2
wx3 =~ 1*x3
wx4 =~ 1*x4
wx5 =~ 1*x5
wy1 =~ 1*y1
wy2 =~ 1*y2
wy3 =~ 1*y3
wy4 =~ 1*y4
wy5 =~ 1*y5
# Estimate the lagged effects between the within-person centered variables.
wx2 + wy2 ~ wx1 + wy1
wx3 + wy3 ~ wx2 + wy2
wx4 + wy4 ~ wx3 + wy3
wx5 + wy5 ~ wx4 + wy4
# Estimate the covariance between the within-person centered variables at the first wave.
wx1 ~~ wy1 # Covariance
# Estimate the covariances between the residuals of the within-person centered variables (the innovations).
wx2 ~~ wy2
wx3 ~~ wy3
wx4 ~~ wy4
wx5 ~~ wy5
# Estimate the variance and covariance of the random intercepts.
RIx ~~ RIx
RIy ~~ RIy
RIx ~~ RIy
# Estimate the (residual) variance of the within-person centered variables.
wx1 ~~ wx1 # Variances
wy1 ~~ wy1
wx2 ~~ wx2 # Residual variances
wy2 ~~ wy2
wx3 ~~ wx3
wy3 ~~ wy3
wx4 ~~ wx4
wy4 ~~ wy4
wx5 ~~ wx5
wy5 ~~ wy5
'
RICLPM.fit <- lavaan(RICLPM, data = dat, missing = 'ML', meanstructure = T, int.ov.free = T)
summary(RICLPM.fit, standardized = T)
```

Imposing constraints to the model can be achieved through
**pre-multiplication**. It means that we have to prepend
the number that we want to fix the parameter to, and an asterisk, to the
parameter in the model specification. For example,
`F =~ 0*x1`

fixes the factor loading of item `x1`

to factor `F`

to 0. Using pre-multiplication we can also
constrain parameters to be the same by giving them the same label. Below
we specify an RI-CLPM with the following constraints:

- fixed auto-regressive and cross-lagged relations over time,
`wx2 ~ a*wx1 + b*wy1; ...`

, - time-invariant (residual) (co-)variances in the within-person part
`wx2 ~~ cov*wy2; ...`

,`wx2 ~~ vx*wx2; ...`

, and`wy2 ~~ vy*wy2; ...`

, and - constrained grand means over time,
`x1 + ... ~ mx*1`

and`y1 + ... ~ my*1`

.

```
RICLPM5 <- '
# Create between components (random intercepts)
RIx =~ 1*x1 + 1*x2 + 1*x3 + 1*x4 + 1*x5
RIy =~ 1*y1 + 1*y2 + 1*y3 + 1*y4 + 1*y5
# Create within-person centered variables
wx1 =~ 1*x1
wx2 =~ 1*x2
wx3 =~ 1*x3
wx4 =~ 1*x4
wx5 =~ 1*x5
wy1 =~ 1*y1
wy2 =~ 1*y2
wy3 =~ 1*y3
wy4 =~ 1*y4
wy5 =~ 1*y5
# Estimate the lagged effects between the within-person centered variables (constrained).
wx2 ~ a*wx1 + b*wy1
wy2 ~ c*wx1 + d*wy1
wx3 ~ a*wx2 + b*wy2
wy3 ~ c*wx2 + d*wy2
wx4 ~ a*wx3 + b*wy3
wy4 ~ c*wx3 + d*wy3
wx5 ~ a*wx4 + b*wy4
wy5 ~ c*wx4 + d*wy4
# Estimate the covariances between the residuals of the within-person centered variables
# (the innovations, constrained).
wx2 ~~ cov*wy2
wx3 ~~ cov*wy3
wx4 ~~ cov*wy4
wx5 ~~ cov*wy5
# Estimate the covariance between the within-person centered variables at the first wave.
wx1 ~~ wy1 # Covariance
# Estimate the variance and covariance of the random intercepts.
RIx ~~ RIx
RIy ~~ RIy
RIx ~~ RIy
# Estimate the (residual) variance of the within-person centered variables (constrained).
wx1 ~~ wx1 # Variance
wy1 ~~ wy1
wx2 ~~ vx*wx2 # Residual variance
wy2 ~~ vy*wy2
wx3 ~~ vx*wx3
wy3 ~~ vy*wy3
wx4 ~~ vx*wx4
wy4 ~~ vy*wy4
wx5 ~~ vx*wx5
wy5 ~~ vy*wy5
# Constrain the grand means over time.
x1 + x2 + x3 + x4 + x5 ~ mx*1
y1 + y2 + y3 + y4 + y5 ~ my*1
'
RICLPM5.fit <- lavaan(RICLPM5, data = dat, missing = 'ML', meanstructure = T, int.ov.free = T)
summary(RICLPM5.fit, standardized = T)
```

Rather than imposing constraints on the unstandardized
auto-regressive and cross-lagged relations over time, we can impose
constraints on the standardized lagged effects, as explained in the FAQ.
Compared to the previous model (with constraints over time on the
unstandardized lagged effects), there are multiple changes to the
syntax. First, we freely estimate the factor loadings that link the
observed variables to the within-components (by premultiplying with
`NA`

), rather than fixing them to 1:

```
'
# Create within-components with freely estimated factor loadings
wx1 =~ NA*x1
wx2 =~ NA*x2
wx3 =~ NA*x3
wx4 =~ NA*x4
wx5 =~ NA*x5
wy1 =~ NA*y1
wy2 =~ NA*y2
wy3 =~ NA*y3
wy4 =~ NA*y4
wy5 =~ NA*y5
'
```

Second, we set the variances of within-components at first wave to 1, and label the covariance (now also the correlation) between them:

```
'
# Set variances of within-components at first wave to 1
wx1 ~~ 1*wx1
wy1 ~~ 1*wy1
# Estimate correlation between within-components at first wave
wx1 ~~ cor1*wy1
'
```

Third, we give the residual variance and covariances between the within-component each a unique label:

```
'
# Label the residual covariances
wx2 ~~ rcov2*wy2
wx3 ~~ rcov3*wy3
wx4 ~~ rcov4*wy4
wx5 ~~ rcov5*wy5
# Label the residual variances
wx2 ~~ rvx2*wx2
wy2 ~~ rvy2*wy2
wx3 ~~ rvx3*wx3
wy3 ~~ rvy3*wy3
wx4 ~~ rvx4*wx4
wy4 ~~ rvy4*wy4
wx5 ~~ rvx5*wx5
wy5 ~~ rvy5*wy5
'
```

Finally, we compute the correlations between the within-components
*themselves* at each wave, and then constrain the residual
variances to ensure that the total variance of each within-component
equals 1. This is done with the `:=`

command:

```
'
# Compute correlations of within-components at each wave
cor2 := a*c + b*d + a*d*cor1 + b*c*cor1 + rcov2
cor3 := a*c + b*d + a*d*cor2 + b*c*cor2 + rcov3
cor4 := a*c + b*d + a*d*cor3 + b*c*cor3 + rcov4
# Contrain residual variances of within-components such that variance of each within-component equals 1
rvx2 == 1 - (a*a + b*b + 2*a*b*cor1)
rvy2 == 1 - (c*c + d*d + 2*c*d*cor1)
rvx3 == 1 - (a*a + b*b + 2*a*b*cor2)
rvy3 == 1 - (c*c + d*d + 2*c*d*cor2)
rvx4 == 1 - (a*a + b*b + 2*a*b*cor3)
rvy4 == 1 - (c*c + d*d + 2*c*d*cor3)
rvx5 == 1 - (a*a + b*b + 2*a*b*cor4)
rvy5 == 1 - (c*c + d*d + 2*c*d*cor4)
'
```

These steps ultimately result in the below syntax. Comparing the constrainted unstandardized and constrained standardized results shows that these are now equivalent.

```
RICLPM6 <- '
# Create between components (random intercepts)
RIx =~ 1*x1 + 1*x2 + 1*x3 + 1*x4 + 1*x5
RIy =~ 1*y1 + 1*y2 + 1*y3 + 1*y4 + 1*y5
# Create within-components with freely estimated factor loadings
wx1 =~ NA*x1
wx2 =~ NA*x2
wx3 =~ NA*x3
wx4 =~ NA*x4
wx5 =~ NA*x5
wy1 =~ NA*y1
wy2 =~ NA*y2
wy3 =~ NA*y3
wy4 =~ NA*y4
wy5 =~ NA*y5
# Estimate the lagged effects between the within-person centered variables (constrained).
wx2 ~ a*wx1 + b*wy1
wy2 ~ c*wx1 + d*wy1
wx3 ~ a*wx2 + b*wy2
wy3 ~ c*wx2 + d*wy2
wx4 ~ a*wx3 + b*wy3
wy4 ~ c*wx3 + d*wy3
wx5 ~ a*wx4 + b*wy4
wy5 ~ c*wx4 + d*wy4
# Label the residual covariances
wx2 ~~ rcov2*wy2
wx3 ~~ rcov3*wy3
wx4 ~~ rcov4*wy4
wx5 ~~ rcov5*wy5
# Estimate correlation between within-components at first wave
wx1 ~~ cor1*wy1
# Estimate the variance and covariance of the random intercepts.
RIx ~~ RIx
RIy ~~ RIy
RIx ~~ RIy
# Set variances of within-components at first wave to 1
wx1 ~~ 1*wx1
wy1 ~~ 1*wy1
# Label the residual variances
wx2 ~~ rvx2*wx2
wy2 ~~ rvy2*wy2
wx3 ~~ rvx3*wx3
wy3 ~~ rvy3*wy3
wx4 ~~ rvx4*wx4
wy4 ~~ rvy4*wy4
wx5 ~~ rvx5*wx5
wy5 ~~ rvy5*wy5
# Constrain the grand means over time.
x1 + x2 + x3 + x4 + x5 ~ mx*1
y1 + y2 + y3 + y4 + y5 ~ my*1
# Compute correlations of within-components at each wave
cor2 := a*c + b*d + a*d*cor1 + b*c*cor1 + rcov2
cor3 := a*c + b*d + a*d*cor2 + b*c*cor2 + rcov3
cor4 := a*c + b*d + a*d*cor3 + b*c*cor3 + rcov4
# Contrain residual variances of within-components such that variance of each within-component equals 1
rvx2 == 1 - (a*a + b*b + 2*a*b*cor1)
rvy2 == 1 - (c*c + d*d + 2*c*d*cor1)
rvx3 == 1 - (a*a + b*b + 2*a*b*cor2)
rvy3 == 1 - (c*c + d*d + 2*c*d*cor2)
rvx4 == 1 - (a*a + b*b + 2*a*b*cor3)
rvy4 == 1 - (c*c + d*d + 2*c*d*cor3)
rvx5 == 1 - (a*a + b*b + 2*a*b*cor4)
rvy5 == 1 - (c*c + d*d + 2*c*d*cor4)
'
RICLPM6.fit <- lavaan(RICLPM6, data = dat, missing = 'ML', meanstructure = T, int.ov.free = T)
summary(RICLPM6.fit, standardized = F)
summary(RICLPM6.fit, standardized = T)
```

Use the tabs below to navigate to the model specification of the RI-CLPM with

- a time-invariant predictor \(z_{1}\) of the observed variables (constrained),
- a time-invariant predictor \(z_{1}\) of the random intercepts,
- random intercepts predicting a time-invariant outcome \(z_{2}\), or
- within components predicting a time-invariant outcome \(z_{2}\).

Below you can find the code for an RI-CLPM with 5 waves and a time-invariant predictor \(z_{1}\) for the observed variables. The effect of \(z_{1}\) on the observed variables is constrained to be the same across waves.

```
RICLPM.ext1 <- '
# Create between components (random intercepts)
RIx =~ 1*x1 + 1*x2 + 1*x3 + 1*x4 + 1*x5
RIy =~ 1*y1 + 1*y2 + 1*y3 + 1*y4 + 1*y5
# Create within-person centered variables
wx1 =~ 1*x1
wx2 =~ 1*x2
wx3 =~ 1*x3
wx4 =~ 1*x4
wx5 =~ 1*x5
wy1 =~ 1*y1
wy2 =~ 1*y2
wy3 =~ 1*y3
wy4 =~ 1*y4
wy5 =~ 1*y5
# Regression of observed variables on z1 (constrained).
x1 + x2 + x3 + x4 + x5 ~ s1*z1 # Constrained over time.
y1 + y2 + y3 + y4 + y5 ~ s2*z1 # Constrained over time.
# Estimate the lagged effects between the within-person centered variables.
wx2 + wy2 ~ wx1 + wy1
wx3 + wy3 ~ wx2 + wy2
wx4 + wy4 ~ wx3 + wy3
wx5 + wy5 ~ wx4 + wy4
# Estimate the covariance between the within-person centered variables at the first wave.
wx1 ~~ wy1 # Covariance
# Estimate the covariances between the residuals of the within-person centered variables (the innovations).
wx2 ~~ wy2
wx3 ~~ wy3
wx4 ~~ wy4
wx5 ~~ wy5
# Estimate the variance and covariance of the random intercepts.
RIx ~~ RIx
RIy ~~ RIy
RIx ~~ RIy
# Estimate the (residual) variance of the within-person centered variables.
wx1 ~~ wx1 # Variances
wy1 ~~ wy1
wx2 ~~ wx2 # Residual variances
wy2 ~~ wy2
wx3 ~~ wx3
wy3 ~~ wy3
wx4 ~~ wx4
wy4 ~~ wy4
wx5 ~~ wx5
wy5 ~~ wy5
'
RICLPM.ext1.fit <- lavaan(RICLPM.ext1, data = datZ, missing = 'ML', meanstructure = T, int.ov.free = T)
summary(RICLPM.ext1.fit, standardized = T)
```

Below you can find the code for an RI-CLPM with 5 waves and a time-invariant predictor \(z_{1}\) for the random intercepts.

```
RICLPM1.ext1 <- '
# Create between components (random intercepts)
RIx =~ 1*x1 + 1*x2 + 1*x3 + 1*x4 + 1*x5
RIy =~ 1*y1 + 1*y2 + 1*y3 + 1*y4 + 1*y5
# Estimate the variance and covariance of the random intercepts.
RIx ~~ RIx
RIy ~~ RIy
RIx ~~ RIy
# Regression of random intercepts on z1.
RIx + RIy ~ z1 # Constrained over time.
# Create within-person centered variables
wx1 =~ 1*x1
wx2 =~ 1*x2
wx3 =~ 1*x3
wx4 =~ 1*x4
wx5 =~ 1*x5
wy1 =~ 1*y1
wy2 =~ 1*y2
wy3 =~ 1*y3
wy4 =~ 1*y4
wy5 =~ 1*y5
# Estimate the lagged effects between the within-person centered variables.
wx2 + wy2 ~ wx1 + wy1
wx3 + wy3 ~ wx2 + wy2
wx4 + wy4 ~ wx3 + wy3
wx5 + wy5 ~ wx4 + wy4
# Estimate the covariance between the within-person centered variables at the first wave.
wx1 ~~ wy1 # Covariance
# Estimate the covariances between the residuals of the within-person centered variables (the innovations).
wx2 ~~ wy2
wx3 ~~ wy3
wx4 ~~ wy4
wx5 ~~ wy5
# Estimate the (residual) variance of the within-person centered variables.
wx1 ~~ wx1 # Variances
wy1 ~~ wy1
wx2 ~~ wx2 # Residual variances
wy2 ~~ wy2
wx3 ~~ wx3
wy3 ~~ wy3
wx4 ~~ wx4
wy4 ~~ wy4
wx5 ~~ wx5
wy5 ~~ wy5
'
RICLPM1.ext1.fit <- lavaan(RICLPM1.ext1, data = datZ, missing = 'ML', meanstructure = T, int.ov.free = T)
summary(RICLPM1.ext1.fit, standardized = T)
```

Below you can find code for an RI-CLPM with the between components (the random intercepts) predicting a time-invariant outcome. For sake of completeness, the time-invariant \(z_{1}\) is also included as a predictor the for observed variables (constrained).

```
RICLPM3.ext1 <- '
# Create between components (random intercepts)
RIx =~ 1*x1 + 1*x2 + 1*x3 + 1*x4 + 1*x5
RIy =~ 1*y1 + 1*y2 + 1*y3 + 1*y4 + 1*y5
# Estimate the variance and covariance of the random intercepts.
RIx ~~ RIx
RIy ~~ RIy
RIx ~~ RIy
# Regression of time-invariant outcome z2 on random intercepts.
z2 ~ RIx + RIy
z2 ~~ z2 # Residual variance z2
# Create within-person centered variables
wx1 =~ 1*x1
wx2 =~ 1*x2
wx3 =~ 1*x3
wx4 =~ 1*x4
wx5 =~ 1*x5
wy1 =~ 1*y1
wy2 =~ 1*y2
wy3 =~ 1*y3
wy4 =~ 1*y4
wy5 =~ 1*y5
# Regression of observed variables on z1 (constrained).
x1 + x2 + x3 + x4 + x5 ~ s1*z1 # Constrained over time.
y1 + y2 + y3 + y4 + y5 ~ s2*z1 # Constrained over time.
# Estimate the lagged effects between the within-person centered variables.
wx2 + wy2 ~ wx1 + wy1
wx3 + wy3 ~ wx2 + wy2
wx4 + wy4 ~ wx3 + wy3
wx5 + wy5 ~ wx4 + wy4
# Estimate the covariance between the within-person centered variables at the first wave.
wx1 ~~ wy1 # Covariance
# Estimate the covariances between the residuals of the within-person centered variables (the innovations).
wx2 ~~ wy2
wx3 ~~ wy3
wx4 ~~ wy4
wx5 ~~ wy5
# Estimate the (residual) variance of the within-person centered variables.
wx1 ~~ wx1 # Variances
wy1 ~~ wy1
wx2 ~~ wx2 # Residual variances
wy2 ~~ wy2
wx3 ~~ wx3
wy3 ~~ wy3
wx4 ~~ wx4
wy4 ~~ wy4
wx5 ~~ wx5
wy5 ~~ wy5
'
RICLPM3.ext1.fit <- lavaan(RICLPM3.ext1, data = datZ, missing = 'ML', meanstructure = T, int.ov.free = T)
summary(RICLPM3.ext1.fit, standardized = T)
```

Below you can find code for an RI-CLPM with the within components predicting a time-invariant outcome. For sake of completeness, the time-invariant \(z_{1}\) is also included as a predictor the for observed variables (constrained).

```
RICLPM4.ext1 <- '
# Create between components (random intercepts)
RIx =~ 1*x1 + 1*x2 + 1*x3 + 1*x4 + 1*x5
RIy =~ 1*y1 + 1*y2 + 1*y3 + 1*y4 + 1*y5
# Estimate the variance and covariance of the random intercepts.
RIx ~~ RIx
RIy ~~ RIy
RIx ~~ RIy
# Regression of time-invariant outcome z2 on within components.
z2 ~ wx1 + wx2 + wx3 + wx4 + wx5 + wy1 + wy2 + wy3 + wy4 + wy5
z2 ~~ z2 # Residual variance z2
# Create within-person centered variables
wx1 =~ 1*x1
wx2 =~ 1*x2
wx3 =~ 1*x3
wx4 =~ 1*x4
wx5 =~ 1*x5
wy1 =~ 1*y1
wy2 =~ 1*y2
wy3 =~ 1*y3
wy4 =~ 1*y4
wy5 =~ 1*y5
# Regression of observed variables on z1 (constrained).
x1 + x2 + x3 + x4 + x5 ~ s1*z1 # Constrained over time.
y1 + y2 + y3 + y4 + y5 ~ s2*z1 # Constrained over time.
# Estimate the lagged effects between the within-person centered variables.
wx2 + wy2 ~ wx1 + wy1
wx3 + wy3 ~ wx2 + wy2
wx4 + wy4 ~ wx3 + wy3
wx5 + wy5 ~ wx4 + wy4
# Estimate the covariance between the within-person centered variables at the first wave.
wx1 ~~ wy1 # Covariance
# Estimate the covariances between the residuals of the within-person centered variables (the innovations).
wx2 ~~ wy2
wx3 ~~ wy3
wx4 ~~ wy4
wx5 ~~ wy5
# Estimate the (residual) variance of the within-person centered variables.
wx1 ~~ wx1 # Variances
wy1 ~~ wy1
wx2 ~~ wx2 # Residual variances
wy2 ~~ wy2
wx3 ~~ wx3
wy3 ~~ wy3
wx4 ~~ wx4
wy4 ~~ wy4
wx5 ~~ wx5
wy5 ~~ wy5
'
RICLPM4.ext1.fit <- lavaan(RICLPM4.ext1, data = datZ, missing = 'ML', meanstructure = T, int.ov.free = T)
summary(RICLPM4.ext1.fit, standardized = T)
```

Use the tabs below to navigate to the model specification of the basic multiple-group model, or the model with constrained lagged parameters (and intercepts across groups).

Below you can find the code for a multiple group RI-CLPM with 5 waves.

```
RICLPM.ext2 <- '
# Create between components (random intercepts)
RIx =~ 1*x1 + 1*x2 + 1*x3 + 1*x4 + 1*x5
RIy =~ 1*y1 + 1*y2 + 1*y3 + 1*y4 + 1*y5
# Create within-person centered variables
wx1 =~ 1*x1
wx2 =~ 1*x2
wx3 =~ 1*x3
wx4 =~ 1*x4
wx5 =~ 1*x5
wy1 =~ 1*y1
wy2 =~ 1*y2
wy3 =~ 1*y3
wy4 =~ 1*y4
wy5 =~ 1*y5
# Estimate the lagged effects between the within-person centered variables.
wx2 + wy2 ~ wx1 + wy1
wx3 + wy3 ~ wx2 + wy2
wx4 + wy4 ~ wx3 + wy3
wx5 + wy5 ~ wx4 + wy4
# Estimate the covariance between the within-person centered variables at the first wave.
wx1 ~~ wy1 # Covariance
# Estimate the covariances between the residuals of the within-person centered variables (the innovations).
wx2 ~~ wy2
wx3 ~~ wy3
wx4 ~~ wy4
wx5 ~~ wy5
# Estimate the variance and covariance of the random intercepts.
RIx ~~ RIx
RIy ~~ RIy
RIx ~~ RIy
# Estimate the (residual) variance of the within-person centered variables.
wx1 ~~ wx1 # Variances
wy1 ~~ wy1
wx2 ~~ wx2 # Residual variances
wy2 ~~ wy2
wx3 ~~ wx3
wy3 ~~ wy3
wx4 ~~ wx4
wy4 ~~ wy4
wx5 ~~ wx5
wy5 ~~ wy5
'
RICLPM.ext2.fit <- lavaan(RICLPM.ext2, data = datMG, missing = 'ML', group = "G", meanstructure = T, int.ov.free = T)
summary(RICLPM.ext2.fit)
```

Below you can find the code for a multiple group RI-CLPM with 4 waves. The lagged-parameters are constrained to be equal over time.

```
RICLPM1.ext2 <- '
# Create between components (random intercepts)
RIx =~ 1*x1 + 1*x2 + 1*x3 + 1*x4 + 1*x5
RIy =~ 1*y1 + 1*y2 + 1*y3 + 1*y4 + 1*y5
# Create within-person centered variables
wx1 =~ 1*x1
wx2 =~ 1*x2
wx3 =~ 1*x3
wx4 =~ 1*x4
wx5 =~ 1*x5
wy1 =~ 1*y1
wy2 =~ 1*y2
wy3 =~ 1*y3
wy4 =~ 1*y4
wy5 =~ 1*y5
# Estimate the lagged effects between the within-person centered variables. Constrain the
# autoregressive effects across groups.
wx2 ~ c(a1, a1)*wx1 + c(b1, b1)*wy1
wy2 ~ c(c1, c1)*wx1 + c(d1, d1)*wy1
wx3 ~ c(a2, a2)*wx2 + c(b2, b2)*wy2
wy3 ~ c(c2, c2)*wx2 + c(d2, d2)*wy2
wx4 ~ c(a3, a3)*wx3 + c(b3, b3)*wy3
wy4 ~ c(c3, c3)*wx3 + c(d3, d3)*wy3
wx5 ~ c(a4, a4)*wx4 + c(b4, b4)*wy4
wy5 ~ c(c4, c4)*wx4 + c(d4, d4)*wy4
# Estimate the covariance between the within-person centered variables at the first wave.
wx1 ~~ wy1 # Covariance
# Estimate the covariances between the residuals of the within-person centered variables (the innovations).
wx2 ~~ wy2
wx3 ~~ wy3
wx4 ~~ wy4
wx5 ~~ wy5
# Estimate the variance and covariance of the random intercepts.
RIx ~~ RIx
RIy ~~ RIy
RIx ~~ RIy
# Estimate the (residual) variance of the within-person centered variables.
wx1 ~~ wx1 # Variances
wy1 ~~ wy1
wx2 ~~ wx2 # Residual variances
wy2 ~~ wy2
wx3 ~~ wx3
wy3 ~~ wy3
wx4 ~~ wx4
wy4 ~~ wy4
wx5 ~~ wx5
wy5 ~~ wy5
'
RICLPM1.ext2.fit <- lavaan(RICLPM1.ext2, data = datMG, missing = 'ML', group = "G", meanstructure = T, int.ov.free = T)
summary(RICLPM1.ext2.fit)
```

Use the tabs below to navigate to the model specification of a multiple indicator RI-CLPM, 5 waves and 3 indicators for each variable at each wave. The five steps correspond to:

- the configural model (Step 1),
- weak factorial invariance (Step 2),
- strong factorial invariance (Step 3),
- strong factorial invariance with factor loadings equal to the within-person factor loadings (Extra), and
- the latent RI-CLPM (Step 4).

You can download the simulated example dataset *MIRICLPM.dat*
from https://jeroendmulder.github.io/RI-CLPM/data/MIRICLPM.dat.

When we have three indicators \(X\),
measured at five waves, we specify three random intercepts to capture
the trait-like part of each indicator, that is,
`RIX1 =~ 1*x11 1*x21 ...`

,
`RIX2 =~ 1*x121 1*x22@1 ...`

, and
`RIX3 =~ 1*x13 1*x23 ...`

. In addition, we specify five
within-unit components that capture the state-like part at each wave,
using `WFX1 =~ x11 x12 x13; WFX2 =~ x21 x22 x23; ...`

.

At the latent within-unit level, we specify the dynamic model in
Mplus using `WFX2 ~ WFY1 + WFX1; WFX3 ~ WFY2 + WFX2; ...`

. In
addition, we allow the within-person factors at the first wave, and
their residuals at subsequent waves to be correlated within each wave,
`WFX1 ~~ WFY1; WFX2 ~~ WFY2; ...`

. The six random intercepts
are allowed to be freely correlated with each other, either through
inclusion of `RIX1 + RIX2 + ... ~~ RIX1 + RIX2 + ...`

in the
model syntax, or by default when using the `cfa()`

function
as we have done below.

```
RICLPM1.ext3 <- '
################
# BETWEEN PART #
################
# Create between factors (random intercepts) for each indicator separately.
RIX1 =~ 1*x11 + 1*x21 + 1*x31 + 1*x41 + 1*x51
RIX2 =~ 1*x12 + 1*x22 + 1*x32 + 1*x42 + 1*x52
RIX3 =~ 1*x13 + 1*x23 + 1*x33 + 1*x43 + 1*x53
RIY1 =~ 1*y11 + 1*y21 + 1*y31 + 1*y41 + 1*y51
RIY2 =~ 1*y12 + 1*y22 + 1*y32 + 1*y42 + 1*y52
RIY3 =~ 1*y13 + 1*y23 + 1*y33 + 1*y43 + 1*y53
##################################
# WITHIN PART: MEASUREMENT MODEL #
##################################
# Factor models for x at 5 waves.
WFX1 =~ x11 + x12 + x13
WFX2 =~ x21 + x22 + x23
WFX3 =~ x31 + x32 + x33
WFX4 =~ x41 + x42 + x43
WFX5 =~ x51 + x52 + x53
# Factor models for y at 5 waves.
WFY1 =~ y11 + y12 + y13
WFY2 =~ y21 + y22 + y23
WFY3 =~ y31 + y32 + y33
WFY4 =~ y41 + y42 + y43
WFY5 =~ y51 + y52 + y53
#########################
# WITHIN PART: DYNAMICS #
#########################
# Specify the lagged effects between the within-person centered latent variables.
WFX2 + WFY2 ~ WFX1 + WFY1
WFX3 + WFY3 ~ WFX2 + WFY2
WFX4 + WFY4 ~ WFX3 + WFY3
WFX5 + WFY5 ~ WFX4 + WFY4
# Estimate the correlations within the same wave.
WFX1 ~~ WFY1
WFX2 ~~ WFY2
WFX3 ~~ WFY3
WFX4 ~~ WFY4
WFX5 ~~ WFY5
##########################
# ADDITIONAL CONSTRAINTS #
##########################
# Constrain covariance of the between factors and exogenous within factors to 0.
RIX1 + RIX2 + RIX3 + RIY1 + RIY2 + RIY3 ~~ 0*WFY1 + 0*WFX1
'
RICLPM1.ext3.fit <- cfa(RICLPM1.ext3, data = datMI, missing = 'ML')
summary(RICLPM1.ext3.fit, standardized = T)
```

In second step, we constrain the factor loadings to be invariant over
time using the labels `a*`

, `b*`

, etc.

```
RICLPM2.ext3 <- '
################
# BETWEEN PART #
################
# Create between factors (random intercepts) for each indicator separately.
RIX1 =~ 1*x11 + 1*x21 + 1*x31 + 1*x41 + 1*x51
RIX2 =~ 1*x12 + 1*x22 + 1*x32 + 1*x42 + 1*x52
RIX3 =~ 1*x13 + 1*x23 + 1*x33 + 1*x43 + 1*x53
RIY1 =~ 1*y11 + 1*y21 + 1*y31 + 1*y41 + 1*y51
RIY2 =~ 1*y12 + 1*y22 + 1*y32 + 1*y42 + 1*y52
RIY3 =~ 1*y13 + 1*y23 + 1*y33 + 1*y43 + 1*y53
##################################
# WITHIN PART: MEASUREMENT MODEL #
##################################
# Factor models for x at 5 waves (constrained).
WFX1 =~ a*x11 + b*x12 + c*x13
WFX2 =~ a*x21 + b*x22 + c*x23
WFX3 =~ a*x31 + b*x32 + c*x33
WFX4 =~ a*x41 + b*x42 + c*x43
WFX5 =~ a*x51 + b*x52 + c*x53
# Factor models for y at 5 waves (constrained).
WFY1 =~ d*y11 + e*y12 + f*y13
WFY2 =~ d*y21 + e*y22 + f*y23
WFY3 =~ d*y31 + e*y32 + f*y33
WFY4 =~ d*y41 + e*y42 + f*y43
WFY5 =~ d*y51 + e*y52 + f*y53
#########################
# WITHIN PART: DYNAMICS #
#########################
# Specify the lagged effects between the within-person centered latent variables.
WFX2 + WFY2 ~ WFX1 + WFY1
WFX3 + WFY3 ~ WFX2 + WFY2
WFX4 + WFY4 ~ WFX3 + WFY3
WFX5 + WFY5 ~ WFX4 + WFY4
# Estimate the correlations within the same wave.
WFX1 ~~ WFY1
WFX2 ~~ WFY2
WFX3 ~~ WFY3
WFX4 ~~ WFY4
WFX5 ~~ WFY5
##########################
# ADDITIONAL CONSTRAINTS #
##########################
# Constrain covariance of the between factors and exogenous within factors to 0.
RIX1 + RIX2 + RIX3 + RIY1 + RIY2 + RIY3 ~~ 0*WFY1 + 0*WFX1
'
RICLPM2.ext3.fit <- cfa(RICLPM2.ext3, data = datMI, missing = 'ML')
summary(RICLPM2.ext3.fit, standardized = T)
```

Multiple indicator RI-CLPM 4 waves with 3 indicators for each variable at each wave (24 observed variables). Fitting a model with constraints to ensure strong factorial invariance, with a random intercept for each indicator separately.

```
RICLPM3.ext3 <- '
################
# BETWEEN PART #
################
# Create between factors (random intercepts) for each indicator separately.
RIX1 =~ 1*x11 + 1*x21 + 1*x31 + 1*x41 + 1*x51
RIX2 =~ 1*x12 + 1*x22 + 1*x32 + 1*x42 + 1*x52
RIX3 =~ 1*x13 + 1*x23 + 1*x33 + 1*x43 + 1*x53
RIY1 =~ 1*y11 + 1*y21 + 1*y31 + 1*y41 + 1*y51
RIY2 =~ 1*y12 + 1*y22 + 1*y32 + 1*y42 + 1*y52
RIY3 =~ 1*y13 + 1*y23 + 1*y33 + 1*y43 + 1*y53
##################################
# WITHIN PART: MEASUREMENT MODEL #
##################################
# Factor models for x at 5 waves (constrained).
WFX1 =~ a*x11 + b*x12 + c*x13
WFX2 =~ a*x21 + b*x22 + c*x23
WFX3 =~ a*x31 + b*x32 + c*x33
WFX4 =~ a*x41 + b*x42 + c*x43
WFX5 =~ a*x51 + b*x52 + c*x53
# Factor models for y at 5 waves (constrained).
WFY1 =~ d*y11 + e*y12 + f*y13
WFY2 =~ d*y21 + e*y22 + f*y23
WFY3 =~ d*y31 + e*y32 + f*y33
WFY4 =~ d*y41 + e*y42 + f*y43
WFY5 =~ d*y51 + e*y52 + f*y53
# Constrained intercepts over time (this is necessary for strong factorial
# invariance; without these contraints we have week factorial invariance).
x11 + x21 + x31 + x41 + x51 ~ g*1
x12 + x22 + x32 + x42 + x52 ~ h*1
x13 + x23 + x33 + x43 + x53 ~ i*1
y11 + y21 + y31 + y41 + y51 ~ j*1
y12 + y22 + y32 + y42 + y52 ~ k*1
y13 + y23 + y33 + y43 + y53 ~ l*1
# Free latent means from t = 2 onward (only do this in combination with the
# constraints on the intercepts; without these, this would not be specified).
WFX2 + WFX3 + WFX4 + WFX5 + WFY2 + WFY3 + WFY4 + WFY5 ~ 1
#########################
# WITHIN PART: DYNAMICS #
#########################
# Specify the lagged effects between the within-person centered latent variables.
WFX2 + WFY2 ~ WFX1 + WFY1
WFX3 + WFY3 ~ WFX2 + WFY2
WFX4 + WFY4 ~ WFX3 + WFY3
WFX5 + WFY5 ~ WFX4 + WFY4
# Estimate the correlations within the same wave.
WFX1 ~~ WFY1
WFX2 ~~ WFY2
WFX3 ~~ WFY3
WFX4 ~~ WFY4
WFX5 ~~ WFY5
##########################
# ADDITIONAL CONSTRAINTS #
##########################
# Constrain covariance of the between factors and exogenous within factors to 0.
RIX1 + RIX2 + RIX3 + RIY1 + RIY2 + RIY3 ~~ 0*WFY1 + 0*WFX1
'
RICLPM3.ext3.fit <- cfa(RICLPM3.ext3, data = datMI, missing = 'ML')
summary(RICLPM3.ext3.fit, standardized = T)
```

Multiple indicator RI-CLPM, 5 waves with 3 indicators for each variable at each wave (30 observed variables). Fitting a model With constraints to ensure strong factorial invariance, with a random intercept for each indicator separately, for which a factor model is specified, with factor loadings equal to the within- person factor loadings.

```
RICLPM4.ext3 <- '
################
# BETWEEN PART #
################
# Create between factors (random intercepts) for each indicator separately.
RIX1 =~ 1*x11 + 1*x21 + 1*x31 + 1*x41 + 1*x51
RIX2 =~ 1*x12 + 1*x22 + 1*x32 + 1*x42 + 1*x52
RIX3 =~ 1*x13 + 1*x23 + 1*x33 + 1*x43 + 1*x53
RIY1 =~ 1*y11 + 1*y21 + 1*y31 + 1*y41 + 1*y51
RIY2 =~ 1*y12 + 1*y22 + 1*y32 + 1*y42 + 1*y52
RIY3 =~ 1*y13 + 1*y23 + 1*y33 + 1*y43 + 1*y53
# Create a single random intercept for al x variables, and another for all
# y variables and constrain the factor loadings to be identical to the
# within-person factor loadings.
RIX =~ a*RIX1 + b*RIX2 + c*RIX3
RIY =~ d*RIY1 + e*RIY2 + f*RIY3
# Add (co)variance between two higher-order random intercepts.
RIX ~~ RIY
RIX ~~ RIX
RIY ~~ RIY
# Constrain measurement error variances of the second order factor model to 0.
RIX1 ~~ 0*RIX1
RIX2 ~~ 0*RIX2
RIX3 ~~ 0*RIX3
RIY1 ~~ 0*RIY1
RIY2 ~~ 0*RIY2
RIY3 ~~ 0*RIY3
##################################
# WITHIN PART: MEASUREMENT MODEL #
##################################
# Factor models for x at 5 waves (constrained).
WFX1 =~ a*x11 + b*x12 + c*x13
WFX2 =~ a*x21 + b*x22 + c*x23
WFX3 =~ a*x31 + b*x32 + c*x33
WFX4 =~ a*x41 + b*x42 + c*x43
WFX5 =~ a*x51 + b*x52 + c*x53
# Factor models for y at 5 waves (constrained).
WFY1 =~ d*y11 + e*y12 + f*y13
WFY2 =~ d*y21 + e*y22 + f*y23
WFY3 =~ d*y31 + e*y32 + f*y33
WFY4 =~ d*y41 + e*y42 + f*y43
WFY5 =~ d*y51 + e*y52 + f*y53
# Constrained intercepts over time (this is necessary for strong factorial
# invariance; without these contraints we have week factorial invariance).
x11 + x21 + x31 + x41 + x51 ~ g*1
x12 + x22 + x32 + x42 + x52 ~ h*1
x13 + x23 + x33 + x43 + x53 ~ i*1
y11 + y21 + y31 + y41 + y51 ~ j*1
y12 + y22 + y32 + y42 + y52 ~ k*1
y13 + y23 + y33 + y43 + y53 ~ l*1
# Free latent means from t = 2 onward (only do this in combination with the
# constraints on the intercepts; without these, this would not be specified).
WFX2 + WFX3 + WFX4 + WFX5 + WFY2 + WFY3 + WFY4 + WFY5 ~ 1
#########################
# WITHIN PART: DYNAMICS #
#########################
# Specify the lagged effects between the within-person centered latent variables.
WFX2 + WFY2 ~ WFX1 + WFY1
WFX3 + WFY3 ~ WFX2 + WFY2
WFX4 + WFY4 ~ WFX3 + WFY3
WFX5 + WFY5 ~ WFX4 + WFY4
# Estimate the correlations within the same wave.
WFX1 ~~ WFY1
WFX2 ~~ WFY2
WFX3 ~~ WFY3
WFX4 ~~ WFY4
WFX5 ~~ WFY5
##########################
# ADDITIONAL CONSTRAINTS #
##########################
# Constrain covariance of the between factors and exogenous within factors to 0.
RIX + RIY + RIX1 + RIX2 + RIX3 + RIY1 + RIY2 + RIY3 ~~ 0*WFY1 + 0*WFX1
'
RICLPM4.ext3.fit <- cfa(RICLPM4.ext3, data = datMI, missing = 'ML')
summary(RICLPM4.ext3.fit, standardized = T)
```

Multiple indicator RI-CLPM, 5 waves with 3 indicators for each variable at each wave (30 observed variables). Fitting a model with constraints to ensure strong factorial invariance, with the RI-CLPM at the latent level.

```
RICLPM5.ext3 <- '
#####################
# MEASUREMENT MODEL #
#####################
# Factor models for x at 5 waves (constrained).
FX1 =~ a*x11 + b*x12 + c*x13
FX2 =~ a*x21 + b*x22 + c*x23
FX3 =~ a*x31 + b*x32 + c*x33
FX4 =~ a*x41 + b*x42 + c*x43
FX5 =~ a*x51 + b*x52 + c*x53
# Factor models for y at 5 waves (constrained).
FY1 =~ d*y11 + e*y12 + f*y13
FY2 =~ d*y21 + e*y22 + f*y23
FY3 =~ d*y31 + e*y32 + f*y33
FY4 =~ d*y41 + e*y42 + f*y43
FY5 =~ d*y51 + e*y52 + f*y53
# Constrained intercepts over time (this is necessary for strong factorial
# invariance; without these contraints we have week factorial invariance).
x11 + x21 + x31 + x41 + x51 ~ g*1
x12 + x22 + x32 + x42 + x52 ~ h*1
x13 + x23 + x33 + x43 + x53 ~ i*1
y11 + y21 + y31 + y41 + y51 ~ j*1
y12 + y22 + y32 + y42 + y52 ~ k*1
y13 + y23 + y33 + y43 + y53 ~ l*1
# Free latent means from t = 2 onward (only do this in combination with the
# constraints on the intercepts; without these, this would not be specified).
FX2 + FX3 + FX4 + FX5 + FY2 + FY3 + FY4 + FY5 ~ 1
################
# BETWEEN PART #
################
# Create between factors (random intercepts).
RIX =~ 1*FX1 + 1*FX2 + 1*FX3 + 1*FX4 + 1*FX5
RIY =~ 1*FY1 + 1*FY2 + 1*FY3 + 1*FY4 + 1*FY5
# Set the residual variances of all FX and FY variables to 0.
FX1 ~~ 0*FX1
FX2 ~~ 0*FX2
FX3 ~~ 0*FX3
FX4 ~~ 0*FX4
FX5 ~~ 0*FX5
FY1 ~~ 0*FY1
FY2 ~~ 0*FY2
FY3 ~~ 0*FY3
FY4 ~~ 0*FY4
FY5 ~~ 0*FY5
###############
# WITHIN PART #
###############
# Create the within-part.
WFX1 =~ 1*FX1
WFX2 =~ 1*FX2
WFX3 =~ 1*FX3
WFX4 =~ 1*FX4
WFX5 =~ 1*FX5
WFY1 =~ 1*FY1
WFY2 =~ 1*FY2
WFY3 =~ 1*FY3
WFY4 =~ 1*FY4
WFY5 =~ 1*FY5
# Specify the lagged effects between the within-person centered latent variables.
WFX2 + WFY2 ~ WFX1 + WFY1
WFX3 + WFY3 ~ WFX2 + WFY2
WFX4 + WFY4 ~ WFX3 + WFY3
WFX5 + WFY5 ~ WFX4 + WFY4
# Estimate the correlations within the same wave.
WFX2 ~~ WFY2
WFX3 ~~ WFY3
WFX4 ~~ WFY4
WFX5 ~~ WFY5
##########################
# ADDITIONAL CONSTRAINTS #
##########################
# Set correlations between the between-factors (random intercepts) and within-
# factors at wave 1 at 0.
RIX + RIY ~~ 0*WFX1 + 0*WFY1
'
RICLPM5.ext3.fit <- cfa(RICLPM5.ext3, data = datMI, missing = 'ML')
summary(RICLPM5.ext3.fit, standardized = T)
```

The use of the chi-square difference test is wide-spread in the SEM community to test constaints on parameters. However, when constraints are placed on the bound of the parameter space, we should use the chi-bar-square test (\(\bar{\chi}^{2}\)-test) (Stoel et al. 2006). For example, if we constrain the variances of all random intercepts (and their covariance) in the RI-CLPM to zero, we obtain a model that is nested under the RI-CLPM, and that is statistically equivalent to the traditional cross-lagged panel model (CLPM). Below you can find R code for performing the chi-bar-square test (code by Rebecca M. Kuiper) for comparing these two models. It involves

- fitting both the RI-CLPM (
`RICLPM.fit`

) and CLPM (`CLPM.fit`

); - extracting the covariance matrix of the random intercepts;
- extracting the \(\chi^{2}\) and degrees of freedom of both models; and
- performing the \(\bar{\chi}^{2}\)-test using the
`ChiBarSq.DiffTest`

package (Kuiper 2020).

```
# Install and load the required packages.
## library(devtools)
## install_github("rebeccakuiper/ChiBarSq.DiffTest")
library(ChiBarSq.DiffTest)
# Step 1
## Fit the RI-CLPM (RICLPM.fit) and the CLPM (CLPM.fit).
# Step 2
## Check which indices you need to get the covariance matrix of the random intercepts.
vcov(RICLPM.fit) # Full covariance matrix
## The 22nd and the 23rd indices regard the random intercepts
indices <- c(22, 23)
q <- length(indices) # Number of random intercepts
S <- vcov(RICLPM.fit)[indices, indices] # Extract full covariance matrix of the random intercepts
# Step 3
Chi2_clpm <- summary(CLPM.fit, fit.measures = TRUE)[1]$FIT[c("chisq")] # Extract chi-square value of CLPM
Chi2_riclpm <- summary(RICLPM.fit, fit.measures = TRUE)[1]$FIT[c("chisq")] # Extract chi-square value of RI-CLPM
df_clpm <- summary(CLPM.fit, fit.measures = TRUE)[1]$FIT[c("df")] # Extract df of CLPM
df_riclpm <- summary(RICLPM.fit, fit.measures = TRUE)[1]$FIT[c("df")] # Extract df of RI-CLPM
# Step 4
## Run function to do chi-bar-square test (and also obtain Chi-bar-square weigths)
ChiBar2DiffTest <- ChiBarSq.DiffTest(q, S, Chi2_clpm, Chi2_riclpm, df_clpm, df_riclpm)
ChiBar2DiffTest
ChiBar2DiffTest$p_value
```

Kuiper, Rebecca M. 2020. *ChiBarSq.DiffTest:
Chi-bar-square difference test of the RI-CLPM versus the CLPM and more
general.*

Rosseel, Yves. 2012. “lavaan: An
R Package for Structural Equation Modeling.”
*Journal of Statistical Software* 48 (2): 1–36. http://www.jstatsoft.org/v48/i02/.

Stoel, Reinoud D., Francisca Galindo Garre, Conor Dolan, and Godfried
van den Wittenboer. 2006. “On the likelihood
ratio test in structural equation modeling when parameters are subject
to boundary constraints.” *Psychological Methods*
11 (4): 439–55. https://doi.org/10.1037/1082-989X.11.4.439.