@@ -588,6 +588,148 @@ quadraticGCM_re$id <- head(quadraticGCM_re$id)
588588quadraticGCM_re
589589```
590590
591+ ### Logarithmic Growth Curve Model {#sec-logGCM}
592+
593+ “an exponential pattern of change—in which change appears to ‘level off’ over time—can be approximated through linear (and potentially quadratic) slopes for a natural-log-transformed” version of time (Hoffman, 2025).
594+
595+ #### Fit Model
596+
597+ ``` {r}
598+ logGCM <- lmer(
599+ math ~ sex + log(ageYearsCentered + 1) + sex:log(ageYearsCentered + 1) + (1 + log(ageYearsCentered + 1) | id), # random intercepts and logarithmic slopes; sex as a fixed-effect predictor of the intercepts and slopes
600+ data = mydata,
601+ REML = FALSE, #for ML
602+ na.action = na.exclude,
603+ control = lmerControl(optimizer = "bobyqa"))
604+
605+ summary(logGCM)
606+
607+ print(effectsize::standardize_parameters(
608+ logGCM,
609+ method = "refit"),
610+ digits = 2)
611+
612+ performance::r2(logGCM)
613+ ```
614+
615+ #### Prototypical Growth Curve
616+
617+ ``` {r}
618+ newData <- expand.grid(
619+ female = c(0, 1),
620+ ageYears = seq(from = min(mydata$ageYears, na.rm = TRUE), to = max(mydata$ageYears, na.rm = TRUE), length.out = 10000))
621+
622+ newData$ageYearsCentered <- newData$ageYears - min(newData$ageYears)
623+
624+ newData$sex <- NA
625+ newData$sex[which(newData$female == 0)] <- "male"
626+ newData$sex[which(newData$female == 1)] <- "female"
627+ newData$sex <- as.factor(newData$sex)
628+
629+ newData$predictedValue <- predict( # predict.merMod
630+ logGCM,
631+ newdata = newData,
632+ re.form = NA
633+ )
634+
635+ ggplot(
636+ data = newData,
637+ mapping = aes(
638+ x = ageYears,
639+ y = predictedValue,
640+ color = sex)) +
641+ geom_line() +
642+ labs(
643+ x = "Age (years)",
644+ y = "Math Score",
645+ color = "Sex"
646+ ) +
647+ theme_classic()
648+ ```
649+
650+ #### Individuals' Growth Curves
651+
652+ ``` {r}
653+ mydata$predictedValue <- predict(
654+ logGCM,
655+ newdata = mydata,
656+ re.form = NULL
657+ )
658+
659+ ggplot(
660+ data = mydata,
661+ mapping = aes(
662+ x = ageYears,
663+ y = predictedValue,
664+ group = id,
665+ color = sex)) +
666+ geom_line(
667+ stat = "smooth",
668+ method = "lm",
669+ formula = y ~ log(x + 1),
670+ se = FALSE,
671+ linewidth = 0.5,
672+ alpha = 0.4
673+ ) +
674+ labs(
675+ x = "Age (years)",
676+ y = "Math Score",
677+ color = "Sex"
678+ ) +
679+ theme_classic()
680+ ```
681+
682+ #### Individuals' Trajectories Overlaid with Prototypical Trajectory
683+
684+ ``` {r}
685+ ggplot(
686+ data = mydata,
687+ mapping = aes(
688+ x = ageYears,
689+ y = predictedValue,
690+ group = id)) +
691+ geom_line( # individuals' trajectories
692+ stat = "smooth",
693+ method = "lm",
694+ formula = y ~ log(x + 1),
695+ se = FALSE,
696+ linewidth = 0.5,
697+ color = "gray",
698+ alpha = 0.4
699+ ) +
700+ geom_line( # prototypical trajectory
701+ data = newData,
702+ mapping = aes(
703+ x = ageYears,
704+ y = predictedValue,
705+ group = sex,
706+ color = sex),
707+ linewidth = 2) +
708+ labs(
709+ x = "Age (years)",
710+ y = "Math Score",
711+ color = "Sex"
712+ ) +
713+ theme_classic()
714+ ```
715+
716+ #### Extract Random Effects
717+
718+ ``` {r}
719+ #| output: false
720+
721+ ranef(logGCM)
722+ ```
723+
724+ ``` {r}
725+ #| echo: false
726+
727+ logGCM_re <- ranef(logGCM)
728+
729+ logGCM_re$id <- head(logGCM_re$id)
730+ logGCM_re
731+ ```
732+
591733### Spline Growth Curve Model {#sec-splineGCM}
592734
593735#### Create Knot
0 commit comments