Generate synthetic multilevel time-series data suitable for testing longitudinal models: multilevel VAR (mlVAR), random-intercept cross-lagged panel models (RI-CLPM), latent growth curves, and similar.
The data-generating process is a VAR(1) model with three layers:
- Temporal
Autoregressive and cross-lagged effects via matrix
B. At each time point,y(t) = mu_i + B (y(t-1) - mu_i) + innovation.- Contemporaneous
Within-time correlations among innovations, given by the Cholesky of
contemporaneous.- Between-person
Person-specific means
mu_idrawn fromN(grand_means, between).
Arguments
- n
Integer. Number of subjects (persons). Default 50.
- tp
Integer. Number of time points per subject. Default 50.
- vars
Integer or character vector. If integer, the number of variables (named
V1...Vp). If character, used as variable names directly. Default 4.- temporal
Numeric matrix (
p x p). The VAR(1) coefficient matrixB. Element[i,j]is the effect of variablejatt-1on variableiatt. Eigenvalues should have modulus < 1 for stationarity. Default: diagonal 0.3 (autoregressive only, no cross-lags).- contemporaneous
Numeric matrix (
p x p). Correlation matrix of the innovation terms (within-time, within-person). Must be symmetric and positive-definite. Default: identity (uncorrelated innovations).- between
Numeric matrix (
p x p). Covariance matrix of the person-specific means. Controls between-person variability. Default: identity.- grand_means
Numeric vector of length
p. Population-level means for each variable. Default: all zeros.- innovation_sd
Numeric scalar or vector of length
p. Standard deviation(s) of the innovation terms (before applying contemporaneous correlation). Default: 1.- beeps_per_day
Integer or NULL. If non-NULL, adds
dayandbeepcolumns (ESM/EMA structure).tpmust be divisible bybeeps_per_day. Default: NULL (singletimecolumn).- ar_range
Numeric vector of length 2. When
temporalis NULL, diagonal (autoregressive) coefficients are drawn uniformly from this range. Default:c(0.2, 0.5).- cross_range
Numeric vector of length 2. When
temporalis NULL, off-diagonal (cross-lag) coefficients are drawn uniformly from this range (with random sign). Default:c(0.05, 0.2).- n_cross
Integer. When
temporalis NULL, the number of non-zero cross-lagged effects to include. Default:min(3, p*(p-1)).- complexity
Character. Edge-case injection, same semantics as
simulate_data. One of"clean"(default),"auto", or a character vector of specific cases (e.g.c("na", "outliers")). Supported cases:"na","outliers","heavy_tailed","heteroscedastic","tiny_n".- seed
Integer or NULL. Random seed.
Value
A saqr_sim object with:
$datadata.frame with columns
id,time(orday/beep), andV1...Vp.$paramslist with
temporal(B matrix),contemporaneous(innovation correlation),between(person-mean covariance),grand_means,innovation_sd,n,tp,var_names.
Details
The temporal matrix B must be stationary (all eigenvalues inside the
unit circle). If an auto-generated or user-supplied B violates this,
it is rescaled by 0.95 / max(Mod(eigen(B)$values)).
For ESM-style data with beeps_per_day, the first observation of each
day is treated as a new starting point (no carry-over from previous day's
last beep), matching the assumption in most ESM-VAR software.
Examples
# Basic: 30 subjects, 60 time points, 3 variables
r <- simulate_longitudinal(n = 30, tp = 60, vars = 3, seed = 42)
head(r$data)
#> id time V1 V2 V3
#> 1 1 1 0.3797833 -2.2436730 0.4158307
#> 2 1 2 1.6277822 -0.4671853 1.2661451
#> 3 1 3 0.5634720 1.2353289 -0.0260383
#> 4 1 4 1.1672413 -0.3871001 0.4766459
#> 5 1 5 1.5363739 -0.5293727 0.4341972
#> 6 1 6 1.6313855 -1.1431780 -0.1041086
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)
# ESM structure with days and beeps
r3 <- simulate_longitudinal(n = 40, tp = 70, vars = 4,
beeps_per_day = 7, seed = 7)
head(r3$data) # has day + beep columns
#> id day beep V1 V2 V3 V4
#> 1 1 1 1 0.5680978 0.9114328 -2.2195456 -2.3066352
#> 2 1 1 2 0.6722628 1.8719812 -1.9654093 0.1321454
#> 3 1 1 3 0.6629147 1.7280159 0.7235085 0.2023174
#> 4 1 1 4 -0.3923350 3.1467353 2.3565133 1.2055313
#> 5 1 1 5 -0.5550650 1.8820806 -0.2582258 1.3479448
#> 6 1 1 6 0.1905947 -0.8165545 -1.0377736 -1.6080693
# With edge-case injection
r4 <- simulate_longitudinal(n = 30, tp = 50, vars = 3,
complexity = c("na", "outliers"), seed = 5)