Extending EGA

Dynamic EGA

Most of {EGAnet} treats each row of data as one independent observation. dynEGA is built for a different kind of data: repeated measurements of the same variables over time, for the same people. It estimates change-based networks (via derivatives, using glla) at up to three levels — "population" (everyone pooled together), "group", and "individual" — and comparing across those levels is often the point, not a side detail.

We’ll use sim.dynEGA, a simulated dataset bundled with the package: 24 variables, 50 time points, for 100 individuals split into 2 groups.

# Load {EGAnet}
library(EGAnet)

dim(sim.dynEGA)
[1] 5000   26
table(sim.dynEGA$Group) / 50 # observations per person

 1  2 
50 50 

Population Structure

dyn_population <- dynEGA(
  data = sim.dynEGA, level = "population",
  seed = 1
)

dyn_population$dynEGA$population$n.dim
[1] 4
dyn_population$dynEGA$population$TEFI
[1] -19.08554

Pooling every person from both groups together, four dimensions emerge from the 24 variables’ derivatives.

Group Structure

dyn_group <- dynEGA(
  data = sim.dynEGA, level = "group",
  seed = 1
)

dyn_group$dynEGA$group[["1"]]$n.dim
[1] 2
dyn_group$dynEGA$group[["2"]]$n.dim
[1] 3

This is where it gets interesting: Group 1 resolves to two dimensions and Group 2 to three — neither of which matches the four-dimension structure found at the population level. Pooling the two groups together didn’t just average their structures, it produced a structure that belongs to neither one.

Individual Structure

The same check can be run person-by-person. Taking three people from each group as an illustration:

group1_people <- sim.dynEGA[sim.dynEGA$ID %in% 1:3, ]
group2_people <- sim.dynEGA[sim.dynEGA$ID %in% 51:53, ]

dyn_individuals <- dynEGA(
  data = rbind(group1_people, group2_people),
  level = "individual", seed = 1
)

sapply(dyn_individuals$dynEGA$individual, `[[`, "n.dim")
 1  2  3 51 52 53 
 2  2  2  3  3  3 

The six individuals sampled split cleanly along group lines: the three people from Group 1 each recover two dimensions, matching their group’s structure, and the three from Group 2 each recover three, matching theirs. Individually, everyone looks like their own group. It’s only the population-level structure — the one you’d get by ignoring group membership entirely — that fails to describe anyone.

Why This Matters

This is the same concern behind {EGAnet}’s ergodicity-related functions (ergoInfo, boot.ergoInfo): a structure estimated on pooled, cross-sectional-looking data is a statement about the average person, and there’s no guarantee it describes any actual person or subgroup well. When your data has repeated measurements and a plausible grouping variable, comparing dynEGA’s population, group, and individual levels against each other is a direct way to check whether that gap exists in your own data, rather than assuming it away.