Skip to content

Commit 8121110

Browse files
20260615 - logarithmic growth curve models
1 parent 0db5a65 commit 8121110

2 files changed

Lines changed: 441 additions & 0 deletions

File tree

hlm.qmd

Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -588,6 +588,148 @@ quadraticGCM_re$id <- head(quadraticGCM_re$id)
588588
quadraticGCM_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

Comments
 (0)