Deeper Dives

EGA

EGA is the core function of the package: it estimates a network from your data and applies a community detection algorithm to recover the number of dimensions. This workflow looks at just that one step in isolation, and at a choice that’s easy to overlook — which community detection algorithm to use — using the Total Entropy Fit Index (tefi) to compare the result.

We’ll use the wmt2 dataset (introduced in Quick Start), a matrix reasoning test with a well-established two-dimensional structure.

# Load {EGAnet}
library(EGAnet)

# Obtain data
wmt <- wmt2[,7:24]

Walktrap

EGA’s default community detection algorithm is "walktrap", a random-walk method that tends to produce compact, conservative communities:

ega_walktrap <- EGA(
  data = wmt, algorithm = "walktrap",
  plot.EGA = FALSE # No plot for CRAN checks
)

# Print results
ega_walktrap
Model: GLASSO (EBIC with gamma = 0.5)
Correlations: auto
Lambda: 0.0648641196433721 (n = 100, ratio = 0.1)

Number of nodes: 18
Number of edges: 96
Edge density: 0.627

Non-zero edge weights: 
     M    SD    Min   Max
 0.082 0.060 -0.013 0.363

----

Algorithm:  Walktrap

Number of communities:  2

 wmt1  wmt2  wmt3  wmt4  wmt5  wmt6  wmt7  wmt8  wmt9 wmt10 wmt11 wmt12 wmt13 
    1     1     1     1     1     2     2     2     2     2     2     2     2 
wmt14 wmt15 wmt16 wmt17 wmt18 
    2     2     2     2     2 

----

Unidimensional Method: Louvain
Unidimensional: No

----

TEFI: -11.171

Spinglass

community.detection supports several other igraph algorithms passed along through EGA’s algorithm argument — among them "spinglass" (Reichardt & Bornholdt, 2006), a method based on statistical mechanics that can be more sensitive to smaller, weakly-separated clusters:

ega_spinglass <- EGA(
  data = wmt, algorithm = "spinglass",
  plot.EGA = FALSE # No plot for CRAN checks
)

# Print results
ega_spinglass
Model: GLASSO (EBIC with gamma = 0.5)
Correlations: auto
Lambda: 0.0648641196433721 (n = 100, ratio = 0.1)

Number of nodes: 18
Number of edges: 96
Edge density: 0.627

Non-zero edge weights: 
     M    SD    Min   Max
 0.082 0.060 -0.013 0.363

----

Algorithm:  Spinglass

Number of communities:  3

 wmt1  wmt2  wmt3  wmt4  wmt5  wmt6  wmt7  wmt8  wmt9 wmt10 wmt11 wmt12 wmt13 
    1     1     1     1     1     2     2     2     3     3     2     2     3 
wmt14 wmt15 wmt16 wmt17 wmt18 
    3     2     3     2     2 

----

Unidimensional Method: Louvain
Unidimensional: No

----

TEFI: -10.932

Comparing TEFI

Walktrap recovers two dimensions; spinglass splits the same items into four. Rather than argue over which looks right, we can compare how well each structure fits the data using tefi — lower (more negative) values indicate better fit:

# Walktrap TEFI
ega_walktrap$TEFI
[1] -11.17103
# Spinglass TEFI
ega_spinglass$TEFI
[1] -10.93215

Walktrap’s two-dimension solution has the lower TEFI (-11.17 vs. -10.93), meaning it’s the better-fitting structure of the two — despite spinglass finding more dimensions. This is a useful reminder: a community detection algorithm that fractures a network into additional communities isn’t automatically finding a more meaningful structure. More dimensions only help if they earn their keep in fit, which is exactly what tefi is for.

In practice, this is why EGA’s default pairs "walktrap" with a uni.method that itself defaults to "louvain" for the unidimensionality check — and why it’s worth comparing algorithms with tefi rather than assuming the default is always right for your data. When two algorithms disagree, tefi (or, across many structures at once, genTEFI for hierarchical/multi-level comparisons) gives you a principled way to adjudicate.

Reproducibility

That uni.method = "louvain" default is worth a closer look, because Louvain isn’t a deterministic algorithm: it processes nodes in a randomly shuffled order, and different orderings can settle into different communities. Called on its own, with no seed, community.unidimensional — the function behind EGA’s unidimensionality check — can genuinely disagree with itself from one call to the next. A single call won’t reliably show this (it might have to get unlucky to disagree), so here it is over 30 calls on the exact same data:

# Same data, no seed, thirty calls
table(sapply(1:30, function(i) community.unidimensional(wmt, verbose = FALSE)["wmt6"]))

 1  2 
 9 21 

wmt6 sits right on the boundary between the two empirical dimensions (it’s the first item of the second), so it’s exactly the kind of item a randomized node order can push back and forth — landing in one dimension some of the time and the other the rest, with nothing in the call itself to say which you’ll get. This isn’t a one-off: it’s the same item the bootEGA workflow independently flags as the least stable in the whole scale.

{EGAnet}’s own community detection routines are seeded internally with a reproducible generator (xoshiro256++, since version 2.5.0), and EGA and bootEGA both expose that through a seed argument. Setting one fixes the random node order — and everything downstream of it — for the entire call:

# Same data, same seed, six calls in a row
sapply(1:6, function(i) {
  EGA(wmt, algorithm = "louvain", plot.EGA = FALSE, verbose = FALSE, seed = 1)$n.dim
})
[1] 3 3 3 3 3 3

Every call agrees. If you need your own analysis — or someone else’s replication of it — to land on the exact same structure every time, seed is what guarantees that. It matters even more once you’re not running one EGA, but hundreds of them at once, which is exactly what bootEGA does; see the bootEGA workflow for what happens without it.