Multivariate Dynamics & Networks
Intensive Longitudinal Data
Overview
This tutorial covers two types of models for examining multivariate dynamics and networks: An N = 1 idiographic approach, and an N = all nomothetic approach.
For the N = 1 model we use a unified
structural equation
model (uSEM) that can be implemented
in R using the pompom package.
For the N = all model we use a
multilevel vector
autoregression model
(mlVAR) that can be implemented in R using the
mlVAR package.
Outline
This script covers the following steps:
A. N = 1 model - unified Structural Equation Model (uSEM)
Set up the uSEM model
Check model summary (model fit statistics)
Data visualization and interpretation of results
B. N = all Multilevel VAR Model
Set up the mlVAR model
Check model summary(model fit statistics)
Data visualization and interpretation of results
C. Selected Readings
for uSEM model: Yang, X., Ram, N., Gest, S., Lydon, D., Conroy, D. E., Pincus, A. L., & Molenaar, P. C. M. (2018). Socioemotional dynamics of emotion regulation and depressive symptoms: A person-specific network approach. Complexity, 2018, Article ID 5094179. doi: 10.1155/2018/5094179 [Open Access https://www.hindawi.com/journals/complexity/2018/5094179/]
for mlVAR model: Bringmann LF, Vissers N, Wichers M, Geschwind N, Kuppens P, Peeters F, et al. (2013) A Network Approach to Psychopathology: New Insights into Clinical Longitudinal Data. PLoS ONE 8(4): e60188. https://doi.org/10.1371/journal.pone.0060188 [Open Access https://journals.plos.org/plosone/article?id=10.1371/journal.pone.0060188]
Preliminaries
Loading Libraries
# Check to see if necessary packages are installed, and install if not
packages <- c("psych", "pompom", "mlVAR", "ggplot2", "dplyr")
if (length(setdiff(packages, rownames(installed.packages()))) > 0) {
install.packages(setdiff(packages, rownames(installed.packages())))
}
# Load packages
library(psych) #data description
library(ggplot2) #data visualization
library(pompom) #uSEM
library(mlVAR) #mlVAR models
library(dplyr) #data manipulationLoading Data
We make use of the extended AMIB Data, a multiple time-scale data set that has been shared for teaching purposes. The data include person-level dispositions, daily diary assessments, and ecological momentary assessments that were obtained after everyday social interactions (event-contingent sampling).
The data are shared with intent to facilitate learning about analysis of intensive longitudinal data (from experience sampling, daily diary, or EMA designs). The data are posted only for teaching purposes and should not be used for research.
Use requires citation and acknowledgement of both this website and the following paper:
Ram, N., Conroy, D. E., Pincus, A. L., Hyde, A. L., & Molloy, L. E. (2012). Tethering theory to method: Using measures of intraindividual variability to operationalize individuals’ dynamic characteristics. In G. Hancock & J. Harring (Eds.), Advances in longitudinal methods in the social and behavioral sciences (pp. 81-110). New York: Information Age.
Specifically, the Phase 2 interaction-level data. This group of 30 participants provided up to 8 reports per day for 21 days. Thus, the time-series are relatively long (> 100 observations per person, M = 140, range = 64-168).
Loading interaction-level file (T = many, 43 assessments per person, on average).
Subsetting to Variables of Interest
For the purpose of illustrating different models we use a not-small (to be truly multivariate) and not-large (for pedagogy) subset of variables:
Person index:
id
Time indices:
day(1-21)interaction(1-168)
Six variables of interest:
igaffinterpersonal affectionigdominterpersonal dominanceagvalaffect valenceagarousaffect arousalstressstresshealthhealth[reverse coded]
Subsetting data to variables of interest:
#subsetting to vaiables of interest
AMIB_interactionP2 <- AMIB_interactionP2 %>%
select(id, day, interaction, igaff, igdom,
agval, agarous, stress, health)
describe(AMIB_interactionP2)## vars n mean sd median trimmed mad min max range skew
## id 1 4200 310.36 77.12 321 308.40 121.57 203 439 236 0.07
## day 2 4200 10.57 5.99 10 10.50 7.41 1 21 20 0.09
## interaction 3 4200 73.88 45.18 71 72.32 54.86 1 168 167 0.23
## igaff 4 4190 7.39 1.78 8 7.69 1.48 1 9 8 -1.43
## igdom 5 4190 6.92 1.62 7 7.08 1.48 1 9 8 -0.93
## agval 6 4189 6.80 2.09 7 7.08 2.22 1 9 8 -0.93
## agarous 7 4189 5.92 2.11 6 6.04 2.97 1 9 8 -0.51
## stress 8 4191 1.22 1.38 1 1.02 1.48 0 5 5 0.97
## health 9 4192 1.08 1.17 1 0.93 1.48 0 5 5 0.88
## kurtosis se
## id -1.21 1.19
## day -1.16 0.09
## interaction -1.00 0.70
## igaff 2.01 0.03
## igdom 0.91 0.02
## agval 0.13 0.03
## agarous -0.56 0.03
## stress 0.02 0.02
## health 0.00 0.02
#getting length of individual time-series
series_length <- AMIB_interactionP2 %>%
group_by(id) %>%
summarize(num_obs = length(unique(interaction)))
describe(series_length)## vars n mean sd median trimmed mad min max range skew kurtosis
## id 1 30 306.97 79.59 318.5 304.04 124.54 203 439 236 0.14 -1.35
## num_obs 2 30 140.00 31.31 152.5 143.96 22.98 64 168 104 -0.75 -0.75
## se
## id 14.53
## num_obs 5.72
Note that the variables are on different scales (e.g., 1-9, 0-5).
A. N = 1 model: unified structural equation model (uSEM)
The uSEM is a person-specific model, meaning that each person is
modeled separately - one model for a person. We illustrate fitting for
one person, and then indicate how we loop through many persons to obtain
models for each person. Implementation is done using the
pompom package by Xiao Yang, Nilam Ram, and Peter Molenaar:
https://cran.r-project.org/web/packages/pompom/index.html
Subsetting to One Person’s Data (id 203)
#select one person's data
data_indiv <- AMIB_interactionP2 %>%
filter(id == 203)
describe(data_indiv)## vars n mean sd median trimmed mad min max range skew
## id 1 111 203.00 0.00 203 203.00 0.00 203 203 0 NaN
## day 2 111 10.39 5.94 10 10.25 7.41 1 21 20 0.19
## interaction 3 111 56.00 32.19 56 56.00 41.51 1 111 110 0.00
## igaff 4 111 8.13 0.53 8 8.15 0.00 7 9 2 0.11
## igdom 5 111 7.96 0.48 8 7.98 0.00 6 9 3 -0.53
## agval 6 111 8.13 0.53 8 8.14 0.00 7 9 2 0.12
## agarous 7 111 7.91 0.47 8 7.94 0.00 6 9 3 -0.70
## stress 8 111 0.15 0.49 0 0.01 0.00 0 3 3 3.56
## health 9 111 0.23 0.60 0 0.09 0.00 0 3 3 3.07
## kurtosis se
## id NaN 0.00
## day -1.15 0.56
## interaction -1.23 3.06
## igaff 0.21 0.05
## igdom 3.10 0.05
## agval 0.30 0.05
## agarous 2.82 0.05
## stress 13.39 0.05
## health 10.05 0.06
Plotting Six-Variate Time-Series for One Person
#plotting intraindividual change
data_indiv %>%
ggplot(aes(x = interaction, group= id)) +
#first variable
geom_line(aes(y=igaff), color=1) +
geom_line(aes(y=igdom), color=2) +
geom_line(aes(y=agval), color=3) +
geom_line(aes(y=agarous), color=4) +
geom_line(aes(y=stress), color=5) +
geom_line(aes(y=health), color=6) +
#plot layouts
scale_x_continuous(name="Interaction #") +
scale_y_continuous(name="Raw Values") +
theme_classic() +
theme(axis.title=element_text(size=14),
axis.text=element_text(size=14),
plot.title=element_text(size=14, hjust=.5)) +
ggtitle("ID # 203")Here it is easy to note that the variables are on different scales (e.g., 1-9, 0-5).
Standardize the Data
For the uSEM, we standardize them all within-person to keep focus on dynamics. Importantly, the data are considered as stationary time-series that fluctuate around zero.
Standardizing within-person:
# standardize specific data columns (not the id or time variables in first 3 columns)
data_indiv[c(4:9)] <- lapply(data_indiv[c(4:9)],
function(x) c(scale(x, center=TRUE, scale=TRUE)))
describe(data_indiv)## vars n mean sd median trimmed mad min max range
## id 1 111 203.00 0.00 203.00 203.00 0.00 203.00 203.00 0.00
## day 2 111 10.39 5.94 10.00 10.25 7.41 1.00 21.00 20.00
## interaction 3 111 56.00 32.19 56.00 56.00 41.51 1.00 111.00 110.00
## igaff 4 111 0.00 1.00 -0.25 0.03 0.00 -2.13 1.64 3.78
## igdom 5 111 0.00 1.00 0.08 0.03 0.00 -4.09 2.16 6.25
## agval 6 111 0.00 1.00 -0.25 0.02 0.00 -2.15 1.65 3.81
## agarous 7 111 0.00 1.00 0.20 0.07 0.00 -4.02 2.31 6.32
## stress 8 111 0.00 1.00 -0.31 -0.29 0.00 -0.31 5.81 6.12
## health 9 111 0.00 1.00 -0.39 -0.24 0.00 -0.39 4.59 4.98
## skew kurtosis se
## id NaN NaN 0.00
## day 0.19 -1.15 0.56
## interaction 0.00 -1.23 3.06
## igaff 0.11 0.21 0.09
## igdom -0.53 3.10 0.09
## agval 0.12 0.30 0.09
## agarous -0.70 2.82 0.09
## stress 3.56 13.39 0.09
## health 3.07 10.05 0.09
Plotting Six-Variate Time-series for One Person (Standardized Vars)
#plotting intraindividual change
data_indiv %>%
ggplot(aes(x = interaction, group= id)) +
#first variable
geom_line(aes(y=igaff), color=1) +
geom_line(aes(y=igdom), color=2) +
geom_line(aes(y=agval), color=3) +
geom_line(aes(y=agarous), color=4) +
geom_line(aes(y=stress), color=5) +
geom_line(aes(y=health), color=6) +
#plot layouts
scale_x_continuous(name="Interaction #") +
scale_y_continuous(name="Standardized Values") +
theme_classic() +
theme(axis.title=element_text(size=14),
axis.text=element_text(size=14),
plot.title=element_text(size=14, hjust=.5)) +
ggtitle("ID # 203")Now we see that all the variables are in standardized form.
Check the Data
It is useful to check that there are data in all columns. If any one of the variables is all missing (or has no variance), the model cannot be fit. Missing data on a few observations within a column is ok.
# check column missing
na_col <- 0
for (col in 1:ncol(data_indiv)) {
if (sum(is.na(data_indiv[,col])) == nrow(data_indiv)){
na_col <- na_col + 1
}
}
na_col## [1] 0
All columns are reported.
Fitting the uSEM Model
In pompom syntax, we need to specify how many variables
are included in the analysis (var.number), the dataset without the
id and time variables (data), the number of lags to examine
(lag.order), whether we want intermediate output (verbose), and whether
to remove non-significant coefficients in the last iteration of model
construction (trim).
Fitting uSEM model to individual data
usem_indiv <- uSEM(var.number = 6,
data = data_indiv[ ,c(4:9)],
lag.order = 1,
verbose = FALSE,
trim = FALSE)For these data, this only took a few seconds.
Save the uSEM Model Summary in an Object
The model summary is put into an object for easy access to the estimated coefficients, the standard errors of the coefficients, and the model fit indices.
Obtaining model summary.
## $beta
## [,1] [,2] [,3] [,4] [,5] [,6] [,7]
## [1,] 0.0000000 0.00000000 0.0000000 0.0000000 0.0000000 0.0000000 0.0000000
## [2,] 0.0000000 0.00000000 0.0000000 0.0000000 0.0000000 0.0000000 0.0000000
## [3,] 0.0000000 0.00000000 0.0000000 0.0000000 0.0000000 0.0000000 0.0000000
## [4,] 0.0000000 0.00000000 0.0000000 0.0000000 0.0000000 0.0000000 0.0000000
## [5,] 0.0000000 0.00000000 0.0000000 0.0000000 0.0000000 0.0000000 0.0000000
## [6,] 0.0000000 0.00000000 0.0000000 0.0000000 0.0000000 0.0000000 0.0000000
## [7,] 0.2179232 0.00000000 0.0000000 0.0000000 0.0000000 0.0000000 0.0000000
## [8,] 0.0000000 -0.06241162 0.0000000 0.1902340 0.0000000 0.0000000 0.5658826
## [9,] 0.0000000 0.00000000 0.2048743 0.0000000 0.0000000 0.0000000 0.3757771
## [10,] 0.0000000 0.00000000 0.0000000 0.1843903 0.0000000 0.0000000 0.3460383
## [11,] 0.0000000 0.00000000 0.0000000 0.0000000 0.4339751 0.0000000 -0.1891902
## [12,] 0.0000000 0.00000000 0.0000000 0.0000000 0.0000000 0.6903588 -0.1366965
## [,8] [,9] [,10] [,11] [,12]
## [1,] 0 0 0 0 0
## [2,] 0 0 0 0 0
## [3,] 0 0 0 0 0
## [4,] 0 0 0 0 0
## [5,] 0 0 0 0 0
## [6,] 0 0 0 0 0
## [7,] 0 0 0 0 0
## [8,] 0 0 0 0 0
## [9,] 0 0 0 0 0
## [10,] 0 0 0 0 0
## [11,] 0 0 0 0 0
## [12,] 0 0 0 0 0
##
## $beta.se
## [,1] [,2] [,3] [,4] [,5] [,6]
## [1,] 0.00000000 0.00000000 0.000000 0.00000000 0.00000000 0.00000000
## [2,] 0.00000000 0.00000000 0.000000 0.00000000 0.00000000 0.00000000
## [3,] 0.00000000 0.00000000 0.000000 0.00000000 0.00000000 0.00000000
## [4,] 0.00000000 0.00000000 0.000000 0.00000000 0.00000000 0.00000000
## [5,] 0.00000000 0.00000000 0.000000 0.00000000 0.00000000 0.00000000
## [6,] 0.00000000 0.00000000 0.000000 0.00000000 0.00000000 0.00000000
## [7,] 0.09186633 0.00000000 0.000000 0.00000000 0.00000000 0.00000000
## [8,] 0.00000000 0.08313478 0.000000 0.08281152 0.00000000 0.00000000
## [9,] 0.00000000 0.00000000 0.085359 0.00000000 0.00000000 0.00000000
## [10,] 0.00000000 0.00000000 0.000000 0.08791538 0.00000000 0.00000000
## [11,] 0.00000000 0.00000000 0.000000 0.00000000 0.08416846 0.00000000
## [12,] 0.00000000 0.00000000 0.000000 0.00000000 0.00000000 0.06710492
## [,7] [,8] [,9] [,10] [,11] [,12]
## [1,] 0.00000000 0 0 0 0 0
## [2,] 0.00000000 0 0 0 0 0
## [3,] 0.00000000 0 0 0 0 0
## [4,] 0.00000000 0 0 0 0 0
## [5,] 0.00000000 0 0 0 0 0
## [6,] 0.00000000 0 0 0 0 0
## [7,] 0.00000000 0 0 0 0 0
## [8,] 0.07904285 0 0 0 0 0
## [9,] 0.08640937 0 0 0 0 0
## [10,] 0.08900623 0 0 0 0 0
## [11,] 0.08519014 0 0 0 0 0
## [12,] 0.06790280 0 0 0 0 0
##
## $psi
## [,1] [,2] [,3] [,4] [,5] [,6]
## [1,] 0.9994419 0.54618258 0.43583469 0.33952881 -0.1836394 -0.18315409
## [2,] 0.5461826 0.99994828 0.23527287 0.34397710 -0.1307191 -0.08030321
## [3,] 0.4358347 0.23527287 0.99943356 0.28759687 -0.1851460 -0.09846587
## [4,] 0.3395288 0.34397710 0.28759687 0.99963571 -0.2103505 -0.08011198
## [5,] -0.1836394 -0.13071910 -0.18514600 -0.21035052 0.9991041 0.09186890
## [6,] -0.1831541 -0.08030321 -0.09846587 -0.08011198 0.0918689 0.99861280
## [7,] 0.0000000 0.00000000 0.00000000 0.00000000 0.0000000 0.00000000
## [8,] 0.0000000 0.00000000 0.00000000 0.00000000 0.0000000 0.00000000
## [9,] 0.0000000 0.00000000 0.00000000 0.00000000 0.0000000 0.00000000
## [10,] 0.0000000 0.00000000 0.00000000 0.00000000 0.0000000 0.00000000
## [11,] 0.0000000 0.00000000 0.00000000 0.00000000 0.0000000 0.00000000
## [12,] 0.0000000 0.00000000 0.00000000 0.00000000 0.0000000 0.00000000
## [,7] [,8] [,9] [,10] [,11] [,12]
## [1,] 0.0000000 0.0000000 0.000000 0.0000000 0.0000000 0.0000000
## [2,] 0.0000000 0.0000000 0.000000 0.0000000 0.0000000 0.0000000
## [3,] 0.0000000 0.0000000 0.000000 0.0000000 0.0000000 0.0000000
## [4,] 0.0000000 0.0000000 0.000000 0.0000000 0.0000000 0.0000000
## [5,] 0.0000000 0.0000000 0.000000 0.0000000 0.0000000 0.0000000
## [6,] 0.0000000 0.0000000 0.000000 0.0000000 0.0000000 0.0000000
## [7,] 0.9278185 0.0000000 0.000000 0.0000000 0.0000000 0.0000000
## [8,] 0.0000000 0.6636745 0.000000 0.0000000 0.0000000 0.0000000
## [9,] 0.0000000 0.0000000 0.761397 0.0000000 0.0000000 0.0000000
## [10,] 0.0000000 0.0000000 0.000000 0.8498415 0.0000000 0.0000000
## [11,] 0.0000000 0.0000000 0.000000 0.0000000 0.7784097 0.0000000
## [12,] 0.0000000 0.0000000 0.000000 0.0000000 0.0000000 0.4926709
##
## $chisq
## chisq
## 37.16166
##
## $cfi
## cfi
## 1
##
## $tli
## tli
## 1.011639
##
## $rmsea
## rmsea
## 0
##
## $srmr
## srmr
## 0.04684503
We see all the matrices of the model as well as some summary fit statistics.
Check Fit Indices
To assess if the model reached a good fit we use a “3 out of 4” rule, meaning that if at least 3 of the 4 following fit rules are satisfied, the model is considered as being a good fitting model. Note that this is an emerging approach in the person-specific uSEM literature (not a standard rule for all SEM),
CFI > .95
TLI > .95
RMSEA < .08
SRMR < .08
Checking if the 3 of 4 Rule is Satisfied
#check for good fit
print(sum(ms_indiv$cfi > .95,
ms_indiv$tli > .95,
ms_indiv$rmsea < .08,
ms_indiv$srmr < .08) >= 3)## [1] TRUE
Becasue the model fitting is iterative and continues until the data are well-represented, we expect to achieve good fit. Lack of good fit may indicate some data problems.
Visualizing the uSEM model
While the matrices above are extremely useful for understanding the model, network visualizations often facilitate interpretation.
Plot model as a network graph.
## NULL
Nodes 1 to 6 represent the six variables. Red/green edges indicate negative/positive temporal relations (or coefficients). Dashed edges indicate lag-1 relations and solid edges indicate contemporaneous relations. The width of the edge indicates the absolute value of the relation.
Interpretation
When the dimension of the network is larger than 2 (nodes), it is often difficult to interpret the overall dynamics of the network as focus on any single pair of nodes may ignore other connections in the network. Therefore, we have developed new network metrics to examine how the network behaves. In particular we examine recovery time of each node, which describes how fast that variable will return to equilibrium (a stable state) after a perturbation in that node or any other node. We set a threshold for what is considered close-enough to equilibrium (threshold), and can evaluate the recovery times using a bootstrap approach that accommodates uncertainty in the model parameters.
Compute and Examine the Recovery Times Implied by the Estimated Network of Relations
#compute recovery time for all nodes
recovery_time <- iRAM(model.fit = usem_indiv,
beta = ms_indiv$beta,
var.number = 6,
lag.order = 1,
threshold = 0.01,
boot = TRUE,
replication = 200, steps = 100)
#examine mean across the recovery time of all node-pairs
recovery_time$mean## [,1] [,2] [,3] [,4] [,5] [,6]
## [1,] 4.545 4.665 4.815 4.625 5.66 9.240
## [2,] 0.000 3.275 0.000 0.000 0.00 0.000
## [3,] 0.000 0.000 4.440 0.000 0.00 0.000
## [4,] 0.000 4.015 0.000 4.195 0.00 0.000
## [5,] 0.000 0.000 0.000 0.000 7.14 0.000
## [6,] 0.000 0.000 0.000 0.000 0.00 14.455
The recovery times can also be plotted for easier interpretation.
Plot the Time-Profiles for When Each Node Gets a Perturbation (xupper controls length of time axis)
## NULL
Interpretation of the Recovery Time of Node-Pairs and the Structure of the Network
We can see most nodes have a recovery time of 3 ~ 4 steps, but node5 (“stress”) and node6 (“health”) have longer recovery times (7.1 and 14.5 time steps, respectively). Looking at the network graph, we see stronger self-loops for node5 and node6 (thickness of lines indicates size of auto-regression). These parameters indicate that there is lots of “carry-over” across observations and thus the length of time it takes this variable to return to equilibrium is extended. In this case, the interpretation is that “stress” and “health” operate at a slower time-scale than the “interpersonal behavior” and “affect” variables. This makes sense!
Further details of how recovery time is computed and interpreted can be found in the selected readings.
Looping to Fit Models for Many Persons
Now we can run the model in a loop for multiple participants. Let us try 5 participants…
Preparing and running loop.
#create list of ids
id_list <- unique(AMIB_interactionP2$id)
for (id in id_list[1:5]) # select the first 5 participants as examples
{
#select data for individual
data_indiv <- AMIB_interactionP2[AMIB_interactionP2$id == id,]
#standardize data for individual
data_indiv[c(4:9)] <- lapply(data_indiv[c(4:9)],
function(x) c(scale(x, center=TRUE, scale=TRUE)))
#indicate id
print(id)
# check column missing
na.col <- 0
for (col in 1:ncol(data_indiv))
{
if (sum(is.na(data_indiv[,col])) == nrow(data_indiv)){
na.col <- na.col + 1
}
}
#fit uSEM model
if (na.col == 0) # no NA column
{
usem_indiv <- uSEM(var.number = 6,
data = data_indiv[ ,c(4:9)],
lag.order = 1,
verbose = FALSE,
trim = FALSE)
ms_indiv <- model_summary(
model.fit = usem_indiv,
var.number = 6,
lag.order = 1)
print(sum(ms_indiv$cfi > .95,
ms_indiv$tli > .95,
ms_indiv$rmsea < .08,
ms_indiv$srmr < .08) >= 3)
plot_network_graph(ms_indiv$beta, var.number = 6)
}
}## [1] 203
## [1] TRUE
## [1] 204
## [1] TRUE
## [1] 205
## [1] TRUE
## [1] 208
## [1] TRUE
## [1] 211
## [1] TRUE
We see lots of heterogeneity in the structure of these 5 individuals’ temporal dynamics!
B. N = all model: multilevel vector autoregression model (mlVAR)
Now we turn to fitting of a multilevel VAR model.
The multilevel VAR is a group-level model, in contrast to the uSEM which is a person-specific model. Thus, multiple individuals are fit together in one model.
Describing the Data
## vars n mean sd median trimmed mad min max range skew
## id 1 4200 310.36 77.12 321 308.40 121.57 203 439 236 0.07
## day 2 4200 10.57 5.99 10 10.50 7.41 1 21 20 0.09
## interaction 3 4200 73.88 45.18 71 72.32 54.86 1 168 167 0.23
## igaff 4 4190 7.39 1.78 8 7.69 1.48 1 9 8 -1.43
## igdom 5 4190 6.92 1.62 7 7.08 1.48 1 9 8 -0.93
## agval 6 4189 6.80 2.09 7 7.08 2.22 1 9 8 -0.93
## agarous 7 4189 5.92 2.11 6 6.04 2.97 1 9 8 -0.51
## stress 8 4191 1.22 1.38 1 1.02 1.48 0 5 5 0.97
## health 9 4192 1.08 1.17 1 0.93 1.48 0 5 5 0.88
## kurtosis se
## id -1.21 1.19
## day -1.16 0.09
## interaction -1.00 0.70
## igaff 2.01 0.03
## igdom 0.91 0.02
## agval 0.13 0.03
## agarous -0.56 0.03
## stress 0.02 0.02
## health 0.00 0.02
From a multilevel perspective, the data are considered as 4200 observations nested within 30 persons that are considered as replicates drawn from a population.
Plotting Six-variate Time-series for All Persons
#plotting intraindividual change
AMIB_interactionP2 %>%
ggplot(aes(x = interaction, group= id)) +
#first variable
geom_line(aes(y=igaff), color=1) +
geom_line(aes(y=igdom), color=2) +
geom_line(aes(y=agval), color=3) +
geom_line(aes(y=agarous), color=4) +
geom_line(aes(y=stress), color=5) +
geom_line(aes(y=health), color=6) +
#plot layouts
scale_x_continuous(name="Interaction #") +
scale_y_continuous(name="Raw Values") +
theme_classic() +
theme(axis.title=element_text(size=10),
axis.text=element_text(size=10),
plot.title=element_text(size=12, hjust=.5)) +
facet_wrap(~id, ncol=2) +
ggtitle("AMIB Phase 2 Data (6 vars)")We see there is some difficulty in having so many persons with so much data =:-]
Not Standardizing the Data
For the mlVAR, the data are kept in their original form. The estimation package does some standardization, as well as separation of within-person and between-person components in the background. Importantly, the data are considered as stationary time-series that fluctuate around individuals’ mean-level.
Fitting the mlVAR model
In mlVAR syntax, we need to specify the dataset (data),
the specific variables included in the analysis (vars), the id variable
(idvar), the number of lags to examine (lags), and the time indices
(dayvar, beepvar). The two time variables are used to
accommodate unequal spacing in EMA studies where no observations are
obtained during the nighttime (e.g., the last evening beep is not
considered to be 1-lag away from the first morning beep).
Fitting the mlVAR model to all N = 30 time-series data:
#fitting mlVAR model
mlvar_all <- mlVAR(data = AMIB_interactionP2,
vars = c("igaff", "igdom", "agval", "agarous", "stress", "health"),
idvar = "id",
lags = 1,
dayvar = "day",
beepvar = "interaction")## | | | 0% | |============ | 17% | |======================= | 33% | |=================================== | 50% | |=============================================== | 67% | |========================================================== | 83% | |======================================================================| 100%
## | | | 0% | |============ | 17% | |======================= | 33% | |=================================== | 50% | |=============================================== | 67% | |========================================================== | 83% | |======================================================================| 100%
## | | | 0% | |== | 3% | |===== | 7% | |======= | 10% | |========= | 13% | |============ | 17% | |============== | 20% | |================ | 23% | |=================== | 27% | |===================== | 30% | |======================= | 33% | |========================== | 37% | |============================ | 40% | |============================== | 43% | |================================= | 47% | |=================================== | 50% | |===================================== | 53% | |======================================== | 57% | |========================================== | 60% | |============================================ | 63% | |=============================================== | 67% | |================================================= | 70% | |=================================================== | 73% | |====================================================== | 77% | |======================================================== | 80% | |========================================================== | 83% | |============================================================= | 87% | |=============================================================== | 90% | |================================================================= | 93% | |==================================================================== | 97% | |======================================================================| 100%
In the background the multivariate model is fit as a collection of
multilevel models (using lmer) and the outputs are combined
together to obtain the full set of multivariate within-person and
between-person relations. For these data, the estimation only took a
couple of minutes.
Examine the model summary.
##
## mlVAR estimation completed. Input was:
## - Variables: igaff igdom agval agarous stress health
## - Lags: 1
## - Estimator: lmer
## - Temporal: correlated
##
## Information indices:
## var aic bic
## igaff 9539.195 9792.416
## igdom 9603.567 9856.787
## agval 8805.919 9059.140
## agarous 8843.996 9097.217
## stress 6603.191 6856.411
## health 5759.345 6012.565
##
##
## Temporal effects:
## from to lag fixed SE P ran_SD
## igaff igaff 1 0.050 0.027 0.070 0.097
## igaff igdom 1 -0.019 0.023 0.417 0.060
## igaff agval 1 -0.009 0.020 0.661 0.044
## igaff agarous 1 -0.039 0.018 0.031 0.026
## igaff stress 1 0.017 0.020 0.394 0.075
## igaff health 1 0.027 0.014 0.049 0.037
## igdom igaff 1 -0.025 0.018 0.181 0.027
## igdom igdom 1 0.034 0.026 0.192 0.096
## igdom agval 1 -0.036 0.016 0.025 0.017
## igdom agarous 1 0.036 0.017 0.039 0.034
## igdom stress 1 0.026 0.012 0.028 0.015
## igdom health 1 0.006 0.012 0.596 0.028
## agval igaff 1 -0.006 0.025 0.815 0.060
## agval igdom 1 0.015 0.029 0.603 0.089
## agval agval 1 0.146 0.034 0.000 0.136
## agval agarous 1 0.026 0.022 0.246 0.042
## agval stress 1 0.029 0.017 0.086 0.041
## agval health 1 0.004 0.014 0.769 0.023
## agarous igaff 1 -0.008 0.029 0.769 0.115
## agarous igdom 1 0.058 0.026 0.028 0.094
## agarous agval 1 0.013 0.019 0.489 0.046
## agarous agarous 1 0.187 0.026 0.000 0.102
## agarous stress 1 -0.020 0.015 0.207 0.049
## agarous health 1 -0.004 0.014 0.767 0.044
## stress igaff 1 -0.067 0.023 0.004 0.023
## stress igdom 1 0.003 0.026 0.904 0.065
## stress agval 1 -0.174 0.032 0.000 0.124
## stress agarous 1 0.052 0.041 0.207 0.186
## stress stress 1 0.641 0.043 0.000 0.209
## stress health 1 0.048 0.018 0.008 0.061
## health igaff 1 -0.010 0.031 0.737 0.110
## health igdom 1 0.021 0.028 0.459 0.087
## health agval 1 -0.054 0.026 0.036 0.083
## health agarous 1 -0.084 0.026 0.001 0.083
## health stress 1 0.069 0.021 0.001 0.072
## health health 1 0.657 0.037 0.000 0.182
##
##
## Contemporaneous effects (posthoc estimated):
## v1 v2 P 1->2 P 1<-2 pcor ran_SD_pcor cor ran_SD_cor
## igdom igaff 0.000 0.000 0.184 0.175 0.250 0.211
## agval igaff 0.000 0.000 0.385 0.131 0.461 0.153
## agval igdom 0.014 0.086 0.057 0.081 0.167 0.140
## agarous igaff 0.206 0.073 0.041 0.074 0.102 0.100
## agarous igdom 0.000 0.000 0.227 0.080 0.248 0.103
## agarous agval 0.456 0.965 0.014 0.129 0.063 0.152
## stress igaff 0.002 0.036 -0.060 0.058 -0.239 0.145
## stress igdom 0.501 0.606 0.013 0.045 -0.059 0.091
## stress agval 0.000 0.000 -0.343 0.151 -0.426 0.174
## stress agarous 0.001 0.004 0.074 0.058 0.023 0.091
## health igaff 0.496 0.614 0.010 0.012 -0.099 0.119
## health igdom 0.655 0.622 -0.010 0.032 -0.063 0.057
## health agval 0.002 0.000 -0.090 0.068 -0.195 0.149
## health agarous 0.000 0.000 -0.105 0.062 -0.108 0.059
## health stress 0.000 0.000 0.188 0.209 0.244 0.222
##
##
## Between-subject effects:
## v1 v2 P 1->2 P 1<-2 pcor cor
## igdom igaff 0.053 0.012 0.320 0.420
## agval igaff 0.000 0.000 0.657 0.797
## agval igdom 0.201 0.333 -0.182 0.255
## agarous igaff 0.534 0.439 -0.027 0.327
## agarous igdom 0.000 0.013 0.472 0.532
## agarous agval 0.267 0.267 0.169 0.295
## stress igaff 0.511 0.456 0.106 -0.480
## stress igdom 0.583 0.776 0.071 -0.105
## stress agval 0.252 0.091 -0.223 -0.612
## stress agarous 0.741 0.778 0.050 -0.100
## health igaff 0.013 0.845 -0.172 -0.612
## health igdom 0.695 0.494 -0.090 -0.233
## health agval 0.361 0.252 -0.161 -0.679
## health agarous 0.886 0.651 0.022 -0.184
## health stress 0.000 0.000 0.640 0.780
We see some summary fit statistics, and all the matrices representing the different parts of the model.
Visualizing the mlVAR model
While the matrices above are extremely useful for understanding the model, network visualizations often facilitate interpretation - and have undoubtedly contributed to the quick uptake of this method.
Plot the Group-Level Networks for Within-Person and Between-Person Relations
# Plot temporal relations:
plot(mlvar_all, "temporal",
title = "Within-person temporal (lag-1) relations",
layout = "circle",
nonsig = "hide")# Plot contemporaneous partial correlations:
plot(mlvar_all, "contemporaneous",
title = "Within-person contemporaneous relations",
layout = "circle",
nonsig = "hide")# Plot between-persons partial correlations:
plot(mlvar_all, "between",
title = "Between-person relations",
layout = "circle",
nonsig = "hide")Interpretation
Temporal network (within-person lag-1 relations)
For the prototypical person, health and
stress have strong positive auto-regression, meaning they
tend to persist over time. stress also has a negative
forward influence on agval (affect valence), meaning when
stress is higher, affect valence goes lower.
Contemporaneous network (within-person contemporaneous relations)
For the prototypical person, many variables tend to move together, as
indicated by the number and thickness of the edges that exist in the
network. For example, igaff (interpersonal affiliation) and
agval (affect valence) tend to fluctuate together (green
positive edge), while stress and agval tend to
fluctuate in opposition to one another (red negative edge).
Between-person network (between-person relations)
Across persons, there are some variables covary. For example,
individuals with high average igaff (interpersonal
affiliation) also tend to have high average agval (affect
valence) (green positive edge) and low average health
(lower score is better health) (red negative edge).
Conclusion
This tutorial illustrates two different approaches for examining
multivariate dynamics - a person-specific (N = 1) network
approach based on the unified structural equation model (uSEM,
implemented in R using the pompom package); and a
group-based (N = all) network approach based on the multilevel
vector autoregression model (mlVAR, implemented in R using the
mlVAR package).
As we get the requisite data (long time-series), we look forward making use of these approaches, and understanding more about which approach is useful in which setting and for which research questions.
Thanks for being multivariate and dynamic as we all figure it out!
Citations
Bringmann, L. F., Vissers, N., Wichers, M., Geschwind, N., Kuppens, P., Peeters, F., Borsboom, D., & Tuerlinckx, F. (2013). A Network Approach to Psychopathology: New Insights into Clinical Longitudinal Data. PLOS ONE, 8(4), e60188. https://doi.org/10.1371/journal.pone.0060188
Epskamp, S., Deserno, M. K., & Bringmann, L. F. (2024). mlVAR: Multi-Level Vector Autoregression (Version 0.5.2) [Computer software]. https://CRAN.R-project.org/package=mlVAR
R Core Team. (2024). R: A Language and Environment for Statistical Computing. Foundation for Statistical Computing. https://www.R-project.org/
Ram, N., Conroy, D. E., Pincus, A. L., Hyde, A. L., & Molloy, L. E. (2012). Tethering theory to method: Using measures of intraindividual variability to operationalize individuals’ dynamic characteristics. In G. Hancock & J. Harring (Eds.), Advances in longitudinal methods in the social and behavioral sciences (pp. 81-110). New York: Information Age.
Revelle, W. (2024). psych: Procedures for Psychological, Psychometric, and Personality Research. Northwestern University. https://CRAN.R-project.org/package=psych
Wickham, H. (2016). ggplot2: Elegant Graphics for Data Analysis. Springer-Verlag. https://ggplot2.tidyverse.org/
Wickham, H., François, R., Henry, L., Müller, K., & Vaughan, D. (2023). dplyr: A Grammar of Data Manipulation (Version 1.1.4). https://CRAN.R-project.org/package=dplyr
Yang, X., Ram, N., Gest, S. D., Lydon-Staley, D. M., Conroy, D. E., Pincus, A. L., & Molenaar, P. C. M. (2018). Socioemotional Dynamics of Emotion Regulation and Depressive Symptoms: A Person-Specific Network Approach. Complexity, 2018(1), 5094179. https://doi.org/10.1155/2018/5094179
Yang, X., Ram, N., & Molenaar, P. C. M. (2021). pompom: Person-Oriented Method and Perturbation on the Model (Version 0.2.1). https://CRAN.R-project.org/package=pompom