A few spline models (also known as piecewise models). As in previous posts, ‘affect’ is the name given to values of $$y$$ throughout.

# 1) Growth and Even More Growth

A model that captures a process that increases initially and then increases at an even greater rate once it reaches time point 5. The data generating process:

$$$y_{it} = \begin{cases} 4 + 0.3t + error_{t}, & \text{if time < 5}\\ 8 + 0.9t + error_{t}, & \text{otherwise} \end{cases}$$$

The data generating code and plot

library(tidyverse)
library(lavaan)
library(ggplot2)
library(MASS)

N <- 400
time <- 10

intercept_1 <- 4
intercept_2 <- 8

growth1 <- 0.3
growth2 <- 0.9

df_matrix <- matrix(, ncol = 3, nrow = N*time)

count <- 0

for(i in 1:N){

unob_het_y <- rnorm(1,0,1)

for(j in 1:time){

count <- count + 1

if(j < 5){
df_matrix[count, 1] <- i
df_matrix[count, 2] <- j
df_matrix[count, 3] <- intercept_1 + growth1*j + unob_het_y + rnorm(1,0,1)

}else{

df_matrix[count, 1] <- i
df_matrix[count, 2] <- j
df_matrix[count, 3] <- intercept_2 + growth2*j + unob_het_y + rnorm(1,0,1)

}
}

}

df <- data.frame(df_matrix)

names(df) <- c('id', 'time', 'affect')

df1 <- df %>%
filter(time < 5)

df2 <- df %>%
filter(time >= 5)

df_sum1 <- df1 %>%
group_by(time) %>%
summarise(
affect = mean(affect)
)

df_sum2 <- df2 %>%
group_by(time) %>%
summarise(
affect = mean(affect)
)

ggplot() +
geom_point(data = df1, aes(x = time, y = affect, group = id), color = 'gray85') +
geom_line(data = df1, aes(x = time, y = affect, group = id), color = 'gray85') +
geom_point(data = df2, aes(x = time, y = affect, group = id), color = 'gray85') +
geom_line(data = df2, aes(x = time, y = affect, group = id), color = 'gray85') +
geom_line(data = df_sum1, aes(x = time, y = affect)) +
geom_line(data = df_sum2, aes(x = time, y = affect))

Estimating the parameters using SEM:

library(lavaan)

df_wide <- reshape(df, idvar = 'id', timevar = 'time', direction = 'wide')

spline_string <- '

# latent intercept for first half

level1_affect =~ 1*affect.1 + 1*affect.2 + 1*affect.3 + 1*affect.4 + 0*affect.5 + 0*affect.6 + 0*affect.7 + 0*affect.8 + 0*affect.9 + 0*affect.10

# latent intercept for second half

level2_affect =~ 0*affect.1 + 0*affect.2 + 0*affect.3 + 0*affect.4 + 1*affect.5 + 1*affect.6 + 1*affect.7 + 1*affect.8 + 1*affect.9 + 1*affect.10

# latent slope for first half basis coefficients

slope1_affect =~ 1*affect.1 + 2*affect.2 + 3*affect.3 + 4*affect.4 + 0*affect.5 + 0*affect.6 + 0*affect.7 + 0*affect.8 + 0*affect.9 + 0*affect.10

# latent slope for second half basis coefficients

slope2_affect =~ 0*affect.1 + 0*affect.2 + 0*affect.3 + 0*affect.4 + 5*affect.5 + 6*affect.6 + 7*affect.7 + 8*affect.8 + 9*affect.9 + 10*affect.10

# means and variance of latent factors

level1_affect ~~ level1_affect
level2_affect ~~ level2_affect
slope1_affect ~~ slope1_affect
slope2_affect ~~ slope2_affect

# covariance between latent factors

level1_affect ~~ level2_affect
level1_affect ~~ slope1_affect
level1_affect ~~ slope2_affect

level2_affect ~~ slope1_affect
level2_affect ~~ slope2_affect

slope1_affect ~~ slope2_affect

# constrain means of indicators to zero across time

affect.1 ~ 0
affect.2 ~ 0
affect.3 ~ 0
affect.4 ~ 0
affect.5 ~ 0
affect.6 ~ 0
affect.7 ~ 0
affect.8 ~ 0
affect.9 ~ 0
affect.10 ~ 0

# constrain residual variance to equality across time

affect.1 ~~ res_var*affect.1
affect.2 ~~ res_var*affect.2
affect.3 ~~ res_var*affect.3
affect.4 ~~ res_var*affect.4
affect.5 ~~ res_var*affect.5
affect.6 ~~ res_var*affect.6
affect.7 ~~ res_var*affect.7
affect.8 ~~ res_var*affect.8
affect.9 ~~ res_var*affect.9
affect.10 ~~ res_var*affect.10

'

spline_model <- growth(spline_string, data = df_wide)
summary(spline_model, fit.measures = T)
## lavaan 0.6-2 ended normally after 84 iterations
##
##   Optimization method                           NLMINB
##   Number of free parameters                         24
##   Number of equality constraints                     9
##
##   Number of observations                           400
##
##   Estimator                                         ML
##   Model Fit Test Statistic                      46.125
##   Degrees of freedom                                50
##   P-value (Chi-square)                           0.630
##
## Model test baseline model:
##
##   Minimum Function Test Statistic             1868.923
##   Degrees of freedom                                45
##   P-value                                        0.000
##
## User model versus baseline model:
##
##   Comparative Fit Index (CFI)                    1.000
##   Tucker-Lewis Index (TLI)                       1.002
##
## Loglikelihood and Information Criteria:
##
##   Loglikelihood user model (H0)              -6175.494
##   Loglikelihood unrestricted model (H1)      -6152.432
##
##   Number of free parameters                         15
##   Akaike (AIC)                               12380.988
##   Bayesian (BIC)                             12440.860
##   Sample-size adjusted Bayesian (BIC)        12393.264
##
## Root Mean Square Error of Approximation:
##
##   RMSEA                                          0.000
##   90 Percent Confidence Interval          0.000  0.028
##   P-value RMSEA <= 0.05                          1.000
##
## Standardized Root Mean Square Residual:
##
##   SRMR                                           0.031
##
## Parameter Estimates:
##
##   Information                                 Expected
##   Information saturated (h1) model          Structured
##   Standard Errors                             Standard
##
## Latent Variables:
##                    Estimate  Std.Err  z-value  P(>|z|)
##   level1_affect =~
##     affect.1          1.000
##     affect.2          1.000
##     affect.3          1.000
##     affect.4          1.000
##     affect.5          0.000
##     affect.6          0.000
##     affect.7          0.000
##     affect.8          0.000
##     affect.9          0.000
##     affect.10         0.000
##   level2_affect =~
##     affect.1          0.000
##     affect.2          0.000
##     affect.3          0.000
##     affect.4          0.000
##     affect.5          1.000
##     affect.6          1.000
##     affect.7          1.000
##     affect.8          1.000
##     affect.9          1.000
##     affect.10         1.000
##   slope1_affect =~
##     affect.1          1.000
##     affect.2          2.000
##     affect.3          3.000
##     affect.4          4.000
##     affect.5          0.000
##     affect.6          0.000
##     affect.7          0.000
##     affect.8          0.000
##     affect.9          0.000
##     affect.10         0.000
##   slope2_affect =~
##     affect.1          0.000
##     affect.2          0.000
##     affect.3          0.000
##     affect.4          0.000
##     affect.5          5.000
##     affect.6          6.000
##     affect.7          7.000
##     affect.8          8.000
##     affect.9          9.000
##     affect.10        10.000
##
## Covariances:
##                    Estimate  Std.Err  z-value  P(>|z|)
##   level1_affect ~~
##     level2_affect     1.061    0.181    5.870    0.000
##     slope1_affect     0.005    0.046    0.105    0.916
##     slope2_affect    -0.003    0.020   -0.129    0.898
##   level2_affect ~~
##     slope1_affect     0.018    0.048    0.368    0.713
##     slope2_affect    -0.053    0.039   -1.374    0.169
##   slope1_affect ~~
##     slope2_affect    -0.003    0.006   -0.587    0.557
##
## Intercepts:
##                    Estimate  Std.Err  z-value  P(>|z|)
##    .affect.1          0.000
##    .affect.2          0.000
##    .affect.3          0.000
##    .affect.4          0.000
##    .affect.5          0.000
##    .affect.6          0.000
##    .affect.7          0.000
##    .affect.8          0.000
##    .affect.9          0.000
##    .affect.10         0.000
##     level1_affect     4.050    0.080   50.730    0.000
##     level2_affect     8.165    0.108   75.429    0.000
##     slope1_affect     0.315    0.022   14.251    0.000
##     slope2_affect     0.889    0.013   69.317    0.000
##
## Variances:
##                    Estimate  Std.Err  z-value  P(>|z|)
##     lvl1_ff           1.049    0.185    5.658    0.000
##     lvl2_ff           1.304    0.345    3.775    0.000
##     slp1_ff          -0.004    0.015   -0.269    0.788
##     slp2_ff           0.009    0.005    1.755    0.079
##    .affct.1 (rs_v)    1.000    0.029   34.641    0.000
##    .affct.2 (rs_v)    1.000    0.029   34.641    0.000
##    .affct.3 (rs_v)    1.000    0.029   34.641    0.000
##    .affct.4 (rs_v)    1.000    0.029   34.641    0.000
##    .affct.5 (rs_v)    1.000    0.029   34.641    0.000
##    .affct.6 (rs_v)    1.000    0.029   34.641    0.000
##    .affct.7 (rs_v)    1.000    0.029   34.641    0.000
##    .affct.8 (rs_v)    1.000    0.029   34.641    0.000
##    .affct.9 (rs_v)    1.000    0.029   34.641    0.000
##    .affc.10 (rs_v)    1.000    0.029   34.641    0.000

The structure of the basis coefficients is the important piece that allows us to capture the change in slope:

'
# latent slope for first half basis coefficients

slope1_affect =~ 1*affect.1 + 2*affect.2 + 3*affect.3 + 4*affect.4 + 0*affect.5 + 0*affect.6 + 0*affect.7 + 0*affect.8 + 0*affect.9 + 0*affect.10

# latent slope for second half basis coefficients

slope2_affect =~ 0*affect.1 + 0*affect.2 + 0*affect.3 + 0*affect.4 + 5*affect.5 + 6*affect.6 + 7*affect.7 + 8*affect.8 + 9*affect.9 + 10*affect.10

'

# 2) Growth and Negative Growth

A model that captures a process that goes up and then goes down. The data generating process:

$$$y_{it} = \begin{cases} 4 + 0.5t + error_{t}, & \text{if time < 5}\\ 4 - 0.5t + error_{t}, & \text{otherwise} \end{cases}$$$

The data generating code and plot

library(tidyverse)
library(lavaan)
library(ggplot2)
library(MASS)

N <- 400
time <- 10

intercept_1 <- 4
intercept_2 <- 4

growth1 <- 0.8
growth2 <- -0.8

df_matrix_b <- matrix(, ncol = 3, nrow = N*time)

count <- 0

for(i in 1:N){

unob_het_y <- rnorm(1,0,1)

for(j in 1:time){

count <- count + 1

if(j < 5){
df_matrix_b[count, 1] <- i
df_matrix_b[count, 2] <- j
df_matrix_b[count, 3] <- intercept_1 + growth1*j + unob_het_y + rnorm(1,0,1)

}else{

df_matrix_b[count, 1] <- i
df_matrix_b[count, 2] <- j
df_matrix_b[count, 3] <- intercept_2 + growth2*j + unob_het_y + rnorm(1,0,1)

}
}

}

df_b <- data.frame(df_matrix_b)

names(df_b) <- c('id', 'time', 'affect')

df1_b <- df_b %>%
filter(time < 5)

df2_b <- df_b %>%
filter(time >= 5)

df_sum1_b <- df1_b %>%
group_by(time) %>%
summarise(
affect = mean(affect)
)

df_sum2_b <- df2_b %>%
group_by(time) %>%
summarise(
affect = mean(affect)
)

ggplot() +
geom_point(data = df1_b, aes(x = time, y = affect, group = id), color = 'gray85') +
geom_line(data = df1_b, aes(x = time, y = affect, group = id), color = 'gray85') +
geom_point(data = df2_b, aes(x = time, y = affect, group = id), color = 'gray85') +
geom_line(data = df2_b, aes(x = time, y = affect, group = id), color = 'gray85') +
geom_line(data = df_sum1_b, aes(x = time, y = affect)) +
geom_line(data = df_sum2_b, aes(x = time, y = affect))

Estimating the parameters using SEM:

library(lavaan)

df_wide_b <- reshape(df_b, idvar = 'id', timevar = 'time', direction = 'wide')

spline_string_b <- '

# latent intercept for first half

level1_affect =~ 1*affect.1 + 1*affect.2 + 1*affect.3 + 1*affect.4 + 0*affect.5 + 0*affect.6 + 0*affect.7 + 0*affect.8 + 0*affect.9 + 0*affect.10

# latent intercept for second half

level2_affect =~ 0*affect.1 + 0*affect.2 + 0*affect.3 + 0*affect.4 + 1*affect.5 + 1*affect.6 + 1*affect.7 + 1*affect.8 + 1*affect.9 + 1*affect.10

# latent slope for first half basis coefficients

slope1_affect =~ 1*affect.1 + 2*affect.2 + 3*affect.3 + 4*affect.4 + 0*affect.5 + 0*affect.6 + 0*affect.7 + 0*affect.8 + 0*affect.9 + 0*affect.10

# latent slope for second half basis coefficients

slope2_affect =~ 0*affect.1 + 0*affect.2 + 0*affect.3 + 0*affect.4 + 5*affect.5 + 6*affect.6 + 7*affect.7 + 8*affect.8 + 9*affect.9 + 10*affect.10

# means and variance of latent factors

level1_affect ~~ level1_affect
level2_affect ~~ level2_affect
slope1_affect ~~ slope1_affect
slope2_affect ~~ slope2_affect

# covariance between latent factors

level1_affect ~~ level2_affect
level1_affect ~~ slope1_affect
level1_affect ~~ slope2_affect

level2_affect ~~ slope1_affect
level2_affect ~~ slope2_affect

slope1_affect ~~ slope2_affect

# constrain means of indicators to zero across time

affect.1 ~ 0
affect.2 ~ 0
affect.3 ~ 0
affect.4 ~ 0
affect.5 ~ 0
affect.6 ~ 0
affect.7 ~ 0
affect.8 ~ 0
affect.9 ~ 0
affect.10 ~ 0

# constrain residual variance to equality across time

affect.1 ~~ res_var*affect.1
affect.2 ~~ res_var*affect.2
affect.3 ~~ res_var*affect.3
affect.4 ~~ res_var*affect.4
affect.5 ~~ res_var*affect.5
affect.6 ~~ res_var*affect.6
affect.7 ~~ res_var*affect.7
affect.8 ~~ res_var*affect.8
affect.9 ~~ res_var*affect.9
affect.10 ~~ res_var*affect.10

'

spline_model_b <- growth(spline_string_b, data = df_wide_b)
summary(spline_model_b, fit.measures = T)
## lavaan 0.6-2 ended normally after 68 iterations
##
##   Optimization method                           NLMINB
##   Number of free parameters                         24
##   Number of equality constraints                     9
##
##   Number of observations                           400
##
##   Estimator                                         ML
##   Model Fit Test Statistic                      57.374
##   Degrees of freedom                                50
##   P-value (Chi-square)                           0.221
##
## Model test baseline model:
##
##   Minimum Function Test Statistic             2053.910
##   Degrees of freedom                                45
##   P-value                                        0.000
##
## User model versus baseline model:
##
##   Comparative Fit Index (CFI)                    0.996
##   Tucker-Lewis Index (TLI)                       0.997
##
## Loglikelihood and Information Criteria:
##
##   Loglikelihood user model (H0)              -6150.596
##   Loglikelihood unrestricted model (H1)      -6121.909
##
##   Number of free parameters                         15
##   Akaike (AIC)                               12331.193
##   Bayesian (BIC)                             12391.065
##   Sample-size adjusted Bayesian (BIC)        12343.469
##
## Root Mean Square Error of Approximation:
##
##   RMSEA                                          0.019
##   90 Percent Confidence Interval          0.000  0.039
##   P-value RMSEA <= 0.05                          0.998
##
## Standardized Root Mean Square Residual:
##
##   SRMR                                           0.028
##
## Parameter Estimates:
##
##   Information                                 Expected
##   Information saturated (h1) model          Structured
##   Standard Errors                             Standard
##
## Latent Variables:
##                    Estimate  Std.Err  z-value  P(>|z|)
##   level1_affect =~
##     affect.1          1.000
##     affect.2          1.000
##     affect.3          1.000
##     affect.4          1.000
##     affect.5          0.000
##     affect.6          0.000
##     affect.7          0.000
##     affect.8          0.000
##     affect.9          0.000
##     affect.10         0.000
##   level2_affect =~
##     affect.1          0.000
##     affect.2          0.000
##     affect.3          0.000
##     affect.4          0.000
##     affect.5          1.000
##     affect.6          1.000
##     affect.7          1.000
##     affect.8          1.000
##     affect.9          1.000
##     affect.10         1.000
##   slope1_affect =~
##     affect.1          1.000
##     affect.2          2.000
##     affect.3          3.000
##     affect.4          4.000
##     affect.5          0.000
##     affect.6          0.000
##     affect.7          0.000
##     affect.8          0.000
##     affect.9          0.000
##     affect.10         0.000
##   slope2_affect =~
##     affect.1          0.000
##     affect.2          0.000
##     affect.3          0.000
##     affect.4          0.000
##     affect.5          5.000
##     affect.6          6.000
##     affect.7          7.000
##     affect.8          8.000
##     affect.9          9.000
##     affect.10        10.000
##
## Covariances:
##                    Estimate  Std.Err  z-value  P(>|z|)
##   level1_affect ~~
##     level2_affect     1.067    0.175    6.087    0.000
##     slope1_affect     0.057    0.042    1.358    0.174
##     slope2_affect    -0.006    0.019   -0.323    0.746
##   level2_affect ~~
##     slope1_affect    -0.015    0.047   -0.327    0.743
##     slope2_affect    -0.058    0.039   -1.508    0.131
##   slope1_affect ~~
##     slope2_affect     0.006    0.005    1.109    0.267
##
## Intercepts:
##                    Estimate  Std.Err  z-value  P(>|z|)
##    .affect.1          0.000
##    .affect.2          0.000
##    .affect.3          0.000
##    .affect.4          0.000
##    .affect.5          0.000
##    .affect.6          0.000
##    .affect.7          0.000
##    .affect.8          0.000
##    .affect.9          0.000
##    .affect.10         0.000
##     level1_affect     4.020    0.076   52.903    0.000
##     level2_affect     3.858    0.110   35.124    0.000
##     slope1_affect     0.774    0.022   35.974    0.000
##     slope2_affect    -0.783    0.013  -61.697    0.000
##
## Variances:
##                    Estimate  Std.Err  z-value  P(>|z|)
##     lvl1_ff           0.845    0.169    5.009    0.000
##     lvl2_ff           1.525    0.354    4.304    0.000
##     slp1_ff          -0.010    0.014   -0.714    0.475
##     slp2_ff           0.009    0.005    1.782    0.075
##    .affct.1 (rs_v)    0.976    0.028   34.641    0.000
##    .affct.2 (rs_v)    0.976    0.028   34.641    0.000
##    .affct.3 (rs_v)    0.976    0.028   34.641    0.000
##    .affct.4 (rs_v)    0.976    0.028   34.641    0.000
##    .affct.5 (rs_v)    0.976    0.028   34.641    0.000
##    .affct.6 (rs_v)    0.976    0.028   34.641    0.000
##    .affct.7 (rs_v)    0.976    0.028   34.641    0.000
##    .affct.8 (rs_v)    0.976    0.028   34.641    0.000
##    .affct.9 (rs_v)    0.976    0.028   34.641    0.000
##    .affc.10 (rs_v)    0.976    0.028   34.641    0.000

Notice that the string syntax is the exact same because the process changes at the same point in time, it does not matter if the process changes to ‘more positive’ or ‘more negative.’

# 3) Negative Growth, Growth, and Negative Growth

Now a process that goes down, goes up, and then goes back down. The data generating process:

$$$y_{it} = \begin{cases} 4 - 0.5t + error_{t}, & \text{if time < 5}\\ 4 + 0.5t + error_{t}, & \text{if 5 < time < 10}\\ 4 - 0.5t + error_{t}, & \text{otherwise} \end{cases}$$$

The data generating code and plot

library(tidyverse)
library(lavaan)
library(ggplot2)
library(MASS)

N <- 400
time <- 15

intercept_1 <- 4
intercept_2 <- 4
intercept_3 <- 4

growth1 <- -0.5
growth2 <- 0.5
growth3 <- -0.5

df_matrix_c <- matrix(, ncol = 3, nrow = N*time)

count <- 0

for(i in 1:N){

unob_het_y <- rnorm(1,0,1)

for(j in 1:time){

count <- count + 1

if(j < 5){
df_matrix_c[count, 1] <- i
df_matrix_c[count, 2] <- j
df_matrix_c[count, 3] <- intercept_1 + growth1*j + unob_het_y + rnorm(1,0,1)

}else if(j >= 5 && j < 10){

df_matrix_c[count, 1] <- i
df_matrix_c[count, 2] <- j
df_matrix_c[count, 3] <- intercept_2 + growth2*j + unob_het_y + rnorm(1,0,1)

}else{

df_matrix_c[count, 1] <- i
df_matrix_c[count, 2] <- j
df_matrix_c[count, 3] <- intercept_3 + growth3*j + unob_het_y + rnorm(1,0,1)

}
}

}

df_c <- data.frame(df_matrix_c)

names(df_c) <- c('id', 'time', 'affect')

df1_c <- df_c %>%
filter(time < 5)

df2_c <- df_c %>%
filter(time >= 5 & time < 10)

df3_c <- df_c %>%
filter(time >= 10)

df_sum1_c <- df1_c %>%
group_by(time) %>%
summarise(
affect = mean(affect)
)

df_sum2_c <- df2_c %>%
group_by(time) %>%
summarise(
affect = mean(affect)
)

df_sum3_c <- df3_c %>%
group_by(time) %>%
summarise(
affect = mean(affect)
)

ggplot() +
geom_point(data = df1_c, aes(x = time, y = affect, group = id), color = 'gray85') +
geom_line(data = df1_c, aes(x = time, y = affect, group = id), color = 'gray85') +
geom_point(data = df2_c, aes(x = time, y = affect, group = id), color = 'gray85') +
geom_line(data = df2_c, aes(x = time, y = affect, group = id), color = 'gray85') +
geom_line(data = df_sum1_c, aes(x = time, y = affect)) +
geom_line(data = df_sum2_c, aes(x = time, y = affect)) +
geom_point(data = df3_c, aes(x = time, y = affect, group = id), color = 'gray85') +
geom_line(data = df3_c, aes(x = time, y = affect, group = id), color = 'gray85') +
geom_line(data = df_sum3_c, aes(x = time, y = affect))

Now estimate the parameters using SEM:

library(lavaan)

df_wide_c <- reshape(df_c, idvar = 'id', timevar = 'time', direction = 'wide')

spline_string_c <- '

# latent intercept for first third

level1_affect =~ 1*affect.1 + 1*affect.2 + 1*affect.3 + 1*affect.4 + 0*affect.5 + 0*affect.6 + 0*affect.7 + 0*affect.8 + 0*affect.9 + 0*affect.10 + 0*affect.11 + 0*affect.12 + 0*affect.13 + 0*affect.14 + 0*affect.15

# latent intercept for second third

level2_affect =~ 0*affect.1 + 0*affect.2 + 0*affect.3 + 0*affect.4 + 1*affect.5 + 1*affect.6 + 1*affect.7 + 1*affect.8 + 1*affect.9 + 0*affect.10 + 0*affect.11 + 0*affect.12 + 0*affect.13 + 0*affect.14 + 0*affect.15

# latent intercept for final third

level3_affect =~ 0*affect.1 + 0*affect.2 + 0*affect.3 + 0*affect.4 + 0*affect.5 + 0*affect.6 + 0*affect.7 + 0*affect.8 + 0*affect.9 + 1*affect.10 + 1*affect.11 + 1*affect.12 + 1*affect.13 + 1*affect.14 + 1*affect.15

# latent slope for first third basis coefficients

slope1_affect =~ 1*affect.1 + 2*affect.2 + 3*affect.3 + 4*affect.4 + 0*affect.5 + 0*affect.6 + 0*affect.7 + 0*affect.8 + 0*affect.9 + 0*affect.10 + 0*affect.11 + 0*affect.12 + 0*affect.13 + 0*affect.14 + 0*affect.15

# latent slope for second third basis coefficients

slope2_affect =~ 0*affect.1 + 0*affect.2 + 0*affect.3 + 0*affect.4 + 5*affect.5 + 6*affect.6 + 7*affect.7 + 8*affect.8 + 9*affect.9 + 0*affect.10 + 0*affect.11 + 0*affect.12 + 0*affect.13 + 0*affect.14 + 0*affect.15

# latent slope for final third basis coefficients

slope3_affect =~ 0*affect.1 + 0*affect.2 + 0*affect.3 + 0*affect.4 + 0*affect.5 + 0*affect.6 + 0*affect.7 + 0*affect.8 + 0*affect.9 + 10*affect.10 + 11*affect.11 + 12*affect.12 + 13*affect.13 + 14*affect.14 + 15*affect.15

# means and variance of latent factors

level1_affect ~~ level1_affect
level2_affect ~~ level2_affect
level3_affect ~~ level3_affect
slope1_affect ~~ slope1_affect
slope2_affect ~~ slope2_affect
slope3_affect ~~ slope3_affect

# covariance between latent factors

level1_affect ~~ level2_affect
level1_affect ~~ level3_affect
level1_affect ~~ slope1_affect
level1_affect ~~ slope2_affect
level1_affect ~~ slope3_affect

level2_affect ~~ level3_affect
level2_affect ~~ slope1_affect
level2_affect ~~ slope2_affect
level2_affect ~~ slope3_affect

level3_affect ~~ slope1_affect
level3_affect ~~ slope2_affect
level3_affect ~~ slope3_affect

slope1_affect ~~ slope2_affect
slope1_affect ~~ slope3_affect

slope2_affect ~~ slope3_affect

# constrain means of indicators to zero across time

affect.1 ~ 0
affect.2 ~ 0
affect.3 ~ 0
affect.4 ~ 0
affect.5 ~ 0
affect.6 ~ 0
affect.7 ~ 0
affect.8 ~ 0
affect.9 ~ 0
affect.10 ~ 0

# constrain residual variance to equality across time

affect.1 ~~ res_var*affect.1
affect.2 ~~ res_var*affect.2
affect.3 ~~ res_var*affect.3
affect.4 ~~ res_var*affect.4
affect.5 ~~ res_var*affect.5
affect.6 ~~ res_var*affect.6
affect.7 ~~ res_var*affect.7
affect.8 ~~ res_var*affect.8
affect.9 ~~ res_var*affect.9
affect.10 ~~ res_var*affect.10

'

spline_model_c <- growth(spline_string_c, data = df_wide_c)
summary(spline_model_c, fit.measures = T)
## lavaan 0.6-2 ended normally after 141 iterations
##
##   Optimization method                           NLMINB
##   Number of free parameters                         42
##   Number of equality constraints                     9
##
##   Number of observations                           400
##
##   Estimator                                         ML
##   Model Fit Test Statistic                     120.300
##   Degrees of freedom                               102
##   P-value (Chi-square)                           0.104
##
## Model test baseline model:
##
##   Minimum Function Test Statistic             3120.637
##   Degrees of freedom                               105
##   P-value                                        0.000
##
## User model versus baseline model:
##
##   Comparative Fit Index (CFI)                    0.994
##   Tucker-Lewis Index (TLI)                       0.994
##
## Loglikelihood and Information Criteria:
##
##   Loglikelihood user model (H0)              -9094.871
##   Loglikelihood unrestricted model (H1)      -9034.722
##
##   Number of free parameters                         33
##   Akaike (AIC)                               18255.743
##   Bayesian (BIC)                             18387.461
##   Sample-size adjusted Bayesian (BIC)        18282.750
##
## Root Mean Square Error of Approximation:
##
##   RMSEA                                          0.021
##   90 Percent Confidence Interval          0.000  0.035
##   P-value RMSEA <= 0.05                          1.000
##
## Standardized Root Mean Square Residual:
##
##   SRMR                                           0.040
##
## Parameter Estimates:
##
##   Information                                 Expected
##   Information saturated (h1) model          Structured
##   Standard Errors                             Standard
##
## Latent Variables:
##                    Estimate  Std.Err  z-value  P(>|z|)
##   level1_affect =~
##     affect.1          1.000
##     affect.2          1.000
##     affect.3          1.000
##     affect.4          1.000
##     affect.5          0.000
##     affect.6          0.000
##     affect.7          0.000
##     affect.8          0.000
##     affect.9          0.000
##     affect.10         0.000
##     affect.11         0.000
##     affect.12         0.000
##     affect.13         0.000
##     affect.14         0.000
##     affect.15         0.000
##   level2_affect =~
##     affect.1          0.000
##     affect.2          0.000
##     affect.3          0.000
##     affect.4          0.000
##     affect.5          1.000
##     affect.6          1.000
##     affect.7          1.000
##     affect.8          1.000
##     affect.9          1.000
##     affect.10         0.000
##     affect.11         0.000
##     affect.12         0.000
##     affect.13         0.000
##     affect.14         0.000
##     affect.15         0.000
##   level3_affect =~
##     affect.1          0.000
##     affect.2          0.000
##     affect.3          0.000
##     affect.4          0.000
##     affect.5          0.000
##     affect.6          0.000
##     affect.7          0.000
##     affect.8          0.000
##     affect.9          0.000
##     affect.10         1.000
##     affect.11         1.000
##     affect.12         1.000
##     affect.13         1.000
##     affect.14         1.000
##     affect.15         1.000
##   slope1_affect =~
##     affect.1          1.000
##     affect.2          2.000
##     affect.3          3.000
##     affect.4          4.000
##     affect.5          0.000
##     affect.6          0.000
##     affect.7          0.000
##     affect.8          0.000
##     affect.9          0.000
##     affect.10         0.000
##     affect.11         0.000
##     affect.12         0.000
##     affect.13         0.000
##     affect.14         0.000
##     affect.15         0.000
##   slope2_affect =~
##     affect.1          0.000
##     affect.2          0.000
##     affect.3          0.000
##     affect.4          0.000
##     affect.5          5.000
##     affect.6          6.000
##     affect.7          7.000
##     affect.8          8.000
##     affect.9          9.000
##     affect.10         0.000
##     affect.11         0.000
##     affect.12         0.000
##     affect.13         0.000
##     affect.14         0.000
##     affect.15         0.000
##   slope3_affect =~
##     affect.1          0.000
##     affect.2          0.000
##     affect.3          0.000
##     affect.4          0.000
##     affect.5          0.000
##     affect.6          0.000
##     affect.7          0.000
##     affect.8          0.000
##     affect.9          0.000
##     affect.10        10.000
##     affect.11        11.000
##     affect.12        12.000
##     affect.13        13.000
##     affect.14        14.000
##     affect.15        15.000
##
## Covariances:
##                    Estimate  Std.Err  z-value  P(>|z|)
##   level1_affect ~~
##     level2_affect     1.238    0.206    6.001    0.000
##     level3_affect     0.745    0.237    3.137    0.002
##     slope1_affect     0.038    0.044    0.857    0.392
##     slope2_affect    -0.032    0.025   -1.275    0.202
##     slope3_affect     0.021    0.018    1.196    0.232
##   level2_affect ~~
##     level3_affect     1.360    0.388    3.507    0.000
##     slope1_affect    -0.020    0.056   -0.363    0.717
##     slope2_affect    -0.006    0.058   -0.098    0.922
##     slope3_affect    -0.015    0.029   -0.512    0.609
##   level3_affect ~~
##     slope1_affect    -0.002    0.066   -0.024    0.981
##     slope2_affect    -0.090    0.048   -1.857    0.063
##     slope3_affect     0.097    0.053    1.819    0.069
##   slope1_affect ~~
##     slope2_affect     0.002    0.007    0.275    0.783
##     slope3_affect    -0.001    0.005   -0.204    0.838
##   slope2_affect ~~
##     slope3_affect     0.005    0.004    1.411    0.158
##
## Intercepts:
##                    Estimate  Std.Err  z-value  P(>|z|)
##    .affect.1          0.000
##    .affect.2          0.000
##    .affect.3          0.000
##    .affect.4          0.000
##    .affect.5          0.000
##    .affect.6          0.000
##    .affect.7          0.000
##    .affect.8          0.000
##    .affect.9          0.000
##    .affect.10         0.000
##    .affect.11         0.000
##    .affect.12         0.000
##    .affect.13         0.000
##    .affect.14         0.000
##    .affect.15         0.000
##     level1_affect     3.978    0.078   51.181    0.000
##     level2_affect     4.030    0.127   31.827    0.000
##     level3_affect     4.034    0.151   26.752    0.000
##     slope1_affect    -0.514    0.022  -23.449    0.000
##     slope2_affect     0.490    0.016   30.764    0.000
##     slope3_affect    -0.505    0.011  -44.201    0.000
##
## Variances:
##                    Estimate  Std.Err  z-value  P(>|z|)
##     lvl1_ff           0.873    0.177    4.933    0.000
##     lvl2_ff           1.163    0.479    2.426    0.015
##     lvl3_ff          -0.323    0.710   -0.455    0.649
##     slp1_ff          -0.014    0.015   -0.907    0.365
##     slp2_ff          -0.001    0.008   -0.189    0.850
##     slp3_ff          -0.007    0.004   -1.664    0.096
##    .affct.1 (rs_v)    1.029    0.031   33.665    0.000
##    .affct.2 (rs_v)    1.029    0.031   33.665    0.000
##    .affct.3 (rs_v)    1.029    0.031   33.665    0.000
##    .affct.4 (rs_v)    1.029    0.031   33.665    0.000
##    .affct.5 (rs_v)    1.029    0.031   33.665    0.000
##    .affct.6 (rs_v)    1.029    0.031   33.665    0.000
##    .affct.7 (rs_v)    1.029    0.031   33.665    0.000
##    .affct.8 (rs_v)    1.029    0.031   33.665    0.000
##    .affct.9 (rs_v)    1.029    0.031   33.665    0.000
##    .affc.10 (rs_v)    1.029    0.031   33.665    0.000
##    .affc.11           0.993    0.078   12.746    0.000
##    .affc.12           1.018    0.078   13.034    0.000
##    .affc.13           1.023    0.078   13.168    0.000
##    .affc.14           0.935    0.073   12.828    0.000
##    .affc.15           1.112    0.091   12.255    0.000

Again, the basis coefficients are the important piece here:

'

# latent slope for first third basis coefficients

slope1_affect =~ 1*affect.1 + 2*affect.2 + 3*affect.3 + 4*affect.4 +
0*affect.5 + 0*affect.6 + 0*affect.7 + 0*affect.8 +
0*affect.9 + 0*affect.10 + 0*affect.11 + 0*affect.12 +
0*affect.13 + 0*affect.14 + 0*affect.15

# latent slope for second third basis coefficients

slope2_affect =~ 0*affect.1 + 0*affect.2 + 0*affect.3 + 0*affect.4 +
5*affect.5 + 6*affect.6 + 7*affect.7 + 8*affect.8 +
9*affect.9 + 0*affect.10 + 0*affect.11 + 0*affect.12 +
0*affect.13 + 0*affect.14 + 0*affect.15

# latent slope for final third basis coefficients

slope3_affect =~ 0*affect.1 + 0*affect.2 + 0*affect.3 + 0*affect.4 +
0*affect.5 + 0*affect.6 + 0*affect.7 + 0*affect.8 +
0*affect.9 + 10*affect.10 + 11*affect.11 + 12*affect.12 +
13*affect.13 + 14*affect.14 + 15*affect.15

'
## [1] "\n\n\n# latent slope for first third basis coefficients\n\nslope1_affect =~ 1*affect.1 + 2*affect.2 + 3*affect.3 + 4*affect.4 + \n                 0*affect.5 + 0*affect.6 + 0*affect.7 + 0*affect.8 + \n                 0*affect.9 + 0*affect.10 + 0*affect.11 + 0*affect.12 + \n                 0*affect.13 + 0*affect.14 + 0*affect.15\n\n# latent slope for second third basis coefficients\n\nslope2_affect =~ 0*affect.1 + 0*affect.2 + 0*affect.3 + 0*affect.4 + \n                 5*affect.5 + 6*affect.6 + 7*affect.7 + 8*affect.8 + \n                 9*affect.9 + 0*affect.10 + 0*affect.11 + 0*affect.12 + \n                 0*affect.13 + 0*affect.14 + 0*affect.15\n\n# latent slope for final third basis coefficients\n\nslope3_affect =~ 0*affect.1 + 0*affect.2 + 0*affect.3 + 0*affect.4 +\n                 0*affect.5 + 0*affect.6 + 0*affect.7 + 0*affect.8 + \n                 0*affect.9 + 10*affect.10 + 11*affect.11 + 12*affect.12 + \n                 13*affect.13 + 14*affect.14 + 15*affect.15\n\n\n\n"

Bo$$^2$$m =)