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("/Users/jeroenmulder/Git/RICLPM/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;`

.

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)
```

```
CLPM <- '
# Estimate the lagged effects between the observed variables.
x2 + y2 ~ x1 + y1
x3 + y3 ~ x2 + y2
x4 + y4 ~ x3 + y3
x5 + y5 ~ x4 + y4
# Estimate the covariance between the observed variables at the first wave.
x1 ~~ y1 # Covariance
# Estimate the covariances between the residuals of the observed variables.
x2 ~~ y2
x3 ~~ y3
x4 ~~ y4
x5 ~~ y5
# Estimate the (residual) variance of the observed variables.
x1 ~~ x1 # Variances
y1 ~~ y1
x2 ~~ x2 # Residual variances
y2 ~~ y2
x3 ~~ x3
y3 ~~ y3
x4 ~~ x4
y4 ~~ y4
x5 ~~ x5
y5 ~~ y5
'
CLPM.fit <- lavaan(CLPM, data = dat, missing = 'ML', meanstructure = T, int.ov.free = T)
summary(CLPM.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)
```

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.