Contents

Overview Experimental (0.16.6+)

The ml_var family models a multi-level (random intercept) lag-1 vector autoregression for intensive longitudinal data: many repeated measures nested in subjects, as collected in experience sampling (ESM) or ecological momentary assessment (EMA) studies. The ml_gvar() wrapper parameterizes the covariance structures as Gaussian graphical models, yielding the three familiar multi-level GVAR networks (as in the mlVAR package):

The estimand is the same multi-level VAR with random intercepts that panelvar() / panelgvar() target, but the family is designed for long time series, where the full-information panel likelihood is computationally infeasible. Its default summary-statistics estimator compresses each subject's time series once into two-level sufficient statistics, so estimation cost is independent of the number of time points.

Experimental: this family is new in psychonetrics 0.16.6/0.16.7 and marked experimental — a note is shown once per session. Please report unexpected behavior on GitHub.

The Multi-level VAR(1) Model

Each subject $i$ follows a within-person stationary VAR(1) process around a person-specific mean:

$$\boldsymbol{y}_{it} = \boldsymbol{\mu} + \boldsymbol{b}_i + \boldsymbol{B}\,(\boldsymbol{y}_{i,t-1} - \boldsymbol{\mu} - \boldsymbol{b}_i) + \boldsymbol{\zeta}_{it}, \qquad \boldsymbol{b}_i \sim N(\boldsymbol{0}, \boldsymbol{\Sigma}_B)$$

Both covariance structures accept the usual five parameterizations through the within and between arguments ("cov", "chol", "prec", "ggm", "cor"); ml_gvar() sets both to "ggm". Note that this model estimates fixed (population) networks with random intercepts; unlike mlVAR(), it does not model random effects in the temporal or contemporaneous structures themselves.

Estimators: "auto", "ML" and "FIML"

Two estimators are available, selected with the estimator argument:

EstimatorHow it worksWhen to use
"ML" Two-level summary-statistics pseudo maximum likelihood: each subject's series is lag-embedded into (current, lagged) pairs, which are treated as conditionally independent given the random intercept (the same working-independence move var1() makes). The data are compressed once into two-level sufficient statistics, so cost is independent of the number of time points. ESM / intensive longitudinal data: dozens to hundreds of measurements per subject.
"FIML" Full-information maximum likelihood through the panelvar() framework: the measurement occasions become the waves of a panel model (missed beeps and missing responses handled by FIML; a night is bridged by one structurally missing occasion). Exact, but cost grows quickly with the number of occasions. Panel-like data: few (say, at most 10) measurement occasions per subject.

The default estimator = "auto" chooses "FIML" when the measurement-occasion grid has at most 10 occasions per subject and "ML" otherwise, and always prints a message stating the choice. Set estimator explicitly to override.

Rule of thumb: panelvar()/panelgvar() for few-wave panel data, ml_var()/ml_gvar() for long ESM time series — estimator = "auto" implements exactly this rule for you.

Data Preparation

ml_var() takes long-format raw data (one row per subject per measurement occasion), exactly like mlVAR():

Under estimator = "ML", incomplete lag pairs (rows with any missing value among the current and lagged variables) are currently dropped with a warning (complete-pairs analysis); under estimator = "FIML", missing data are handled by full-information ML.

Example: Multi-level Graphical VAR on ESM Data

library("psychonetrics")
library("dplyr")

# Long-format ESM data:
#   id  day  beep  Stressed  Relaxed  Sad  ...
#   1   1    1     2         4        1
#   1   1    2     3         3        1
#   ...

vars <- c("Stressed", "Relaxed", "Sad", "Nervous", "Concentration")

# Multi-level graphical VAR (the message will report the selected estimator):
model <- ml_gvar(data, vars = vars, idvar = "id",
                 dayvar = "day", beepvar = "beep")
model <- model %>% runmodel

# Fit measures (AIC / BIC etc.):
model %>% summary
model %>% fit

# The three networks:
temporal        <- getmatrix(model, "PDC")                 # standardized temporal
contemporaneous <- getmatrix(model, "omega_zeta_within")   # contemporaneous
between         <- getmatrix(model, "omega_zeta_between")  # between-persons

# Visualize:
library("qgraph")
L <- averageLayout(temporal, contemporaneous, between)
layout(t(1:3))
qgraph(temporal, layout = L, theme = "colorblind", directed = TRUE,
       title = "Temporal", vsize = 12)
qgraph(contemporaneous, layout = L, theme = "colorblind",
       title = "Contemporaneous", vsize = 12)
qgraph(between, layout = L, theme = "colorblind",
       title = "Between-persons", vsize = 12)

# The usual workflow applies:
model_pruned <- model %>% prune(alpha = 0.01)
compare(full = model, pruned = model_pruned)
Significance thresholding: getmatrix(model, "omega_zeta_within", threshold = TRUE) hides non-significant edges, similar to getNet(..., nonsig = "hide") in mlVAR.

Statistical Caveats

The summary-statistics estimator ("ML") is a working-independence pseudo (composite) likelihood. Two caveats follow (see ?ml_var1 for simulation details):

Point estimates of the temporal and contemporaneous networks are consistent and closely track both the full-likelihood panelvar() estimates and mlVAR() estimates on the same data.

Naming & History

Summary

Further Reading