My last post demonstrated a dual change model for one variable, now I want to demonstrate a bivariate dual change model. A SEM path diagram for a bivariate dual change model is below, taken from Wang, Zhou, and Zhang (2016)

(If you do not have access to that link you can view a similar path diagram in Jones, King, Gilrane, McCausland, Cortina, & Grimm, 2016)

Essentially, we have two dual change processes and a coupling parameter from the latent true score on one variable to the latent change score on the other.

The DGP

$$$y_t = constant_y + (1 + proportion_y)*y_{t-1} + coupling_{xy}*x_{t-1} + e$$$

where $$constant_y$$ is the change factor (or latent slope) on $$y$$, $$proportion_y$$ is the proportion change factor, and $$coupling_xy$$ is the coupling parameter relating $$x$$ to $$y$$. The DGP for $$x$$ is

$$$x_t = constant_x + (1 + proportion_x)*x_{t-1} + coupling_{yx}*y_{t-1} + e$$$

where the terms are similar but now applied to values of $$x$$. The true values used in the DGP are:

\begin{align} y_t &= 0.5 + (1 + -0.32)y_{t-1} + 0.4x_{t-1} + e \\ x_t &= 0.5 + (1 + 0.22)x_{t-1} - 0.4y_{t-1} + e \end{align}

with initial values for both $$x$$ and $$y$$ sampled from $$N$$ ~ (10, 1).

people <- 700
time <- 6
x_cause_y <- 0.4
y_cause_x <- -0.4

const_x <- 0.5
const_y <- 0.5

prop_x <- 0.22
prop_y <- -0.32

df_mat <- matrix(, ncol = 4, nrow = people*time)
count <- 0

for(i in 1:people){

unob_het_y <- rnorm(1, 0, 3)
unob_het_x <- rnorm(1, 0, 3)

for(j in 1:time){
count <- count + 1

if(j == 1){
df_mat[count, 1] <- i
df_mat[count, 2] <- j
df_mat[count, 3] <- rnorm(1, 10, 1)
df_mat[count, 4] <- rnorm(1, 10, 1)
}else{

df_mat[count, 1] <- i
df_mat[count, 2] <- j
df_mat[count, 3] <- const_x + (1+prop_x)*df_mat[count - 1, 3] + y_cause_x*df_mat[count - 1, 4] + unob_het_x + rnorm(1,0,1)
df_mat[count, 4] <- const_y + (1+prop_y)*df_mat[count - 1, 4] + x_cause_y*df_mat[count - 1, 3] + unob_het_y + rnorm(1,0,1)
}

}

}

library(tidyverse)
library(ggplot2)
library(reshape2)

df <- data.frame(df_mat)
names(df) <- c('id', 'time', 'x', 'y')

Values of $$y$$ over time.

random_nums <- sample(c(1:700), 6)
df_sample <- df %>%
filter(id %in% random_nums)

ggplot(df, aes(x = time, y = y, group = id)) +
geom_point(color = 'grey85') +
geom_line(color = 'grey85') +
geom_point(data = df_sample, aes(x = time, y = y, group = id)) +
geom_line(data = df_sample, aes(x = time, y = y, group = id))

Values of $$x$$ over time.

plot_single_response <- function(y_axis){

plot_it <- ggplot(df, aes(x = time, y = !!y_axis, group = id)) +
geom_point(color = 'grey85') +
geom_line(color = 'grey85') +
geom_point(data = df_sample, aes(x = time, y = !!y_axis, group = id)) +
geom_line(data = df_sample, aes(x = time, y = !!y_axis, group = id))

return(plot_it)
}

plot_single_response(quo(x))

Three randomly selected individuals with $$x$$ and $$y$$ plotted simultaneously.

three_cases <- df %>%
filter(id == 4 | id == 500 | id == 322) %>%
gather(x, y, key = 'variable', value = 'response')

ggplot(three_cases, aes(x = time, y = response, color = variable)) +
geom_point() +
geom_line() +
facet_wrap(~id)

Dual Change Model on Y

df_wide_y <- df %>%
select(id, time, y) %>%
reshape(idvar = 'id', timevar = 'time', direction = 'wide')

library(lavaan)

dual_change_y_string <- '

# latent true scores over y
ly1 =~ 1*y.1
ly2 =~ 1*y.2
ly3 =~ 1*y.3
ly4 =~ 1*y.4
ly5 =~ 1*y.5
ly6 =~ 1*y.6

# latent change scores over the true scores (but not the first time point)
cy2 =~ 1*ly2
cy3 =~ 1*ly3
cy4 =~ 1*ly4
cy5 =~ 1*ly5
cy6 =~ 1*ly6

# autoregressions of latent true scores over y constrained to 1
ly2 ~ 1*ly1
ly3 ~ 1*ly2
ly4 ~ 1*ly3
ly5 ~ 1*ly4
ly6 ~ 1*ly5

# latent intercept over first latent true score on y
l_intercept =~ 1*ly1

# change component 1 of the dual change model

# latent slope (or change factor) over the change scores
l_slope =~ 1*cy2 + 1*cy3 + 1*cy4 + 1*cy5 + 1*cy6

# estimate means and variances of those intercept and slope terms
l_intercept ~~ l_intercept
l_slope ~~ l_slope
l_slope ~ 1
l_intercept ~ 1

# and a covariance between them
l_intercept ~~ l_slope

# change component 2 of the dual change model

# proportion change from true scores over y to the change factors
cy2 ~ prop*ly1
cy3 ~ prop*ly2
cy4 ~ prop*ly3
cy5 ~ prop*ly4
cy6 ~ prop*ly5

# means and variances of latent factors set to zero
ly1 ~ 0
ly2 ~ 0
ly3 ~ 0
ly4 ~ 0
ly5 ~ 0
ly6 ~ 0

cy2 ~ 0
cy3 ~ 0
cy4 ~ 0
cy5 ~ 0
cy6 ~ 0

ly1 ~~ 0*ly1
ly2 ~~ 0*ly2
ly3 ~~ 0*ly3
ly4 ~~ 0*ly4
ly5 ~~ 0*ly5
ly6 ~~ 0*ly6

cy2 ~~ 0*cy2
cy3 ~~ 0*cy3
cy4 ~~ 0*cy4
cy5 ~~ 0*cy5
cy6 ~~ 0*cy6

# means of indicators to zero
y.1 ~ 0
y.2 ~ 0
y.3 ~ 0
y.4 ~ 0
y.5 ~ 0
y.6 ~ 0

# residual variances constrained to equality across time
y.1 ~~ res_var*y.1
y.2 ~~ res_var*y.2
y.3 ~~ res_var*y.3
y.4 ~~ res_var*y.4
y.5 ~~ res_var*y.5
y.6 ~~ res_var*y.6

# do not allow change factors to correlate
cy2 ~~ 0*cy3 + 0*cy4 + 0*cy5 + 0*cy6
cy3 ~~ 0*cy4 + 0*cy5 + 0*cy6
cy4 ~~ 0*cy5 + 0*cy6
cy5 ~~ 0*cy6

'

dc_y_model <- sem(dual_change_y_string, data = df_wide_y)
summary(dc_y_model, fit.measures = T)
## lavaan 0.6-3 ended normally after 70 iterations
##
##   Optimization method                           NLMINB
##   Number of free parameters                         16
##   Number of equality constraints                     9
##
##   Number of observations                           700
##
##   Estimator                                         ML
##   Model Fit Test Statistic                    6067.310
##   Degrees of freedom                                20
##   P-value (Chi-square)                           0.000
##
## Model test baseline model:
##
##   Minimum Function Test Statistic             7955.551
##   Degrees of freedom                                15
##   P-value                                        0.000
##
## User model versus baseline model:
##
##   Comparative Fit Index (CFI)                    0.238
##   Tucker-Lewis Index (TLI)                       0.429
##
## Loglikelihood and Information Criteria:
##
##   Loglikelihood user model (H0)             -11519.219
##   Loglikelihood unrestricted model (H1)      -8485.564
##
##   Number of free parameters                          7
##   Akaike (AIC)                               23052.438
##   Bayesian (BIC)                             23084.296
##   Sample-size adjusted Bayesian (BIC)        23062.069
##
## Root Mean Square Error of Approximation:
##
##   RMSEA                                          0.657
##   90 Percent Confidence Interval          0.643  0.671
##   P-value RMSEA <= 0.05                          0.000
##
## Standardized Root Mean Square Residual:
##
##   SRMR                                           2.258
##
## Parameter Estimates:
##
##   Information                                 Expected
##   Information saturated (h1) model          Structured
##   Standard Errors                             Standard
##
## Latent Variables:
##                    Estimate  Std.Err  z-value  P(>|z|)
##   ly1 =~
##     y.1               1.000
##   ly2 =~
##     y.2               1.000
##   ly3 =~
##     y.3               1.000
##   ly4 =~
##     y.4               1.000
##   ly5 =~
##     y.5               1.000
##   ly6 =~
##     y.6               1.000
##   cy2 =~
##     ly2               1.000
##   cy3 =~
##     ly3               1.000
##   cy4 =~
##     ly4               1.000
##   cy5 =~
##     ly5               1.000
##   cy6 =~
##     ly6               1.000
##   l_intercept =~
##     ly1               1.000
##   l_slope =~
##     cy2               1.000
##     cy3               1.000
##     cy4               1.000
##     cy5               1.000
##     cy6               1.000
##
## Regressions:
##                    Estimate  Std.Err  z-value  P(>|z|)
##   ly2 ~
##     ly1               1.000
##   ly3 ~
##     ly2               1.000
##   ly4 ~
##     ly3               1.000
##   ly5 ~
##     ly4               1.000
##   ly6 ~
##     ly5               1.000
##   cy2 ~
##     ly1     (prop)    0.313    0.019   16.735    0.000
##   cy3 ~
##     ly2     (prop)    0.313    0.019   16.735    0.000
##   cy4 ~
##     ly3     (prop)    0.313    0.019   16.735    0.000
##   cy5 ~
##     ly4     (prop)    0.313    0.019   16.735    0.000
##   cy6 ~
##     ly5     (prop)    0.313    0.019   16.735    0.000
##
## Covariances:
##                    Estimate  Std.Err  z-value  P(>|z|)
##   l_intercept ~~
##     l_slope          -1.656    0.210   -7.881    0.000
##  .cy2 ~~
##    .cy3               0.000
##    .cy4               0.000
##    .cy5               0.000
##    .cy6               0.000
##  .cy3 ~~
##    .cy4               0.000
##    .cy5               0.000
##    .cy6               0.000
##  .cy4 ~~
##    .cy5               0.000
##    .cy6               0.000
##  .cy5 ~~
##    .cy6               0.000
##
## Intercepts:
##                    Estimate  Std.Err  z-value  P(>|z|)
##     l_slope          -3.976    0.207  -19.164    0.000
##     l_intercept      11.536    0.107  107.690    0.000
##     ly1               0.000
##    .ly2               0.000
##    .ly3               0.000
##    .ly4               0.000
##    .ly5               0.000
##    .ly6               0.000
##    .cy2               0.000
##    .cy3               0.000
##    .cy4               0.000
##    .cy5               0.000
##    .cy6               0.000
##    .y.1               0.000
##    .y.2               0.000
##    .y.3               0.000
##    .y.4               0.000
##    .y.5               0.000
##    .y.6               0.000
##
## Variances:
##                    Estimate  Std.Err  z-value  P(>|z|)
##     l_ntrcp           5.263    0.427   12.341    0.000
##     l_slope           2.069    0.171   12.095    0.000
##     ly1               0.000
##    .ly2               0.000
##    .ly3               0.000
##    .ly4               0.000
##    .ly5               0.000
##    .ly6               0.000
##    .cy2               0.000
##    .cy3               0.000
##    .cy4               0.000
##    .cy5               0.000
##    .cy6               0.000
##    .y.1     (rs_v)    6.411    0.171   37.417    0.000
##    .y.2     (rs_v)    6.411    0.171   37.417    0.000
##    .y.3     (rs_v)    6.411    0.171   37.417    0.000
##    .y.4     (rs_v)    6.411    0.171   37.417    0.000
##    .y.5     (rs_v)    6.411    0.171   37.417    0.000
##    .y.6     (rs_v)    6.411    0.171   37.417    0.000

Code to change the $$y$$’s in the string to $$x$$’s without manually deleting and inserting $$x$$ into the string above. All you have to do is paste the string into a .txt document and save the file as “y_file.txt”

library(readr)

new_data <- gsub('y', 'x', mystring)
# write_file(new_data, path = 'x_file.txt') # not executed but will work

Dual Change Model on X

df_wide_x <- df %>%
select(id, time, x) %>%
reshape(idvar = 'id', timevar = 'time', direction = 'wide')

library(lavaan)

dual_change_x_string <- '

# latent true scores over x
lx1 =~ 1*x.1
lx2 =~ 1*x.2
lx3 =~ 1*x.3
lx4 =~ 1*x.4
lx5 =~ 1*x.5
lx6 =~ 1*x.6

# latent change scores over the true scores (but not the first time point)
cx2 =~ 1*lx2
cx3 =~ 1*lx3
cx4 =~ 1*lx4
cx5 =~ 1*lx5
cx6 =~ 1*lx6

# autoregressions of latent true scores over x constrained to 1
lx2 ~ 1*lx1
lx3 ~ 1*lx2
lx4 ~ 1*lx3
lx5 ~ 1*lx4
lx6 ~ 1*lx5

# latent intercept over first latent true score on x
l_intercept =~ 1*lx1

# change component 1 of the dual change model

# latent slope (or change factor) over the change scores
l_slope =~ 1*cx2 + 1*cx3 + 1*cx4 + 1*cx5 + 1*cx6

# estimate means and variances of those intercept and slope terms
l_intercept ~~ l_intercept
l_slope ~~ l_slope
l_slope ~ 1
l_intercept ~ 1

# and a covariance between them
l_intercept ~~ l_slope

# change component 2 of the dual change model

# proportion change from true scores over x to the change factors
cx2 ~ prop*lx1
cx3 ~ prop*lx2
cx4 ~ prop*lx3
cx5 ~ prop*lx4
cx6 ~ prop*lx5

# means and variances of latent factors set to zero
lx1 ~ 0
lx2 ~ 0
lx3 ~ 0
lx4 ~ 0
lx5 ~ 0
lx6 ~ 0

cx2 ~ 0
cx3 ~ 0
cx4 ~ 0
cx5 ~ 0
cx6 ~ 0

lx1 ~~ 0*lx1
lx2 ~~ 0*lx2
lx3 ~~ 0*lx3
lx4 ~~ 0*lx4
lx5 ~~ 0*lx5
lx6 ~~ 0*lx6

cx2 ~~ 0*cx2
cx3 ~~ 0*cx3
cx4 ~~ 0*cx4
cx5 ~~ 0*cx5
cx6 ~~ 0*cx6

# means of indicators to zero
x.1 ~ 0
x.2 ~ 0
x.3 ~ 0
x.4 ~ 0
x.5 ~ 0
x.6 ~ 0

# residual variances constrained to equalitx across time
x.1 ~~ res_var*x.1
x.2 ~~ res_var*x.2
x.3 ~~ res_var*x.3
x.4 ~~ res_var*x.4
x.5 ~~ res_var*x.5
x.6 ~~ res_var*x.6

# do not allow change factors to correlate
cx2 ~~ 0*cx3 + 0*cx4 + 0*cx5 + 0*cx6
cx3 ~~ 0*cx4 + 0*cx5 + 0*cx6
cx4 ~~ 0*cx5 + 0*cx6
cx5 ~~ 0*cx6

'

dc_x_model <- sem(dual_change_x_string, data = df_wide_x)
summary(dc_x_model, fit.measures = T)
## lavaan 0.6-3 ended normally after 55 iterations
##
##   Optimization method                           NLMINB
##   Number of free parameters                         16
##   Number of equality constraints                     9
##
##   Number of observations                           700
##
##   Estimator                                         ML
##   Model Fit Test Statistic                    4046.134
##   Degrees of freedom                                20
##   P-value (Chi-square)                           0.000
##
## Model test baseline model:
##
##   Minimum Function Test Statistic            11769.574
##   Degrees of freedom                                15
##   P-value                                        0.000
##
## User model versus baseline model:
##
##   Comparative Fit Index (CFI)                    0.657
##   Tucker-Lewis Index (TLI)                       0.743
##
## Loglikelihood and Information Criteria:
##
##   Loglikelihood user model (H0)             -10105.606
##   Loglikelihood unrestricted model (H1)      -8082.539
##
##   Number of free parameters                          7
##   Akaike (AIC)                               20225.212
##   Bayesian (BIC)                             20257.069
##   Sample-size adjusted Bayesian (BIC)        20234.843
##
## Root Mean Square Error of Approximation:
##
##   RMSEA                                          0.536
##   90 Percent Confidence Interval          0.522  0.550
##   P-value RMSEA <= 0.05                          0.000
##
## Standardized Root Mean Square Residual:
##
##   SRMR                                           0.723
##
## Parameter Estimates:
##
##   Information                                 Expected
##   Information saturated (h1) model          Structured
##   Standard Errors                             Standard
##
## Latent Variables:
##                    Estimate  Std.Err  z-value  P(>|z|)
##   lx1 =~
##     x.1               1.000
##   lx2 =~
##     x.2               1.000
##   lx3 =~
##     x.3               1.000
##   lx4 =~
##     x.4               1.000
##   lx5 =~
##     x.5               1.000
##   lx6 =~
##     x.6               1.000
##   cx2 =~
##     lx2               1.000
##   cx3 =~
##     lx3               1.000
##   cx4 =~
##     lx4               1.000
##   cx5 =~
##     lx5               1.000
##   cx6 =~
##     lx6               1.000
##   l_intercept =~
##     lx1               1.000
##   l_slope =~
##     cx2               1.000
##     cx3               1.000
##     cx4               1.000
##     cx5               1.000
##     cx6               1.000
##
## Regressions:
##                    Estimate  Std.Err  z-value  P(>|z|)
##   lx2 ~
##     lx1               1.000
##   lx3 ~
##     lx2               1.000
##   lx4 ~
##     lx3               1.000
##   lx5 ~
##     lx4               1.000
##   lx6 ~
##     lx5               1.000
##   cx2 ~
##     lx1     (prop)    0.150    0.004   35.444    0.000
##   cx3 ~
##     lx2     (prop)    0.150    0.004   35.444    0.000
##   cx4 ~
##     lx3     (prop)    0.150    0.004   35.444    0.000
##   cx5 ~
##     lx4     (prop)    0.150    0.004   35.444    0.000
##   cx6 ~
##     lx5     (prop)    0.150    0.004   35.444    0.000
##
## Covariances:
##                    Estimate  Std.Err  z-value  P(>|z|)
##   l_intercept ~~
##     l_slope          -0.928    0.255   -3.641    0.000
##  .cx2 ~~
##    .cx3               0.000
##    .cx4               0.000
##    .cx5               0.000
##    .cx6               0.000
##  .cx3 ~~
##    .cx4               0.000
##    .cx5               0.000
##    .cx6               0.000
##  .cx4 ~~
##    .cx5               0.000
##    .cx6               0.000
##  .cx5 ~~
##    .cx6               0.000
##
## Intercepts:
##                    Estimate  Std.Err  z-value  P(>|z|)
##     l_slope          -3.468    0.123  -28.161    0.000
##     l_intercept      10.332    0.077  134.910    0.000
##     lx1               0.000
##    .lx2               0.000
##    .lx3               0.000
##    .lx4               0.000
##    .lx5               0.000
##    .lx6               0.000
##    .cx2               0.000
##    .cx3               0.000
##    .cx4               0.000
##    .cx5               0.000
##    .cx6               0.000
##    .x.1               0.000
##    .x.2               0.000
##    .x.3               0.000
##    .x.4               0.000
##    .x.5               0.000
##    .x.6               0.000
##
## Variances:
##                    Estimate  Std.Err  z-value  P(>|z|)
##     l_ntrcp           2.969    0.212   14.021    0.000
##     l_slope          10.023    0.574   17.467    0.000
##     lx1               0.000
##    .lx2               0.000
##    .lx3               0.000
##    .lx4               0.000
##    .lx5               0.000
##    .lx6               0.000
##    .cx2               0.000
##    .cx3               0.000
##    .cx4               0.000
##    .cx5               0.000
##    .cx6               0.000
##    .x.1     (rs_v)    2.088    0.056   37.417    0.000
##    .x.2     (rs_v)    2.088    0.056   37.417    0.000
##    .x.3     (rs_v)    2.088    0.056   37.417    0.000
##    .x.4     (rs_v)    2.088    0.056   37.417    0.000
##    .x.5     (rs_v)    2.088    0.056   37.417    0.000
##    .x.6     (rs_v)    2.088    0.056   37.417    0.000

Bivariate Dual Change Model

bi_dc_string <- '

# DUAL CHANGE IN Y

#

#

#

# latent true scores over y
ly1 =~ 1*y.1
ly2 =~ 1*y.2
ly3 =~ 1*y.3
ly4 =~ 1*y.4
ly5 =~ 1*y.5
ly6 =~ 1*y.6

# latent change scores over the true scores (but not the first time point)
cy2 =~ 1*ly2
cy3 =~ 1*ly3
cy4 =~ 1*ly4
cy5 =~ 1*ly5
cy6 =~ 1*ly6

# autoregressions of latent true scores over y constrained to 1
ly2 ~ 1*ly1
ly3 ~ 1*ly2
ly4 ~ 1*ly3
ly5 ~ 1*ly4
ly6 ~ 1*ly5

# latent intercept over first latent true score on y
l_intercept =~ 1*ly1

# change component 1 of the dual change model

# latent slope (or change factor) over the change scores
l_slope =~ 1*cy2 + 1*cy3 + 1*cy4 + 1*cy5 + 1*cy6

# estimate means and variances of those intercept and slope terms
l_intercept ~~ l_intercept
l_slope ~~ l_slope
l_slope ~ 1
l_intercept ~ 1

# and a covariance between them
l_intercept ~~ l_slope

# change component 2 of the dual change model

# proportion change from true scores over y to the change factors
cy2 ~ prop*ly1
cy3 ~ prop*ly2
cy4 ~ prop*ly3
cy5 ~ prop*ly4
cy6 ~ prop*ly5

# means and variances of latent factors set to zero
ly1 ~ 0
ly2 ~ 0
ly3 ~ 0
ly4 ~ 0
ly5 ~ 0
ly6 ~ 0

cy2 ~ 0
cy3 ~ 0
cy4 ~ 0
cy5 ~ 0
cy6 ~ 0

ly1 ~~ 0*ly1
ly2 ~~ 0*ly2
ly3 ~~ 0*ly3
ly4 ~~ 0*ly4
ly5 ~~ 0*ly5
ly6 ~~ 0*ly6

cy2 ~~ 0*cy2
cy3 ~~ 0*cy3
cy4 ~~ 0*cy4
cy5 ~~ 0*cy5
cy6 ~~ 0*cy6

# means of indicators to zero
y.1 ~ 0
y.2 ~ 0
y.3 ~ 0
y.4 ~ 0
y.5 ~ 0
y.6 ~ 0

# residual variances constrained to equality across time
y.1 ~~ res_var*y.1
y.2 ~~ res_var*y.2
y.3 ~~ res_var*y.3
y.4 ~~ res_var*y.4
y.5 ~~ res_var*y.5
y.6 ~~ res_var*y.6

# do not allow change factors to correlate
cy2 ~~ 0*cy3 + 0*cy4 + 0*cy5 + 0*cy6
cy3 ~~ 0*cy4 + 0*cy5 + 0*cy6
cy4 ~~ 0*cy5 + 0*cy6
cy5 ~~ 0*cy6

# DUAL CHANGE IN X

#

#

#

# latent true scores over x
lx1 =~ 1*x.1
lx2 =~ 1*x.2
lx3 =~ 1*x.3
lx4 =~ 1*x.4
lx5 =~ 1*x.5
lx6 =~ 1*x.6

# latent change scores over the true scores (but not the first time point)
cx2 =~ 1*lx2
cx3 =~ 1*lx3
cx4 =~ 1*lx4
cx5 =~ 1*lx5
cx6 =~ 1*lx6

# autoregressions of latent true scores over x constrained to 1
lx2 ~ 1*lx1
lx3 ~ 1*lx2
lx4 ~ 1*lx3
lx5 ~ 1*lx4
lx6 ~ 1*lx5

# latent intercept over first latent true score on x
lx_intercept =~ 1*lx1

# change component 1 of the dual change model

# latent slope (or change factor) over the change scores
lx_slope =~ 1*cx2 + 1*cx3 + 1*cx4 + 1*cx5 + 1*cx6

# estimate means and variances of those intercept and slope terms
lx_intercept ~~ lx_intercept
lx_slope ~~ lx_slope
lx_slope ~ 1
lx_intercept ~ 1

# and a covariance between them
lx_intercept ~~ lx_slope

# change component 2 of the dual change model

# proportion change from true scores over x to the change factors
cx2 ~ propx*lx1
cx3 ~ propx*lx2
cx4 ~ propx*lx3
cx5 ~ propx*lx4
cx6 ~ propx*lx5

# means and variances of latent factors set to zero
lx1 ~ 0
lx2 ~ 0
lx3 ~ 0
lx4 ~ 0
lx5 ~ 0
lx6 ~ 0

cx2 ~ 0
cx3 ~ 0
cx4 ~ 0
cx5 ~ 0
cx6 ~ 0

lx1 ~~ 0*lx1
lx2 ~~ 0*lx2
lx3 ~~ 0*lx3
lx4 ~~ 0*lx4
lx5 ~~ 0*lx5
lx6 ~~ 0*lx6

cx2 ~~ 0*cx2
cx3 ~~ 0*cx3
cx4 ~~ 0*cx4
cx5 ~~ 0*cx5
cx6 ~~ 0*cx6

# means of indicators to zero
x.1 ~ 0
x.2 ~ 0
x.3 ~ 0
x.4 ~ 0
x.5 ~ 0
x.6 ~ 0

# residual variances constrained to equalitx across time
x.1 ~~ res_varx*x.1
x.2 ~~ res_varx*x.2
x.3 ~~ res_varx*x.3
x.4 ~~ res_varx*x.4
x.5 ~~ res_varx*x.5
x.6 ~~ res_varx*x.6

# do not allow change factors to correlate
cx2 ~~ 0*cx3 + 0*cx4 + 0*cx5 + 0*cx6
cx3 ~~ 0*cx4 + 0*cx5 + 0*cx6
cx4 ~~ 0*cx5 + 0*cx6
cx5 ~~ 0*cx6

# COUPLING

#

#

cy2 ~ xy*lx1
cy3 ~ xy*lx2
cy4 ~ xy*lx3
cy5 ~ xy*lx4
cy6 ~ xy*lx5

cx2 ~ yx*ly1
cx3 ~ yx*ly2
cx4 ~ yx*ly3
cx5 ~ yx*ly4
cx6 ~ yx*ly5

'

df_both <- df %>%
reshape(idvar = 'id', timevar = 'time', direction = 'wide')

bi_dc_model <- sem(bi_dc_string, data = df_both)
summary(bi_dc_model, fit.measures = T)
## lavaan 0.6-3 ended normally after 117 iterations
##
##   Optimization method                           NLMINB
##   Number of free parameters                         46
##   Number of equality constraints                    26
##
##   Number of observations                           700
##
##   Estimator                                         ML
##   Model Fit Test Statistic                    1422.723
##   Degrees of freedom                                70
##   P-value (Chi-square)                           0.000
##
## Model test baseline model:
##
##   Minimum Function Test Statistic            23848.355
##   Degrees of freedom                                66
##   P-value                                        0.000
##
## User model versus baseline model:
##
##   Comparative Fit Index (CFI)                    0.943
##   Tucker-Lewis Index (TLI)                       0.946
##
## Loglikelihood and Information Criteria:
##
##   Loglikelihood user model (H0)             -15217.849
##   Loglikelihood unrestricted model (H1)     -14506.488
##
##   Number of free parameters                         20
##   Akaike (AIC)                               30475.699
##   Bayesian (BIC)                             30566.721
##   Sample-size adjusted Bayesian (BIC)        30503.217
##
## Root Mean Square Error of Approximation:
##
##   RMSEA                                          0.166
##   90 Percent Confidence Interval          0.159  0.174
##   P-value RMSEA <= 0.05                          0.000
##
## Standardized Root Mean Square Residual:
##
##   SRMR                                           0.098
##
## Parameter Estimates:
##
##   Information                                 Expected
##   Information saturated (h1) model          Structured
##   Standard Errors                             Standard
##
## Latent Variables:
##                    Estimate  Std.Err  z-value  P(>|z|)
##   ly1 =~
##     y.1               1.000
##   ly2 =~
##     y.2               1.000
##   ly3 =~
##     y.3               1.000
##   ly4 =~
##     y.4               1.000
##   ly5 =~
##     y.5               1.000
##   ly6 =~
##     y.6               1.000
##   cy2 =~
##     ly2               1.000
##   cy3 =~
##     ly3               1.000
##   cy4 =~
##     ly4               1.000
##   cy5 =~
##     ly5               1.000
##   cy6 =~
##     ly6               1.000
##   l_intercept =~
##     ly1               1.000
##   l_slope =~
##     cy2               1.000
##     cy3               1.000
##     cy4               1.000
##     cy5               1.000
##     cy6               1.000
##   lx1 =~
##     x.1               1.000
##   lx2 =~
##     x.2               1.000
##   lx3 =~
##     x.3               1.000
##   lx4 =~
##     x.4               1.000
##   lx5 =~
##     x.5               1.000
##   lx6 =~
##     x.6               1.000
##   cx2 =~
##     lx2               1.000
##   cx3 =~
##     lx3               1.000
##   cx4 =~
##     lx4               1.000
##   cx5 =~
##     lx5               1.000
##   cx6 =~
##     lx6               1.000
##   lx_intercept =~
##     lx1               1.000
##   lx_slope =~
##     cx2               1.000
##     cx3               1.000
##     cx4               1.000
##     cx5               1.000
##     cx6               1.000
##
## Regressions:
##                    Estimate  Std.Err  z-value  P(>|z|)
##   ly2 ~
##     ly1               1.000
##   ly3 ~
##     ly2               1.000
##   ly4 ~
##     ly3               1.000
##   ly5 ~
##     ly4               1.000
##   ly6 ~
##     ly5               1.000
##   cy2 ~
##     ly1     (prop)   -0.315    0.004  -74.218    0.000
##   cy3 ~
##     ly2     (prop)   -0.315    0.004  -74.218    0.000
##   cy4 ~
##     ly3     (prop)   -0.315    0.004  -74.218    0.000
##   cy5 ~
##     ly4     (prop)   -0.315    0.004  -74.218    0.000
##   cy6 ~
##     ly5     (prop)   -0.315    0.004  -74.218    0.000
##   lx2 ~
##     lx1               1.000
##   lx3 ~
##     lx2               1.000
##   lx4 ~
##     lx3               1.000
##   lx5 ~
##     lx4               1.000
##   lx6 ~
##     lx5               1.000
##   cx2 ~
##     lx1     (prpx)    0.225    0.002  101.044    0.000
##   cx3 ~
##     lx2     (prpx)    0.225    0.002  101.044    0.000
##   cx4 ~
##     lx3     (prpx)    0.225    0.002  101.044    0.000
##   cx5 ~
##     lx4     (prpx)    0.225    0.002  101.044    0.000
##   cx6 ~
##     lx5     (prpx)    0.225    0.002  101.044    0.000
##   cy2 ~
##     lx1       (xy)    0.403    0.002  184.708    0.000
##   cy3 ~
##     lx2       (xy)    0.403    0.002  184.708    0.000
##   cy4 ~
##     lx3       (xy)    0.403    0.002  184.708    0.000
##   cy5 ~
##     lx4       (xy)    0.403    0.002  184.708    0.000
##   cy6 ~
##     lx5       (xy)    0.403    0.002  184.708    0.000
##   cx2 ~
##     ly1       (yx)   -0.420    0.004  -96.376    0.000
##   cx3 ~
##     ly2       (yx)   -0.420    0.004  -96.376    0.000
##   cx4 ~
##     ly3       (yx)   -0.420    0.004  -96.376    0.000
##   cx5 ~
##     ly4       (yx)   -0.420    0.004  -96.376    0.000
##   cx6 ~
##     ly5       (yx)   -0.420    0.004  -96.376    0.000
##
## Covariances:
##                    Estimate  Std.Err  z-value  P(>|z|)
##   l_intercept ~~
##     l_slope          -0.134    0.136   -0.985    0.324
##  .cy2 ~~
##    .cy3               0.000
##    .cy4               0.000
##    .cy5               0.000
##    .cy6               0.000
##  .cy3 ~~
##    .cy4               0.000
##    .cy5               0.000
##    .cy6               0.000
##  .cy4 ~~
##    .cy5               0.000
##    .cy6               0.000
##  .cy5 ~~
##    .cy6               0.000
##   lx_intercept ~~
##     lx_slope         -0.033    0.135   -0.244    0.807
##  .cx2 ~~
##    .cx3               0.000
##    .cx4               0.000
##    .cx5               0.000
##    .cx6               0.000
##  .cx3 ~~
##    .cx4               0.000
##    .cx5               0.000
##    .cx6               0.000
##  .cx4 ~~
##    .cx5               0.000
##    .cx6               0.000
##  .cx5 ~~
##    .cx6               0.000
##   l_intercept ~~
##     lx_intercept     -0.130    0.051   -2.526    0.012
##     lx_slope          0.001    0.140    0.009    0.993
##   l_slope ~~
##     lx_intercept     -0.051    0.131   -0.393    0.695
##     lx_slope          0.213    0.336    0.635    0.526
##
## Intercepts:
##                    Estimate  Std.Err  z-value  P(>|z|)
##     l_slope           0.466    0.117    3.994    0.000
##     l_intercept       9.983    0.045  220.323    0.000
##     ly1               0.000
##    .ly2               0.000
##    .ly3               0.000
##    .ly4               0.000
##    .ly5               0.000
##    .ly6               0.000
##    .cy2               0.000
##    .cy3               0.000
##    .cy4               0.000
##    .cy5               0.000
##    .cy6               0.000
##    .y.1               0.000
##    .y.2               0.000
##    .y.3               0.000
##    .y.4               0.000
##    .y.5               0.000
##    .y.6               0.000
##     lx_slope          0.664    0.122    5.441    0.000
##     lx_intercept      9.937    0.044  224.982    0.000
##     lx1               0.000
##    .lx2               0.000
##    .lx3               0.000
##    .lx4               0.000
##    .lx5               0.000
##    .lx6               0.000
##    .cx2               0.000
##    .cx3               0.000
##    .cx4               0.000
##    .cx5               0.000
##    .cx6               0.000
##    .x.1               0.000
##    .x.2               0.000
##    .x.3               0.000
##    .x.4               0.000
##    .x.5               0.000
##    .x.6               0.000
##
## Variances:
##                    Estimate  Std.Err  z-value  P(>|z|)
##     l_ntr             0.965    0.075   12.954    0.000
##     l_slp             8.201    0.454   18.047    0.000
##     ly1               0.000
##    .ly2               0.000
##    .ly3               0.000
##    .ly4               0.000
##    .ly5               0.000
##    .ly6               0.000
##    .cy2               0.000
##    .cy3               0.000
##    .cy4               0.000
##    .cy5               0.000
##    .cy6               0.000
##    .y.1   (res_vr)    0.726    0.019   37.348    0.000
##    .y.2   (res_vr)    0.726    0.019   37.348    0.000
##    .y.3   (res_vr)    0.726    0.019   37.348    0.000
##    .y.4   (res_vr)    0.726    0.019   37.348    0.000
##    .y.5   (res_vr)    0.726    0.019   37.348    0.000
##    .y.6   (res_vr)    0.726    0.019   37.348    0.000
##     lx_nt             1.140    0.071   16.062    0.000
##     lx_sl             9.056    0.494   18.318    0.000
##     lx1               0.000
##    .lx2               0.000
##    .lx3               0.000
##    .lx4               0.000
##    .lx5               0.000
##    .lx6               0.000
##    .cx2               0.000
##    .cx3               0.000
##    .cx4               0.000
##    .cx5               0.000
##    .cx6               0.000
##    .x.1   (rs_vrx)    0.417    0.011   36.461    0.000
##    .x.2   (rs_vrx)    0.417    0.011   36.461    0.000
##    .x.3   (rs_vrx)    0.417    0.011   36.461    0.000
##    .x.4   (rs_vrx)    0.417    0.011   36.461    0.000
##    .x.5   (rs_vrx)    0.417    0.011   36.461    0.000
##    .x.6   (rs_vrx)    0.417    0.011   36.461    0.000

Bo$$^2$$m =)