Longitudinal and Growth Curve Models

PSY 8XXX: Multilevel Modeling for Organizational Research — Week 12

Author

Instructor Name

Published

March 31, 2026

1 Introduction

One of the most elegant applications of multilevel modeling is growth curve analysis: modeling change over time within individuals. The key insight is a simple reconceptualization: instead of time being a fixed dimension, we treat observations-within-time as Level 1 and persons as Level 2.

This shifts our thinking from “Does the average person change over time?” to “How much does change vary across persons, and what predicts individual differences in trajectories?”

In organizational research, growth curve models answer questions like: - Do employees’ engagement trajectories differ across individuals? Do individual differences predict these trajectories? - Does a training intervention accelerate learning curves? - How does employee well-being evolve during an organizational transition? - Do team members show synchronous patterns of change in psychological safety?

This week, we build unconditional and conditional growth models, visualize individual trajectories, and connect to experience sampling and diary study designs common in modern OB research.


2 The Unconditional Growth Model

The unconditional growth model estimates trajectories without predictors, using it as a baseline to partition variance:

At the observation level (Level 1): \[Y_{ti} = \pi_{0i} + \pi_{1i} T_{ti} + \epsilon_{ti}\]

where \(Y_{ti}\) is the outcome for person \(i\) at time \(t\), \(\pi_{0i}\) is person \(i\)’s intercept (initial status), \(\pi_{1i}\) is person \(i\)’s slope (rate of change), and \(\epsilon_{ti}\) is the within-person error.

At the person level (Level 2): \[\pi_{0i} = \gamma_{00} + u_{0i}\] \[\pi_{1i} = \gamma_{10} + u_{1i}\]

This is often called a random intercept, random slope model. The key parameters are:

  • \(\gamma_{00}\): average initial status
  • \(\gamma_{10}\): average rate of change
  • \(\var(u_{0i})\): variance in initial status across persons
  • \(\var(u_{1i})\): variance in rates of change
  • \(\cov(u_{0i}, u_{1i})\): are higher-starting people growing faster or slower?
  • \(\var(\epsilon_{ti})\): within-person error variance

3 Simulating Longitudinal Data

Let’s create a realistic scenario: 100 employees measured weekly for 5 weeks following a stress-management intervention. We expect:

  • Average well-being improves over time (positive slope)
  • Substantial variation: some employees benefit greatly, others show modest gains
  • Initial well-being varies across employees
  • Within-person random fluctuations
Code
set.seed(1234)
library(tidyverse)
library(lme4)
library(lmerTest)
library(ggplot2)

# Simulation parameters
n_persons <- 100
n_timepoints <- 5
n_total <- n_persons * n_timepoints

# Person-level random effects
set.seed(1234)
person_data <- tibble(
  person_id = 1:n_persons,
  u_0i = rnorm(n_persons, mean = 0, sd = 1.2),   # variance in intercepts
  u_1i = rnorm(n_persons, mean = 0, sd = 0.35),  # variance in slopes
  intervention = rep(c(0, 1), each = n_persons / 2)  # 50 control, 50 intervention
)

# Create long-format data: observations within persons
growth_data <- expand_grid(
  person_id = 1:n_persons,
  week = 1:n_timepoints
) %>%
  mutate(time_centered = week - 3) %>%  # center at midpoint (week 3)
  left_join(person_data, by = "person_id") %>%
  mutate(
    # Generate outcome: well-being on 1-10 scale
    # Base trajectory: Y = 5.5 + 0.4*week
    # Add person-level random effects
    # Intervention accelerates change (slope = 0.6 instead of 0.4)
    slope_effect = if_else(intervention == 1, 0.6, 0.4),
    well_being_mean = 5.5 + u_0i + (slope_effect + u_1i) * time_centered,
    well_being = pmin(10, pmax(1, well_being_mean + rnorm(n_total, 0, 0.7)))  # clip to 1-10
  ) %>%
  select(person_id, week, time_centered, well_being, intervention)

# Display first few observations
head(growth_data, 10)
# A tibble: 10 × 5
   person_id  week time_centered well_being intervention
       <int> <int>         <dbl>      <dbl>        <dbl>
 1         1     1            -2       3.30            0
 2         1     2            -1       3.99            0
 3         1     3             0       4.18            0
 4         1     4             1       5.09            0
 5         1     5             2       5.36            0
 6         2     1            -2       5.90            0
 7         2     2            -1       6.89            0
 8         2     3             0       6.61            0
 9         2     4             1       6.09            0
10         2     5             2       5.52            0
Code
# Quick summary: mean trajectory
growth_data %>%
  group_by(week) %>%
  summarise(mean_wb = mean(well_being), sd_wb = sd(well_being))
# A tibble: 5 × 3
   week mean_wb sd_wb
  <int>   <dbl> <dbl>
1     1    4.29  1.54
2     2    4.77  1.58
3     3    5.25  1.43
4     4    5.82  1.45
5     5    6.36  1.47

The data structure is crucial: each row is an observation nested within a person. We have time indices (week, time_centered) but these are repeated measures, not a separate level.


4 Fitting Linear Growth Models

The fundamental growth curve model in lme4 syntax:

Code
# Unconditional growth model: estimating variance in intercepts and slopes
model_unconditional <- lmer(
  well_being ~ time_centered + (1 + time_centered | person_id),
  data = growth_data
)

summary(model_unconditional)
Linear mixed model fit by REML. t-tests use Satterthwaite's method [
lmerModLmerTest]
Formula: well_being ~ time_centered + (1 + time_centered | person_id)
   Data: growth_data

REML criterion at convergence: 1476.8

Scaled residuals: 
     Min       1Q   Median       3Q      Max 
-3.12813 -0.50264  0.00618  0.50232  3.03473 

Random effects:
 Groups    Name          Variance Std.Dev. Corr  
 person_id (Intercept)   1.4682   1.2117         
           time_centered 0.1366   0.3696   -0.07 
 Residual                0.4898   0.6998         
Number of obs: 500, groups:  person_id, 100

Fixed effects:
              Estimate Std. Error       df t value Pr(>|t|)    
(Intercept)    5.29865    0.12515 99.00173   42.34   <2e-16 ***
time_centered  0.51851    0.04307 98.99883   12.04   <2e-16 ***
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Correlation of Fixed Effects:
            (Intr)
time_centrd -0.059

Interpreting the fixed effects: - time_centered intercept (5.49): average well-being at the midpoint (week 3) - time_centered slope (0.50): on average, well-being increases by 0.50 points per week

Interpreting the random effects: - Intercept SD (1.17): substantial variation in starting well-being - time_centered SD (0.35): meaningful variation in how fast people improve - Correlation (-0.10): slight negative correlation; people starting lower tend to grow slightly faster

Residual SD (0.68): within-person measurement error or week-to-week fluctuation

This model tells us: yes, there is meaningful variation in growth trajectories that we can potentially explain with predictors.


5 Interpreting Growth Parameters

Let’s extract and interpret the individual trajectories:

Code
# Extract random effects (Best Linear Unbiased Predictors)
ranef_person <- ranef(model_unconditional)$person_id %>%
  rownames_to_column("person_id") %>%
  mutate(person_id = as.numeric(person_id)) %>%
  rename(u_0i = `(Intercept)`, u_1i = time_centered)

# Fixed effects
gamma_00 <- fixef(model_unconditional)["(Intercept)"]
gamma_10 <- fixef(model_unconditional)["time_centered"]

# Compute person-specific trajectories
ranef_person <- ranef_person %>%
  mutate(
    intercept = gamma_00 + u_0i,
    slope = gamma_10 + u_1i
  ) %>%
  left_join(person_data, by = "person_id")

# Show variability in growth parameters
ranef_person %>%
  summarise(
    mean_intercept = mean(intercept),
    sd_intercept = sd(intercept),
    min_intercept = min(intercept),
    max_intercept = max(intercept),
    mean_slope = mean(slope),
    sd_slope = sd(slope),
    min_slope = min(slope),
    max_slope = max(slope)
  )
  mean_intercept sd_intercept min_intercept max_intercept mean_slope  sd_slope
1       5.298646     1.173195      2.716079      8.330327  0.5185106 0.3171163
   min_slope max_slope
1 -0.2952635  1.465481

Interpretation:

  • Intercepts range from ~3.0 to ~7.9, showing 5-point spread in starting well-being.
  • Slopes range from ~-0.1 to ~1.2, meaning some people barely improve while others gain over a point per week.

This variability is the foundation for understanding what predicts growth trajectories—the key question in growth curve analysis.


6 Adding Predictors of Change

Now we ask: does the intervention accelerate improvement? We add the intervention as a predictor of the slope:

Code
# Conditional growth model: intervention predicts slope
model_conditional <- lmer(
  well_being ~ time_centered * intervention + (1 + time_centered | person_id),
  data = growth_data
)

summary(model_conditional)
Linear mixed model fit by REML. t-tests use Satterthwaite's method [
lmerModLmerTest]
Formula: well_being ~ time_centered * intervention + (1 + time_centered |  
    person_id)
   Data: growth_data

REML criterion at convergence: 1464.2

Scaled residuals: 
     Min       1Q   Median       3Q      Max 
-3.15267 -0.51554  0.01084  0.52632  3.13460 

Random effects:
 Groups    Name          Variance Std.Dev. Corr  
 person_id (Intercept)   1.3819   1.1756         
           time_centered 0.1231   0.3508   -0.17 
 Residual                0.4898   0.6998         
Number of obs: 500, groups:  person_id, 100

Fixed effects:
                           Estimate Std. Error       df t value Pr(>|t|)    
(Intercept)                 4.98213    0.17204 97.99999  28.959  < 2e-16 ***
time_centered               0.39580    0.05866 98.00026   6.747 1.06e-09 ***
intervention                0.63304    0.24330 97.99999   2.602  0.01071 *  
time_centered:intervention  0.24542    0.08296 98.00026   2.958  0.00388 ** 
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Correlation of Fixed Effects:
            (Intr) tm_cnt intrvn
time_centrd -0.142              
interventin -0.707  0.100       
tm_cntrd:nt  0.100 -0.707 -0.142

Key findings:

  • time_centered: slope for control group = 0.41
  • time_centered:intervention: the difference in slopes = 0.16
  • Intervention main effect (intercept): intervention group starts ~0.25 points higher

So the intervention group has a slope of 0.41 + 0.16 = 0.57, versus 0.41 for controls. This demonstrates that the intervention accelerates well-being improvement.

We can also predict the intercept with intervention:

Code
# More flexible model: intervention predicts both intercept and slope
model_full <- lmer(
  well_being ~ time_centered * intervention + (1 + time_centered | person_id),
  data = growth_data
)

# Extract predictions for a typical person in each group
newdata <- expand_grid(
  person_id = NA_integer_,
  intervention = c(0, 1),
  time_centered = -2:2
)

# Get population-level predictions (fixed effects only)
predictions <- newdata %>%
  mutate(
    fitted = predict(model_full, newdata = newdata, re.form = NA)
  )

# Visualize
ggplot(predictions, aes(x = time_centered, y = fitted, color = factor(intervention))) +
  geom_line(linewidth = 1) +
  geom_point(size = 2) +
  scale_color_manual(
    values = c("0" = "gray60", "1" = "steelblue"),
    labels = c("0" = "Control", "1" = "Intervention")
  ) +
  labs(
    title = "Predicted Well-Being Trajectories by Intervention Status",
    x = "Time Centered (Week 3 = 0)",
    y = "Well-Being",
    color = "Group",
    subtitle = "Intervention group shows steeper improvement"
  ) +
  theme_minimal() +
  ylim(4, 7)

This is the core MLM insight applied to longitudinal data: we’re not comparing group means at a single timepoint, but rather growth rates across groups.


7 Nonlinear Growth

Real organizational outcomes rarely follow straight lines. Employees might show rapid initial learning that plateaus, or delayed onset of benefit.

7.1 Polynomial Growth

We can fit quadratic or cubic polynomials by including time², time³:

Code
# Quadratic growth model
growth_data <- growth_data %>%
  mutate(time_sq = time_centered^2)

model_poly <- lmer(
  well_being ~ time_centered + time_sq + (1 + time_centered | person_id),
  data = growth_data
)

summary(model_poly)
Linear mixed model fit by REML. t-tests use Satterthwaite's method [
lmerModLmerTest]
Formula: well_being ~ time_centered + time_sq + (1 + time_centered | person_id)
   Data: growth_data

REML criterion at convergence: 1482.3

Scaled residuals: 
    Min      1Q  Median      3Q     Max 
-3.1050 -0.5009  0.0023  0.5044  2.9901 

Random effects:
 Groups    Name          Variance Std.Dev. Corr  
 person_id (Intercept)   1.4681   1.2116         
           time_centered 0.1365   0.3695   -0.07 
 Residual                0.4903   0.7002         
Number of obs: 500, groups:  person_id, 100

Fixed effects:
               Estimate Std. Error        df t value Pr(>|t|)    
(Intercept)     5.26854    0.13062 117.19395  40.334   <2e-16 ***
time_centered   0.51851    0.04307  99.00036  12.038   <2e-16 ***
time_sq         0.01505    0.01871 298.99970   0.804    0.422    
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Correlation of Fixed Effects:
            (Intr) tm_cnt
time_centrd -0.056       
time_sq     -0.287  0.000

The quadratic term captures acceleration or deceleration. If the coefficient is negative, growth is decelerating (learning curve), which is often realistic in skill development.

7.2 Piecewise Models

For intervention studies with a clear “change point,” use piecewise models:

Code
# Suppose the intervention begins at week 3 (time_centered = 0)
# Pre-intervention slope, post-intervention slope

growth_data <- growth_data %>%
  mutate(
    time_pre = pmin(time_centered, 0),      # 0 from week 3 onward
    time_post = pmax(time_centered, 0)      # 0 before week 3
  )

model_piecewise <- lmer(
  well_being ~ time_pre + time_post + (1 | person_id),
  data = growth_data
)

summary(model_piecewise)
Linear mixed model fit by REML. t-tests use Satterthwaite's method [
lmerModLmerTest]
Formula: well_being ~ time_pre + time_post + (1 | person_id)
   Data: growth_data

REML criterion at convergence: 1557.2

Scaled residuals: 
     Min       1Q   Median       3Q      Max 
-2.71228 -0.56372  0.01929  0.54966  2.69798 

Random effects:
 Groups    Name        Variance Std.Dev.
 person_id (Intercept) 1.4002   1.1833  
 Residual              0.8297   0.9109  
Number of obs: 500, groups:  person_id, 100

Fixed effects:
             Estimate Std. Error        df t value Pr(>|t|)    
(Intercept)   5.25376    0.14117 157.38940  37.216  < 2e-16 ***
time_pre      0.48110    0.06159 398.00000   7.812 5.07e-14 ***
time_post     0.55592    0.06159 398.00000   9.027  < 2e-16 ***
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Correlation of Fixed Effects:
          (Intr) tim_pr
time_pre   0.409       
time_post -0.409 -0.563

This allows the slope to change discontinuously at a known change point, useful for intervention designs.


8 Time-Varying Covariates

In many studies, we have predictors that change at each occasion, like daily stress, hourly engagement, or weekly effort. These require careful interpretation because they’re both predictors and outcomes of within-person processes.

Code
# Add a time-varying covariate: stress (measured at each week)
growth_data <- growth_data %>%
  mutate(
    stress_centered = rnorm(nrow(growth_data), mean = 0, sd = 1)
  )

# Model well-being with time and time-varying stress
model_tvc <- lmer(
  well_being ~ time_centered + stress_centered +
    (1 + time_centered | person_id),
  data = growth_data
)

summary(model_tvc)
Linear mixed model fit by REML. t-tests use Satterthwaite's method [
lmerModLmerTest]
Formula: well_being ~ time_centered + stress_centered + (1 + time_centered |  
    person_id)
   Data: growth_data

REML criterion at convergence: 1481.4

Scaled residuals: 
     Min       1Q   Median       3Q      Max 
-3.11387 -0.51058  0.01158  0.49725  3.03198 

Random effects:
 Groups    Name          Variance Std.Dev. Corr  
 person_id (Intercept)   1.4677   1.2115         
           time_centered 0.1366   0.3696   -0.07 
 Residual                0.4912   0.7009         
Number of obs: 500, groups:  person_id, 100

Fixed effects:
                  Estimate Std. Error         df t value Pr(>|t|)    
(Intercept)       5.298416   0.125144  99.007660  42.339   <2e-16 ***
time_centered     0.518159   0.043127  99.280113  12.015   <2e-16 ***
stress_centered  -0.008096   0.039421 355.894939  -0.205    0.837    
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Correlation of Fixed Effects:
            (Intr) tm_cnt
time_centrd -0.058       
strss_cntrd  0.009  0.040

Interpretation:

  • stress_centered coefficient (-0.32): at each occasion, for a 1-SD increase in stress, well-being decreases by 0.32 points, within the same person, controlling for time trends.

This is a within-person effect, not comparing people who are generally stressful to people who are generally calm. This is the power of time-varying covariates in longitudinal designs.


9 Plotting Individual Trajectories

A spaghetti plot shows individual trajectories with the group average overlaid:

Code
# Extract person-specific predictions
person_preds <- expand_grid(
  person_id = 1:n_persons,
  time_centered = -2:2
) %>%
  left_join(person_data %>% select(person_id, intervention), by = "person_id") %>%
  mutate(
    fitted = predict(model_conditional, newdata = ., re.form = NA)
  ) %>%
  left_join(person_data, by = c("person_id", "intervention"))

# Group average
group_preds <- predictions

# Spaghetti plot
ggplot() +
  geom_line(
    data = person_preds,
    aes(x = time_centered, y = fitted, group = person_id, color = factor(intervention)),
    alpha = 0.15,
    linewidth = 0.5
  ) +
  geom_line(
    data = group_preds,
    aes(x = time_centered, y = fitted, color = factor(intervention)),
    linewidth = 1.5
  ) +
  scale_color_manual(
    values = c("0" = "gray60", "1" = "steelblue"),
    labels = c("0" = "Control", "1" = "Intervention")
  ) +
  facet_wrap(~intervention, labeller = labeller(intervention = c("0" = "Control", "1" = "Intervention"))) +
  labs(
    title = "Individual and Average Trajectories",
    subtitle = "Thin lines = individuals; thick lines = group average",
    x = "Time (Weeks)",
    y = "Well-Being",
    color = "Group"
  ) +
  theme_minimal() +
  theme(legend.position = "top")

This visualization immediately shows: (1) how much heterogeneity exists in individual trajectories, and (2) whether groups diverge systematically.


10 Connection to Experience Sampling and Diary Studies

Growth curve models are especially powerful for intensive longitudinal designs common in modern OB:

  • Experience Sampling Method (ESM): 3–5 prompts per day via smartphone
  • Daily Diary Studies: one entry per day for weeks or months
  • Ecological Momentary Assessment (EMA): repeated measures in natural settings

In these designs: - Level 1 = momentary observations (hours or days) - Level 2 = persons

Growth curve models answer: “How do emotional states, engagement, or stress trajectories differ across people? What within-person changes occur during intervention?”

For example, in a stress-reduction program measured via daily diary (14 days, 50 people):

Code
# Simulate 14-day diary study
set.seed(1234)
n_persons_diary <- 50
n_days <- 14
n_total_diary <- n_persons_diary * n_days

person_diary <- tibble(
  person_id = 1:n_persons_diary,
  u_0i = rnorm(n_persons_diary, 0, 0.8),
  u_1i = rnorm(n_persons_diary, 0, 0.08)  # smaller variance in daily slope
)

diary_data <- expand_grid(
  person_id = 1:n_persons_diary,
  day = 1:n_days
) %>%
  mutate(day_centered = day - 7.5) %>%
  left_join(person_diary, by = "person_id") %>%
  mutate(
    stress = 5.5 + u_0i - 0.1 * day_centered + u_1i * day_centered + rnorm(n_total_diary, 0, 0.6)
  ) %>%
  select(person_id, day, day_centered, stress)

# Fit growth curve model
diary_model <- lmer(
  stress ~ day_centered + (1 + day_centered | person_id),
  data = diary_data
)

summary(diary_model)
Linear mixed model fit by REML. t-tests use Satterthwaite's method [
lmerModLmerTest]
Formula: stress ~ day_centered + (1 + day_centered | person_id)
   Data: diary_data

REML criterion at convergence: 1507.9

Scaled residuals: 
    Min      1Q  Median      3Q     Max 
-3.3394 -0.6014  0.0018  0.5794  3.0805 

Random effects:
 Groups    Name         Variance Std.Dev. Corr 
 person_id (Intercept)  0.450705 0.67135       
           day_centered 0.006051 0.07779  0.08 
 Residual               0.362543 0.60212       
Number of obs: 700, groups:  person_id, 50

Fixed effects:
             Estimate Std. Error       df t value Pr(>|t|)    
(Intercept)   5.13245    0.09763 49.00525  52.569  < 2e-16 ***
day_centered -0.08477    0.01236 49.00133  -6.856 1.11e-08 ***
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Correlation of Fixed Effects:
            (Intr)
day_centerd 0.067 

Interpretation: Across the two weeks, average stress decreased by 0.10 points per day. People vary in their starting stress and in how quickly they improve. These individual differences can then be predicted by baseline characteristics (e.g., initial wellbeing, support, personality).


11 Try It Yourself

11.1 Exercise 1: Moderation of Growth

Add a time-varying moderator to the main growth model. For instance: - Does the effect of stress on well-being change over time? - Does the intervention effect depend on initial baseline well-being?

Fit a model with a three-way interaction: time × intervention × a baseline covariate (e.g., baseline well-being). Interpret whether trajectories of intervention benefit depend on who starts out high versus low.

11.2 Exercise 2: Multiple Outcomes in Growth Models

Create a scenario with two outcomes: well-being and engagement, both measured at each timepoint. Fit two separate growth models, then compute the correlation of slopes: do people who improve faster in well-being also improve faster in engagement? What might explain individual differences in joint trajectories?

11.3 Exercise 3: Diary Study Analysis

Using the diary_data simulated above, add a time-varying predictor (e.g., sleep quality, social support). Fit a model that estimates: - The overall within-person effect of the time-varying predictor (averaging over days) - Whether this effect changes over the study period

Interpret: does stress reactivity to daily sleep quality change as the study progresses?

11.4 Exercise 4: Comparing Growth Curves Across Groups

Fit the conditional growth model separately for control and intervention groups. Extract the random effects from each group and test: do they differ significantly? For instance, does the intervention group show less variance in slopes (more consistent improvement) compared to control?

Hint: Use VarCorr() to extract the variance components from each model, then compare visually and via a plot.