The longitudinal and multilevel simulators generate nested and time-structured data with known generating parameters: VAR(1) multilevel time series for mlVAR / RI-CLPM, two-level (cluster-nested) data with a target intraclass correlation, and linear latent growth-curve trajectories. Each returns a saqr_sim object with $data and the true $params.

simulate_longitudinal()

Generate multilevel time-series data (a VAR(1) process with temporal, contemporaneous, and between-person layers) suitable for testing mlVAR, RI-CLPM, latent growth, and similar longitudinal models.

Signature

args(simulate_longitudinal)
#> function (n = 50L, tp = 50L, vars = 4L, temporal = NULL, contemporaneous = NULL, 
#>     between = NULL, grand_means = NULL, innovation_sd = 1, beeps_per_day = NULL, 
#>     ar_range = c(0.2, 0.5), cross_range = c(0.05, 0.2), n_cross = NULL, 
#>     complexity = "clean", seed = NULL) 
#> NULL

Example

# 30 subjects, 60 time points, 3 variables
r <- simulate_longitudinal(n = 30, tp = 60, vars = 3, seed = 42)
head(r$data)
r$params$temporal   # the true VAR(1) matrix
#>             V1        V2        V3
#> V1  0.47444181 0.0000000 0.0000000
#> V2  0.16048825 0.4811226 0.0000000
#> V3 -0.07019999 0.1485488 0.2858419

# Explicit temporal structure
B <- matrix(c(0.4,  0.0, 0.1,
              0.2,  0.3, 0.0,
              0.0, -0.1, 0.5), nrow = 3, byrow = TRUE)
r2 <- simulate_longitudinal(n = 50, tp = 100, vars = 3, temporal = B, seed = 1)
str(r2$params, max.level = 1)
#> List of 8
#>  $ temporal       : num [1:3, 1:3] 0.4 0.2 0 0 0.3 -0.1 0.1 0 0.5
#>   ..- attr(*, "dimnames")=List of 2
#>  $ contemporaneous: num [1:3, 1:3] 1 0 0 0 1 0 0 0 1
#>   ..- attr(*, "dimnames")=List of 2
#>  $ between        : num [1:3, 1:3] 1 0 0 0 1 0 0 0 1
#>   ..- attr(*, "dimnames")=List of 2
#>  $ grand_means    : Named num [1:3] 0 0 0
#>   ..- attr(*, "names")= chr [1:3] "V1" "V2" "V3"
#>  $ innovation_sd  : Named num [1:3] 1 1 1
#>   ..- attr(*, "names")= chr [1:3] "V1" "V2" "V3"
#>  $ n              : int 50
#>  $ tp             : int 100
#>  $ var_names      : chr [1:3] "V1" "V2" "V3"

simulate_mlm()

Generate two-level data where level-1 units are nested within clusters, with a target intraclass correlation and a fixed slope on the first predictor (and an optional cluster random slope), designed so both are recovered at large n_clusters. The core example below does not require lme4; an optional fit is shown afterwards.

Signature

args(simulate_mlm)
#> function (n_clusters = 30, cluster_size = 20, intercept = 0, 
#>     slope = 0.5, residual_sd = 1, icc = 0.1, n_predictors = 1, 
#>     random_slope = FALSE, slope_sd = 0, seed = NULL) 
#> NULL

Example

r <- simulate_mlm(n_clusters = 40, cluster_size = 25, slope = 0.8,
                  icc = 0.2, seed = 1)
print(r)
#> saqr_sim [mlm]  1000 x 3  (seed=1)
#>   params: intercept, slope, betas, icc, tau00, residual_sd, slope_sd, random_slope, cluster_size, cluster_intercepts, cluster_slopes 
#>   cols:   cluster_id, y, x1
head(r$data)
str(r$params)
#> List of 11
#>  $ intercept         : num 0
#>  $ slope             : num 0.8
#>  $ betas             : Named num 0.8
#>   ..- attr(*, "names")= chr "x1"
#>  $ icc               : num 0.2
#>  $ tau00             : num 0.25
#>  $ residual_sd       : num 1
#>  $ slope_sd          : num 0
#>  $ random_slope      : logi FALSE
#>  $ cluster_size      : Named int [1:40] 25 25 25 25 25 25 25 25 25 25 ...
#>   ..- attr(*, "names")= chr [1:40] "cluster_1" "cluster_2" "cluster_3" "cluster_4" ...
#>  $ cluster_intercepts: Named num [1:40] -0.3132 0.0918 -0.4178 0.7976 0.1648 ...
#>   ..- attr(*, "names")= chr [1:40] "cluster_1" "cluster_2" "cluster_3" "cluster_4" ...
#>  $ cluster_slopes    : NULL
# Optional: recover the fixed slope and ICC with lme4
m <- lme4::lmer(y ~ x1 + (1 | cluster_id), data = r$data)
lme4::fixef(m)
#> (Intercept)          x1 
#>  0.03006212  0.80627900
print(lme4::VarCorr(m))
#>  Groups     Name        Std.Dev.
#>  cluster_id (Intercept) 0.45802 
#>  Residual               1.03960

simulate_growth()

Generate longitudinal data from a linear latent growth-curve model: each subject draws a random intercept and slope from a bivariate normal, then \(y_{it} = b_{0i} + b_{1i}\,t + e_{it}\) with time coded 0..(n_time - 1). Returned in long format.

Signature

args(simulate_growth)
#> function (n = 200, n_time = 5, intercept_mean = 0, slope_mean = 1, 
#>     intercept_sd = 1, slope_sd = 0.5, intercept_slope_cor = 0, 
#>     residual_sd = 1, seed = NULL) 
#> NULL

Example

r <- simulate_growth(n = 300, n_time = 6, slope_mean = 2,
                     intercept_sd = 1.5, seed = 1)
print(r)
#> saqr_sim [growth]  1800 x 3  (seed=1)
#>   params: means, sds, correlation, residual_sd, n_time, subject_intercepts, subject_slopes 
#>   cols:   subject, time, y
head(r$data)
str(r$params)
#> List of 7
#>  $ means             : Named num [1:2] 0 2
#>   ..- attr(*, "names")= chr [1:2] "intercept" "slope"
#>  $ sds               : Named num [1:2] 1.5 0.5
#>   ..- attr(*, "names")= chr [1:2] "intercept" "slope"
#>  $ correlation       : num 0
#>  $ residual_sd       : num 1
#>  $ n_time            : int 6
#>  $ subject_intercepts: Named num [1:300] -0.94 0.275 -1.253 2.393 0.494 ...
#>   ..- attr(*, "names")= chr [1:300] "s1" "s2" "s3" "s4" ...
#>  $ subject_slopes    : Named num [1:300] 2.45 1.48 2.99 1.81 2.83 ...
#>   ..- attr(*, "names")= chr [1:300] "s1" "s2" "s3" "s4" ...
d <- r$data
ids <- head(unique(d$subject), 8)
sub <- d[d$subject %in% ids, ]
plot(sub$time, sub$y, type = "n",
     xlab = "time", ylab = "y",
     main = "simulate_growth(): individual trajectories")
invisible(lapply(split(sub, sub$subject), function(s) {
  s <- s[order(s$time), ]
  lines(s$time, s$y, col = as.integer(factor(s$subject[1], levels = ids)), lwd = 2)
}))
Trajectories of a few subjects.

Trajectories of a few subjects.