-
Notifications
You must be signed in to change notification settings - Fork 3
/
README.Rmd
762 lines (677 loc) · 25.7 KB
/
README.Rmd
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
---
output: github_document
---
<!-- README.md is generated from README.Rmd. Please edit that file -->
```{r, include = FALSE}
library(knitr)
knitr::opts_chunk$set(
collapse = TRUE,
comment = "#>",
fig.path = "man/figures/README-",
out.width = "100%"
)
```
# lcsm: An R Package for Latent Change Score Modeling
<!-- badges: start -->
[![licence](https://img.shields.io/badge/Licence-MIT-brightgreen.svg)](https://choosealicense.com/licenses/mit/)
[![CRAN status](https://www.r-pkg.org/badges/version/lcsm)](https://CRAN.R-project.org/package=lcsm/)
<!-- badges: end -->
This package offers some helper functions to specify and analyse
univariate and bivariate latent change score models (LCSM) using
[lavaan](https://lavaan.ugent.be/) (Rosseel,
[2012](https://www.jstatsoft.org/v48/i02/)).
For details about this method see for example McArdle
([2009](https://pubmed.ncbi.nlm.nih.gov/18817479/)),
Ghisletta ([2012](https://pubmed.ncbi.nlm.nih.gov/25505366/)), Grimm
et al. ([2012](https://www.ncbi.nlm.nih.gov/pmc/articles/PMC3638891/)), and
Grimm, Ram & Estabrook
([2017](https://www.guilford.com/books/Growth-Modeling/Grimm-Ram-Estabrook/9781462526062)).
The `lcsm` package combines the strengths of other R packages like [lavaan](https://lavaan.ugent.be/), [broom](https://github.com/tidymodels/broom/), and [semPlot](https://CRAN.R-project.org/package=semPlot/) by generating lavaan syntax that helps these packages work together.
This is work in progress and feedback is very welcome!
## Installation
You can install the released version of `lcsm` from [CRAN](https://CRAN.R-project.org/package=lcsm/) with:
``` r
install.packages("lcsm")
```
The development version can be installed from [GitHub](https://github.com/milanwiedemann/lcsm/) using:
``` r
# install.packages("devtools")
devtools::install_github("milanwiedemann/lcsm")
```
## Overview of the functions
The `lcsm` package contains the functions listed below.
A more detailed description of these functions is available in this README or vignettes.
The interactive online application **[`shinychange`](https://milanwiedemann.shinyapps.io/shinychange/)** also illustrates some functions of this package.
- Functions to generate [lavaan](https://lavaan.ugent.be/) syntax for different model specifications:
- `specify_uni_lcsm()`: Generate syntax for univariate LCSM
- `specify_bi_lcsm()`: Generate syntax for bivariate LCSM
- Functions to fit models using [lavaan](https://lavaan.ugent.be/):
- `fit_uni_lcsm()`: Fit univariate LCSM
- `fit_bi_lcsm()`: Fit bivariate LCSM
- Functions to extract results from models using [broom](https://broom.tidymodels.org/):
- `extract_fit()`: Extract fit statistics
- `extract_param()`: Extract estimated parameters
- Simulate data using [lavaan](https://lavaan.ugent.be/):
- `sim_uni_lcsm()`: Simulate data by specifying parameters for a univariate LCSM
- `sim_bi_lcsm()`: Simulate data by specifying parameters for a bivariate LCSM
- Helper functions:
- `plot_lcsm()`: Visualise LCSM using [semPlot](https://github.com/SachaEpskamp/semPlot/)
- `select_uni_cases()`: Select cases for analysis based on available scores on one construct
- `select_bi_cases()`: Select cases for analysis based on available scores on two construct
## How to use `lcsm`
Here are a few examples how to use the `lcsm` package.
```{r}
# Load the package
library(lcsm)
```
### Visualise data
Longitudinal data can be visualised using the `plot_trajectories()` function.
Here only 30% of the data is visualised using the argument `random_sample_frac = 0.3`.
Only consecutive measures are connected by lines as specified in `connect_missing = FALSE`.
```{r, fig.width = 6, fig.height = 3.5}
# Create plot for construct x
plot_x <- plot_trajectories(data = data_bi_lcsm,
id_var = "id",
var_list = c("x1", "x2", "x3", "x4", "x5",
"x6", "x7", "x8", "x9", "x10"),
xlab = "Time", ylab = "X Score",
connect_missing = FALSE,
random_sample_frac = 0.3)
# Create plot for construct y
plot_y <- plot_trajectories(data = data_bi_lcsm,
id_var = "id",
var_list = c("y1", "y2", "y3", "y4", "y5",
"y6", "y7", "y8", "y9", "y10"),
xlab = "Time", ylab = "Y Score",
connect_missing = FALSE,
random_sample_frac = 0.3)
# Arrange plots next to each other using patchwork
library(patchwork)
plot_x + plot_y + plot_annotation(tag_levels = 'A')
```
### Fit LCSMs
The functions `fit_uni_lcsm()` and `fit_bi_lcsm()` can be used to fit univariate and bivariate LCSM with different model specifications.
In a first step, these two function generate the user specified lavaan syntax by calling the `specify_uni_lcsm()` or `specify_bi_lcsm()` functions.
The following table describes some of the different model specifications that the `model` arguments can take.
More detail can be found in the help files `help(fit_uni_lcsm)`.
#### Fit univariate LCSMs
|Model specification |Description |
|:-------------------|:--------------------------------------------------------------|
|alpha_constant |Constant change factor |
|beta |Proportional change factor |
|phi |Autoregression of change scores |
The example below shows how to specify a generic univariate latent change score model using the function `specify_uni_lcsm()`.
A table of the description of all parameters that can be estimated is shown [here](#overview-of-estimated-lcs-model-parameters).
```{r, eval=FALSE}
specify_uni_lcsm(timepoints = 5,
var = "x",
change_letter = "g",
model = list(alpha_constant = TRUE,
beta = TRUE,
phi = TRUE))
```
<details>
<summary>Click here to see the <code>lavaan</code> syntax specified above.</summary>
<p>
```
# Specify latent true scores
lx1 =~ 1 * x1
lx2 =~ 1 * x2
lx3 =~ 1 * x3
lx4 =~ 1 * x4
lx5 =~ 1 * x5
# Specify mean of latent true scores
lx1 ~ gamma_lx1 * 1
lx2 ~ 0 * 1
lx3 ~ 0 * 1
lx4 ~ 0 * 1
lx5 ~ 0 * 1
# Specify variance of latent true scores
lx1 ~~ sigma2_lx1 * lx1
lx2 ~~ 0 * lx2
lx3 ~~ 0 * lx3
lx4 ~~ 0 * lx4
lx5 ~~ 0 * lx5
# Specify intercept of obseved scores
x1 ~ 0 * 1
x2 ~ 0 * 1
x3 ~ 0 * 1
x4 ~ 0 * 1
x5 ~ 0 * 1
# Specify variance of observed scores
x1 ~~ sigma2_ux * x1
x2 ~~ sigma2_ux * x2
x3 ~~ sigma2_ux * x3
x4 ~~ sigma2_ux * x4
x5 ~~ sigma2_ux * x5
# Specify autoregressions of latent variables
lx2 ~ 1 * lx1
lx3 ~ 1 * lx2
lx4 ~ 1 * lx3
lx5 ~ 1 * lx4
# Specify latent change scores
dx2 =~ 1 * lx2
dx3 =~ 1 * lx3
dx4 =~ 1 * lx4
dx5 =~ 1 * lx5
# Specify latent change scores means
dx2 ~ 0 * 1
dx3 ~ 0 * 1
dx4 ~ 0 * 1
dx5 ~ 0 * 1
# Specify latent change scores variances
dx2 ~~ 0 * dx2
dx3 ~~ 0 * dx3
dx4 ~~ 0 * dx4
dx5 ~~ 0 * dx5
# Specify constant change factor
g2 =~ 1 * dx2 + 1 * dx3 + 1 * dx4 + 1 * dx5
# Specify constant change factor mean
g2 ~ alpha_g2 * 1
# Specify constant change factor variance
g2 ~~ sigma2_g2 * g2
# Specify constant change factor covariance with the initial true score
g2 ~~ sigma_g2lx1 * lx1
# Specify proportional change component
dx2 ~ beta_x * lx1
dx3 ~ beta_x * lx2
dx4 ~ beta_x * lx3
dx5 ~ beta_x * lx4
# Specify autoregression of change score
dx3 ~ phi_x * dx2
dx4 ~ phi_x * dx3
dx5 ~ phi_x * dx4
```
</p>
</details>
The function `fit_uni_lcsm()` can be used to fit a univariate LCSM using the sample data set `data_uni_lcsm`.
This functions first writes the lavaan syntax specified in the `model` argument and passes it on to `lavaaan::lavaan()`.
```{r}
# Fit univariate latent change score model
fit_uni_lcsm(data = data_uni_lcsm,
var = c("x1", "x2", "x3", "x4", "x5",
"x6", "x7", "x8", "x9", "x10"),
model = list(alpha_constant = TRUE,
beta = FALSE,
phi = TRUE))
```
It is also possible to show the lavaan syntax that was created to fit the model by the function `specify_uni_lcsm()`.
The lavaan syntax includes comments describing some parts of the syntax in more detail.
To save the syntax in an object the argument `return_lavaan_syntax` has to be set to `TRUE`.
This object looks a bit funny, it's one very long line of text, but can be formatted to look more beautiful and readable using `cat(syntax)`.
```{r, eval=FALSE}
# Fit univariate latent change score model
syntax <- fit_uni_lcsm(data = data_uni_lcsm,
var = c("x1", "x2", "x3", "x4", "x5",
"x6", "x7", "x8", "x9", "x10"),
model = list(alpha_constant = TRUE,
beta = FALSE,
phi = TRUE),
return_lavaan_syntax = TRUE)
# Return lavaan syntax in easy to read format
cat(syntax)
```
<details>
<summary>Click here to see the lavaan syntax specified in <code>syntax</code>.</summary>
<p>
```
# Specify latent true scores
lx1 =~ 1 * x1
lx2 =~ 1 * x2
lx3 =~ 1 * x3
lx4 =~ 1 * x4
lx5 =~ 1 * x5
lx6 =~ 1 * x6
lx7 =~ 1 * x7
lx8 =~ 1 * x8
lx9 =~ 1 * x9
lx10 =~ 1 * x10
# Specify mean of latent true scores
lx1 ~ gamma_lx1 * 1
lx2 ~ 0 * 1
lx3 ~ 0 * 1
lx4 ~ 0 * 1
lx5 ~ 0 * 1
lx6 ~ 0 * 1
lx7 ~ 0 * 1
lx8 ~ 0 * 1
lx9 ~ 0 * 1
lx10 ~ 0 * 1
# Specify variance of latent true scores
lx1 ~~ sigma2_lx1 * lx1
lx2 ~~ 0 * lx2
lx3 ~~ 0 * lx3
lx4 ~~ 0 * lx4
lx5 ~~ 0 * lx5
lx6 ~~ 0 * lx6
lx7 ~~ 0 * lx7
lx8 ~~ 0 * lx8
lx9 ~~ 0 * lx9
lx10 ~~ 0 * lx10
# Specify intercept of obseved scores
x1 ~ 0 * 1
x2 ~ 0 * 1
x3 ~ 0 * 1
x4 ~ 0 * 1
x5 ~ 0 * 1
x6 ~ 0 * 1
x7 ~ 0 * 1
x8 ~ 0 * 1
x9 ~ 0 * 1
x10 ~ 0 * 1
# Specify variance of observed scores
x1 ~~ sigma2_ux * x1
x2 ~~ sigma2_ux * x2
x3 ~~ sigma2_ux * x3
x4 ~~ sigma2_ux * x4
x5 ~~ sigma2_ux * x5
x6 ~~ sigma2_ux * x6
x7 ~~ sigma2_ux * x7
x8 ~~ sigma2_ux * x8
x9 ~~ sigma2_ux * x9
x10 ~~ sigma2_ux * x10
# Specify autoregressions of latent variables
lx2 ~ 1 * lx1
lx3 ~ 1 * lx2
lx4 ~ 1 * lx3
lx5 ~ 1 * lx4
lx6 ~ 1 * lx5
lx7 ~ 1 * lx6
lx8 ~ 1 * lx7
lx9 ~ 1 * lx8
lx10 ~ 1 * lx9
# Specify latent change scores
dx2 =~ 1 * lx2
dx3 =~ 1 * lx3
dx4 =~ 1 * lx4
dx5 =~ 1 * lx5
dx6 =~ 1 * lx6
dx7 =~ 1 * lx7
dx8 =~ 1 * lx8
dx9 =~ 1 * lx9
dx10 =~ 1 * lx10
# Specify latent change scores means
dx2 ~ 0 * 1
dx3 ~ 0 * 1
dx4 ~ 0 * 1
dx5 ~ 0 * 1
dx6 ~ 0 * 1
dx7 ~ 0 * 1
dx8 ~ 0 * 1
dx9 ~ 0 * 1
dx10 ~ 0 * 1
# Specify latent change scores variances
dx2 ~~ 0 * dx2
dx3 ~~ 0 * dx3
dx4 ~~ 0 * dx4
dx5 ~~ 0 * dx5
dx6 ~~ 0 * dx6
dx7 ~~ 0 * dx7
dx8 ~~ 0 * dx8
dx9 ~~ 0 * dx9
dx10 ~~ 0 * dx10
# Specify constant change factor
g2 =~ 1 * dx2 + 1 * dx3 + 1 * dx4 + 1 * dx5 + 1 * dx6 + 1 * dx7 + 1 * dx8 + 1 * dx9 + 1 * dx10
# Specify constant change factor mean
g2 ~ alpha_g2 * 1
# Specify constant change factor variance
g2 ~~ sigma2_g2 * g2
# Specify constant change factor covariance with the initial true score
g2 ~~ sigma_g2lx1 * lx1
# Specify autoregression of change score
dx3 ~ phi_x * dx2
dx4 ~ phi_x * dx3
dx5 ~ phi_x * dx4
dx6 ~ phi_x * dx5
dx7 ~ phi_x * dx6
dx8 ~ phi_x * dx7
dx9 ~ phi_x * dx8
dx10 ~ phi_x * dx9
```
</p>
</details>
#### Fit bivariate LCSMs
The function `fit_bi_lcsm()` allows to specify two univariate LCSMs using the arguments `model_x` and `model_x`.
These two constructs can then be connected using the `coupling` argument.
More details can be found in the help files `help(fit_bi_lcsm)`.
|Coupling specification |Description |
|:----------------------|:------------------------------------------------------|
|coupling_piecewise |Piecewise coupling parameters |
|coupling_piecewise_num |Changepoint of piecewise coupling parameters |
|delta_con_xy |Change score x (t) determined by true score y (t) |
|delta_con_yx |Change score y (t) determined by true score x (t) |
|delta_lag_xy |Change score x (t) determined by true score y (t-1) |
|delta_lag_yx |Change score y (t) determined by true score x (t-1) |
|xi_con_xy |Change score x (t) determined by change score y (t) |
|xi_con_yx |Change score y (t) determined by change score x (t) |
|xi_lag_xy |Change score x (t) determined by change score y (t-1) |
|xi_lag_yx |Change score y (t) determined by change score x (t-1) |
```{r}
fit_bi_lcsm(data = data_bi_lcsm,
var_x = c("x1", "x2", "x3", "x4", "x5",
"x6", "x7", "x8", "x9", "x10"),
var_y = c("y1", "y2", "y3", "y4", "y5",
"y6", "y7", "y8", "y9", "y10"),
model_x = list(alpha_constant = TRUE,
beta = TRUE,
phi = FALSE),
model_y = list(alpha_constant = TRUE,
beta = TRUE,
phi = TRUE),
coupling = list(delta_lag_xy = TRUE,
xi_lag_yx = TRUE))
```
### Extract fit statistics and parmeters
The main underlying functions to extract parameters and fit statistics come from the `broom` package: `broom::tidy()` and `broom::glance()`.
The functions `extract_param()` and `extract_fit()` offer some tools that I find helpful when running LCSMs in R, for example:
- `extract_param()`: only one row per estimated parameter,
- `extract_fit()`: fit statistics for multiple lavaan objects can be extracted.
A table of the description of all parameters that can be estimated is shown [here](#overview-of-estimated-lcs-model-parameters).
```{r}
# First create a lavaan object
bi_lcsm_01 <- fit_bi_lcsm(data = data_bi_lcsm,
var_x = c("x1", "x2", "x3", "x4", "x5",
"x6", "x7", "x8", "x9", "x10"),
var_y = c("y1", "y2", "y3", "y4", "y5",
"y6", "y7", "y8", "y9", "y10"),
model_x = list(alpha_constant = TRUE,
beta = TRUE,
phi = FALSE),
model_y = list(alpha_constant = TRUE,
beta = TRUE,
phi = TRUE),
coupling = list(delta_lag_xy = TRUE,
xi_lag_yx = TRUE))
# Now extract parameter estimates
# Only extract first 7 columns for this example by adding [ , 1:7]
param_bi_lcsm_01 <- extract_param(bi_lcsm_01, printp = TRUE)[ , 1:7]
# Print table of parameter estimates
kable(param_bi_lcsm_01, digits = 3)
```
### Plot simplified path diagrams of LCSMs
This function is work in progress and can only plot univariate and bivariate LCSMs that were specified with `fit_uni_lcsm()` or `fit_bi_lcsm()`.
Modified LCSMs will probably return errors as the layout matrix that gets created by this plot function only supports the specifications that can be modelled with this package.
The input arguments for plotting a simplified path diagram are:
- the estimated lavaan object `lavaan_object`,
- the `lavaan_syntax` and ,
- `lcsm` indicating whether the LCSMs is "univariate" or "bivariate"
Optional arguments can be used to change the look of the plot, for example:
- `lcsm_colours` can be used to highlight the different parts of the latent change score model
- white: observed scores
- green: latent true scores
- blue: latent change scores
- yellow: latent change scores
Further arguments can be passed on to `semPlot::semPaths()`, for example:
- `what`, **"path"** to show unweighted gray edges, **"par"** to show parameter estimates as weighted (green/red) edges
- `whatLabels`, **"label"** to show edege names as label or **"est"** for parameter estimates, **"hide"** to hide edge labels
#### Univariate LCSM
```{r, fig.width = 6, fig.height = 4}
# Fit bivariate lcsm and save the results
uni_lavaan_results <- fit_uni_lcsm(data = data_uni_lcsm,
var = c("x1", "x2", "x3", "x4", "x5"),
model = list(alpha_constant = TRUE,
beta = TRUE,
phi = TRUE)
)
# Save the lavaan syntax that is used to create the layout matrix for semPlot
uni_lavaan_syntax <- fit_uni_lcsm(data = data_uni_lcsm,
var = c("x1", "x2", "x3", "x4", "x5"),
model = list(alpha_constant = TRUE,
beta = TRUE,
phi = TRUE),
return_lavaan_syntax = TRUE)
# Plot the results
plot_lcsm(lavaan_object = uni_lavaan_results,
lavaan_syntax = uni_lavaan_syntax,
edge.label.cex = .9,
lcsm_colours = TRUE,
lcsm = "univariate")
```
#### Bivariate LCSM
```{r, fig.width = 6, fig.height = 4}
# Fit bivariate lcsm and save the results
bi_lavaan_results <- fit_bi_lcsm(data = data_bi_lcsm,
var_x = c("x1", "x2", "x3", "x4", "x5"),
var_y = c("y1", "y2", "y3", "y4", "y5"),
model_x = list(alpha_constant = TRUE,
beta = TRUE,
phi = FALSE),
model_y = list(alpha_constant = TRUE,
beta = TRUE,
phi = TRUE),
coupling = list(delta_lag_xy = TRUE,
xi_lag_yx = TRUE))
# Save the lavaan syntax that is used to create the layout matrix for semPlot
bi_lavaan_syntax <- fit_bi_lcsm(data = data_bi_lcsm,
var_x = c("x1", "x2", "x3", "x4", "x5"),
var_y = c("y1", "y2", "y3", "y4", "y5"),
model_x = list(alpha_constant = TRUE,
beta = TRUE,
phi = FALSE),
model_y = list(alpha_constant = TRUE,
beta = TRUE,
phi = TRUE),
coupling = list(delta_lag_xy = TRUE,
xi_lag_yx = TRUE),
return_lavaan_syntax = TRUE)
# Plot the results
plot_lcsm(lavaan_object = bi_lavaan_results,
lavaan_syntax = bi_lavaan_syntax,
lcsm_colours = TRUE,
whatLabels = "hide",
lcsm = "bivariate")
```
### Simulate data
The functions `sim_uni_lcsm()` and `sim_bi_lcsm()` simulate data based on some some parameters that can be specified.
See the tables [here](#overview-of-estimated-lcs-model-parameters) for a full list of parameters that can be specified for the data simulation.
```{r sim-uni-data}
# Simulate some data
sim_uni_lcsm(timepoints = 5,
model = list(alpha_constant = TRUE, beta = FALSE, phi = TRUE),
model_param = list(gamma_lx1 = 21,
sigma2_lx1 = 1.5,
sigma2_ux = 0.2,
alpha_j2 = -0.93,
sigma2_j2 = 0.1,
sigma_j2lx1 = 0.2,
phi_x = 0.3),
sample.nobs = 1000,
na_pct = 0.3)
```
It is also possible to return the lavaan syntax instead of simulating data for further manual specifications.
The modified object could then be used to simulate data using `lavaan::simulateData()`.
```{r, eval=FALSE}
# Return lavaan syntax based on the following argument specifications
simsyntax <- sim_bi_lcsm(timepoints = 5,
model_x = list(alpha_constant = TRUE, beta = TRUE, phi = FALSE),
model_x_param = list(gamma_lx1 = 21,
sigma2_lx1 = .5,
sigma2_ux = .2,
alpha_g2 = -.4,
sigma2_g2 = .4,
sigma_g2lx1 = .2,
beta_x = -.1),
model_y = list(alpha_constant = TRUE, beta = TRUE, phi = TRUE),
model_y_param = list(gamma_ly1 = 5,
sigma2_ly1 = .2,
sigma2_uy = .2,
alpha_j2 = -.2,
sigma2_j2 = .1,
sigma_j2ly1 = .02,
beta_y = -.2,
phi_y = .1),
coupling = list(delta_lag_xy = TRUE,
xi_lag_yx = TRUE),
coupling_param = list(sigma_su = .01,
sigma_ly1lx1 = .2,
sigma_g2ly1 = .1,
sigma_j2lx1 = .1,
sigma_j2g2 = .01,
delta_lag_xy = .13,
xi_lag_yx = .4),
return_lavaan_syntax = TRUE)
```
<details>
<summary>Click here to see the lavaan syntax specified in <code>simsyntax</code>.</summary>
<p>
```
# Specify parameters for construct x ----
# Specify latent true scores
lx1 =~ 1 * x1
lx2 =~ 1 * x2
lx3 =~ 1 * x3
lx4 =~ 1 * x4
lx5 =~ 1 * x5
# Specify mean of latent true scores
lx1 ~ 21 * 1
lx2 ~ 0 * 1
lx3 ~ 0 * 1
lx4 ~ 0 * 1
lx5 ~ 0 * 1
# Specify variance of latent true scores
lx1 ~~ 0.5 * lx1
lx2 ~~ 0 * lx2
lx3 ~~ 0 * lx3
lx4 ~~ 0 * lx4
lx5 ~~ 0 * lx5
# Specify intercept of obseved scores
x1 ~ 0 * 1
x2 ~ 0 * 1
x3 ~ 0 * 1
x4 ~ 0 * 1
x5 ~ 0 * 1
# Specify variance of observed scores
x1 ~~ 0.2 * x1
x2 ~~ 0.2 * x2
x3 ~~ 0.2 * x3
x4 ~~ 0.2 * x4
x5 ~~ 0.2 * x5
# Specify autoregressions of latent variables
lx2 ~ 1 * lx1
lx3 ~ 1 * lx2
lx4 ~ 1 * lx3
lx5 ~ 1 * lx4
# Specify latent change scores
dx2 =~ 1 * lx2
dx3 =~ 1 * lx3
dx4 =~ 1 * lx4
dx5 =~ 1 * lx5
# Specify latent change scores means
dx2 ~ 0 * 1
dx3 ~ 0 * 1
dx4 ~ 0 * 1
dx5 ~ 0 * 1
# Specify latent change scores variances
dx2 ~~ 0 * dx2
dx3 ~~ 0 * dx3
dx4 ~~ 0 * dx4
dx5 ~~ 0 * dx5
# Specify constant change factor
g2 =~ 1 * dx2 + 1 * dx3 + 1 * dx4 + 1 * dx5
# Specify constant change factor mean
g2 ~ -0.4 * 1
# Specify constant change factor variance
g2 ~~ 0.4 * g2
# Specify constant change factor covariance with the initial true score
g2 ~~ 0.2 * lx1
# Specify proportional change component
dx2 ~ -0.1 * lx1
dx3 ~ -0.1 * lx2
dx4 ~ -0.1 * lx3
dx5 ~ -0.1 * lx4
# Specify parameters for construct y ----
# Specify latent true scores
ly1 =~ 1 * y1
ly2 =~ 1 * y2
ly3 =~ 1 * y3
ly4 =~ 1 * y4
ly5 =~ 1 * y5
# Specify mean of latent true scores
ly1 ~ 5 * 1
ly2 ~ 0 * 1
ly3 ~ 0 * 1
ly4 ~ 0 * 1
ly5 ~ 0 * 1
# Specify variance of latent true scores
ly1 ~~ 0.2 * ly1
ly2 ~~ 0 * ly2
ly3 ~~ 0 * ly3
ly4 ~~ 0 * ly4
ly5 ~~ 0 * ly5
# Specify intercept of obseved scores
y1 ~ 0 * 1
y2 ~ 0 * 1
y3 ~ 0 * 1
y4 ~ 0 * 1
y5 ~ 0 * 1
# Specify variance of observed scores
y1 ~~ 0.2 * y1
y2 ~~ 0.2 * y2
y3 ~~ 0.2 * y3
y4 ~~ 0.2 * y4
y5 ~~ 0.2 * y5
# Specify autoregressions of latent variables
ly2 ~ 1 * ly1
ly3 ~ 1 * ly2
ly4 ~ 1 * ly3
ly5 ~ 1 * ly4
# Specify latent change scores
dy2 =~ 1 * ly2
dy3 =~ 1 * ly3
dy4 =~ 1 * ly4
dy5 =~ 1 * ly5
# Specify latent change scores means
dy2 ~ 0 * 1
dy3 ~ 0 * 1
dy4 ~ 0 * 1
dy5 ~ 0 * 1
# Specify latent change scores variances
dy2 ~~ 0 * dy2
dy3 ~~ 0 * dy3
dy4 ~~ 0 * dy4
dy5 ~~ 0 * dy5
# Specify constant change factor
j2 =~ 1 * dy2 + 1 * dy3 + 1 * dy4 + 1 * dy5
# Specify constant change factor mean
j2 ~ -0.2 * 1
# Specify constant change factor variance
j2 ~~ 0.1 * j2
# Specify constant change factor covariance with the initial true score
j2 ~~ 0.02 * ly1
# Specify proportional change component
dy2 ~ -0.2 * ly1
dy3 ~ -0.2 * ly2
dy4 ~ -0.2 * ly3
dy5 ~ -0.2 * ly4
# Specify autoregression of change score
dy3 ~ 0.1 * dy2
dy4 ~ 0.1 * dy3
dy5 ~ 0.1 * dy4
# Specify residual covariances
x1 ~~ 0.01 * y1
x2 ~~ 0.01 * y2
x3 ~~ 0.01 * y3
x4 ~~ 0.01 * y4
x5 ~~ 0.01 * y5
# Specify covariances betweeen specified change components (alpha) and intercepts (initial latent true scores lx1 and ly1) ----
# Specify covariance of intercepts
lx1 ~~ 0.2 * ly1
# Specify covariance of constant change and intercept within the same construct
ly1 ~~ 0.1 * g2
# Specify covariance of constant change and intercept within the same construct
lx1 ~~ 0.1 * j2
# Specify covariance of constant change factors between constructs
g2 ~~ 0.01 * j2
# Specify between-construct coupling parameters ----
# Change score x (t) is determined by true score y (t-1)
dx2 ~ 0.13 * ly1
dx3 ~ 0.13 * ly2
dx4 ~ 0.13 * ly3
dx5 ~ 0.13 * ly4
# Change score y (t) is determined by change score x (t-1)
dy3 ~ 0.4 * dx2
dy4 ~ 0.4 * dx3
dy5 ~ 0.4 * dx4
```
</p>
</details>