@@ -374,6 +374,249 @@ ggplot(
374
374
linewidth = 2)
375
375
```
376
376
377
+ # Latent Basis Growth Curve Model {#lbgcm}
378
+
379
+ ## Model Syntax
380
+
381
+ ### Abbreviated
382
+
383
+ ``` {r}
384
+ lbgcm1_syntax <- '
385
+ # Intercept and slope
386
+ intercept =~ 1*t1 + 1*t2 + 1*t3 + 1*t4
387
+ slope =~ 0*t1 + a*t2 + b*t3 + 3*t4 # freely estimate the loadings for t2 and t3
388
+
389
+ # Regression paths
390
+ intercept ~ x1 + x2
391
+ slope ~ x1 + x2
392
+
393
+ # Time-varying covariates
394
+ t1 ~ c1
395
+ t2 ~ c2
396
+ t3 ~ c3
397
+ t4 ~ c4
398
+ '
399
+ ```
400
+
401
+ ### Full
402
+
403
+ ``` {r}
404
+ lbgcm2_syntax <- '
405
+ # Intercept and slope
406
+ intercept =~ 1*t1 + 1*t2 + 1*t3 + 1*t4
407
+ slope =~ 0*t1 + a*t2 + b*t3 + 3*t4 # freely estimate the loadings for t2 and t3
408
+
409
+ # Regression paths
410
+ intercept ~ x1 + x2
411
+ slope ~ x1 + x2
412
+
413
+ # Time-varying covariates
414
+ t1 ~ c1
415
+ t2 ~ c2
416
+ t3 ~ c3
417
+ t4 ~ c4
418
+
419
+ # Constrain observed intercepts to zero
420
+ t1 ~ 0
421
+ t2 ~ 0
422
+ t3 ~ 0
423
+ t4 ~ 0
424
+
425
+ # Estimate mean of intercept and slope
426
+ intercept ~ 1
427
+ slope ~ 1
428
+ '
429
+ ```
430
+
431
+ ## Fit the Model
432
+
433
+ ### Abbreviated
434
+
435
+ ``` {r}
436
+ lbgcm1_fit <- growth(
437
+ lbgcm1_syntax,
438
+ data = Demo.growth,
439
+ missing = "ML",
440
+ estimator = "MLR",
441
+ meanstructure = TRUE,
442
+ int.ov.free = FALSE,
443
+ int.lv.free = TRUE,
444
+ fixed.x = FALSE,
445
+ em.h1.iter.max = 100000)
446
+ ```
447
+
448
+ ### Full
449
+
450
+ ``` {r}
451
+ lbgcm2_fit <- sem(
452
+ lbgcm2_syntax,
453
+ data = Demo.growth,
454
+ missing = "ML",
455
+ estimator = "MLR",
456
+ meanstructure = TRUE,
457
+ fixed.x = FALSE,
458
+ em.h1.iter.max = 100000)
459
+ ```
460
+
461
+ ## Summary Output
462
+
463
+ ### Abbreviated
464
+
465
+ ``` {r}
466
+ summary(
467
+ lbgcm1_fit,
468
+ fit.measures = TRUE,
469
+ standardized = TRUE,
470
+ rsquare = TRUE)
471
+ ```
472
+
473
+ ### Full
474
+
475
+ ``` {r}
476
+ summary(
477
+ lbgcm2_fit,
478
+ fit.measures = TRUE,
479
+ standardized = TRUE,
480
+ rsquare = TRUE)
481
+ ```
482
+
483
+ ## Estimates of Model Fit
484
+
485
+ ``` {r}
486
+ fitMeasures(
487
+ lbgcm1_fit,
488
+ fit.measures = c(
489
+ "chisq", "df", "pvalue",
490
+ "chisq.scaled", "df.scaled", "pvalue.scaled",
491
+ "chisq.scaling.factor",
492
+ "baseline.chisq","baseline.df","baseline.pvalue",
493
+ "rmsea", "cfi", "tli", "srmr",
494
+ "rmsea.robust", "cfi.robust", "tli.robust"))
495
+ ```
496
+
497
+ ## Residuals of Observed vs. Model-Implied Correlation Matrix
498
+
499
+ ``` {r}
500
+ residuals(
501
+ lbgcm1_fit,
502
+ type = "cor")
503
+ ```
504
+
505
+ ## Modification Indices
506
+
507
+ ``` {r}
508
+ modificationindices(
509
+ lbgcm1_fit,
510
+ sort. = TRUE)
511
+ ```
512
+
513
+ ## Internal Consistency Reliability
514
+
515
+ ``` {r}
516
+ compRelSEM(lbgcm1_fit)
517
+ ```
518
+
519
+ ## Path Diagram
520
+
521
+ ``` {r}
522
+ semPaths(
523
+ lbgcm1_fit,
524
+ what = "Std.all",
525
+ layout = "tree2",
526
+ edge.label.cex = 1.5)
527
+ ```
528
+
529
+ ## Plot Trajectories
530
+
531
+ ### Protoypical Growth Curve
532
+
533
+ ``` {r}
534
+ lbgcm1_intercept <- coef(lbgcm1_fit)["intercept~1"]
535
+ lbgcm1_slope <- coef(lbgcm1_fit)["slope~1"]
536
+ lbgcm1_slopeloadingt2 <- coef(lbgcm1_fit)["a"]
537
+ lbgcm1_slopeloadingt3 <- coef(lbgcm1_fit)["b"]
538
+
539
+ timepoints <- 4
540
+
541
+ newData <- data.frame(
542
+ time = 1:4,
543
+ slopeloading = c(0, lbgcm1_slopeloadingt2, lbgcm1_slopeloadingt3, 3)
544
+ )
545
+
546
+ newData$predictedValue <- NA
547
+ newData$predictedValue <- lbgcm1_intercept + lbgcm1_slope * newData$slopeloading
548
+
549
+ ggplot(
550
+ data = newData,
551
+ mapping = aes(x = time, y = predictedValue)) +
552
+ xlab("Timepoint") +
553
+ ylab("Score") +
554
+ scale_y_continuous(
555
+ limits = c(0, 5)) +
556
+ geom_line()
557
+ ```
558
+
559
+ ### Individuals' Growth Curves
560
+
561
+ ``` {r}
562
+ person_factors <- as.data.frame(predict(lbgcm1_fit))
563
+ person_factors$id <- rownames(person_factors)
564
+
565
+ slope_loadings <- c(0, lbgcm1_slopeloadingt2, lbgcm1_slopeloadingt3, 3)
566
+
567
+ # Compute model-implied values for each person at each time point
568
+ individual_trajectories <- person_factors %>%
569
+ rowwise() %>%
570
+ mutate(
571
+ t1 = intercept + slope * slope_loadings[1],
572
+ t2 = intercept + slope * slope_loadings[2],
573
+ t3 = intercept + slope * slope_loadings[3],
574
+ t4 = intercept + slope * slope_loadings[4]
575
+ ) %>%
576
+ ungroup() %>%
577
+ select(id, t1, t2, t3, t4) %>%
578
+ pivot_longer(
579
+ cols = starts_with("t"),
580
+ names_to = "timepoint",
581
+ values_to = "value") %>%
582
+ mutate(
583
+ time = as.integer(substr(timepoint, 2, 2)) # extract number from "t1", "t2", etc.
584
+ )
585
+
586
+ ggplot(
587
+ data = individual_trajectories,
588
+ mapping = aes(x = time, y = value, group = factor(id))) +
589
+ xlab("Timepoint") +
590
+ ylab("Score") +
591
+ scale_y_continuous(
592
+ limits = c(-10, 20)) +
593
+ geom_line()
594
+ ```
595
+
596
+ ### Individuals' Trajectories Overlaid with Prototypical Trajectory
597
+
598
+ ``` {r}
599
+ #ggplot(
600
+ # data = newData) +
601
+ # xlab("Timepoint") +
602
+ # ylab("Score") +
603
+ # scale_x_continuous(
604
+ # limits = c(0, 3),
605
+ # labels = 1:4) +
606
+ # scale_y_continuous(
607
+ # limits = c(-10, 20)) +
608
+ # geom_abline(
609
+ # mapping = aes(
610
+ # slope = slope,
611
+ # intercept = intercept)) +
612
+ # geom_abline(
613
+ # mapping = aes(
614
+ # slope = lgcm1_slope,
615
+ # intercept = lgcm1_intercept),
616
+ # color = "blue",
617
+ # linewidth = 2)
618
+ ```
619
+
377
620
# Latent Change Score Model {#lcsm}
378
621
379
622
## Model Syntax
0 commit comments