Computes four prevalence-weighted structural indices for every node in a modality-level network: gravitational mass (MGI+), orbital drag (MGI-), net gravity (dMGI), and orbital score (OS). These indices extend standard centrality measures by incorporating the empirical prevalence of each modality, allowing direction-sensitive identification of attractor and satellite modalities.
Arguments
- x
A
catmodgraphobject as returned bybuild_modality_graphorprune_modality_edges. The object must contain a$dataslot with the original data frame from which prevalences are computed.- weight_attr
Character. Name of the edge attribute to use as association weight. Defaults to
"weight"(absolute phi / Cramer's V stored bybuild_modality_graph).- min_prevalence
Numeric in (0, 1). Modalities with prevalence below this value are retained in the output but their prevalence-ratio contributions are flagged. Default
0.01(1%).
Value
A data frame with one row per modality node and columns:
- node
Full node label in
variable=modalityformat.- variable
Variable name (left of
=).- modality
Modality label (right of
=).- prevalence
Empirical relative frequency computed from
x$data, ignoringNAs.- degree
Number of edges incident to the node.
- strength
Weighted degree: sum of incident edge weights.
- mgi_plus
MGI+: sum of \(w_{ij} \cdot p_i/p_j\) over neighbours \(j\) with \(p_j < p_i\).
- mgi_minus
MGI-: sum of \(w_{ij} \cdot p_i/p_j\) over neighbours \(j\) with \(p_j > p_i\).
- delta_mgi
Net gravity:
mgi_plus - mgi_minus. Positive = net attractor; negative = net satellite.- mgi_plus_norm
MGI+ normalised to \([0, 1]\) within the graph, for cross-graph comparisons.
- os
Orbital Score: sum of \(w_{ij} \cdot p_j/p_i\) over all neighbours. High OS indicates strong gravitational capture.
- role
Character:
"attractor"ifdelta_mgi > 0,"satellite"ifdelta_mgi < 0,"neutral"ifdelta_mgi == 0(isolated nodes or perfectly balanced).
Rows are ordered by delta_mgi descending (strongest attractors
first).
Details
Prevalence computation. Prevalences are computed from
x$data as \(n_{ij} / n_j\) where \(n_{ij}\) is the number of
non-missing observations of variable \(j\) taking value \(i\), and
\(n_j\) is the total non-missing count for that variable. Each variable
is normalised independently, so prevalences sum to 1 within each variable.
Relationship to standard centrality.
When all nodes in the graph have equal prevalence, \(p_i/p_j = 1\) for
every edge, and mgi_plus + mgi_minus equals weighted degree
(strength). delta_mgi is then determined solely by whether a
node's neighbours are uniformly more or less prevalent, which is
uninformative. The metric is most useful when prevalences vary
substantially across modalities.
Edge weights. The function takes the absolute value of edge
weights before computing ratios so that signed phi values (stored for
the modality graph) do not cancel positive and negative contributions.
The sign of the association is a separate dimension captured in
std_resid; delta_mgi captures prevalence-weighted
directional dominance.
Examples
data(survey_health)
mg <- build_modality_graph(survey_health)
mg <- prune_modality_edges(mg, min_weight = 0.10, max_p = 0.05)
grav <- modality_gravity(mg)
print(grav)
#>
#> === Modality Gravity Index ===
#> (22 nodes: 12 attractors, 2 neutral, 8 satellites)
#>
#> ATTRACTORS [dMGI > 0]
#> Node Prev MGI+ MGI- dMGI OS
#> ---------------------------------------------------------------------------------------------
#> lung_disease=no 0.855 1.958 0.000 1.958 0.329
#> smoking_status=never 0.469 1.630 0.173 1.458 0.935
#> health_insurance=yes 0.783 1.291 0.000 1.291 0.198
#> age_group=18-34 0.379 1.502 0.316 1.186 1.595
#> bmi_category=normal 0.434 0.988 0.000 0.988 0.508
#> exercise_freq=low 0.352 0.940 0.360 0.580 1.098
#> smoking_status=current 0.257 0.579 0.161 0.418 1.451
#> sex=female 0.514 0.378 0.000 0.378 0.136
#> sex=male 0.486 0.358 0.000 0.358 0.144
#> exercise_freq=moderate 0.364 0.328 0.000 0.328 0.197
#> diet_quality=good 0.337 0.362 0.119 0.242 0.398
#> smoking_status=former 0.274 0.280 0.181 0.099 0.559
#>
#> NEUTRAL [dMGI = 0]
#> Node Prev MGI+ MGI- dMGI OS
#> ---------------------------------------------------------------------------------------------
#> bmi_category=underweight 0.022 0.000 0.000 0.000 0.000
#> bmi_category=overweight 0.319 0.000 0.000 0.000 0.000
#>
#> SATELLITES [dMGI < 0]
#> Node Prev MGI+ MGI- dMGI OS
#> ---------------------------------------------------------------------------------------------
#> bmi_category=obese 0.224 0.000 0.508 -0.508 1.112
#> age_group=55+ 0.239 0.232 0.739 -0.507 2.403
#> health_insurance=no 0.217 0.000 0.358 -0.358 0.714
#> lung_disease=yes 0.145 0.000 0.331 -0.331 1.945
#> diet_quality=poor 0.312 0.160 0.286 -0.126 0.524
#> diet_quality=fair 0.352 0.000 0.122 -0.122 0.131
#> age_group=35-54 0.382 0.159 0.182 -0.023 0.418
#> exercise_freq=high 0.284 0.381 0.382 -0.001 0.950
#>
#> Columns: Prev = prevalence MGI+ = gravitational mass MGI- = orbital drag dMGI = net gravity OS = orbital score
# Top attractors
head(grav[grav$role == "attractor", ], 5)
#>
#> === Modality Gravity Index ===
#> (5 nodes: 5 attractors, 0 neutral, 0 satellites)
#>
#> ATTRACTORS [dMGI > 0]
#> Node Prev MGI+ MGI- dMGI OS
#> ---------------------------------------------------------------------------------------------
#> lung_disease=no 0.855 1.958 0.000 1.958 0.329
#> smoking_status=never 0.469 1.630 0.173 1.458 0.935
#> health_insurance=yes 0.783 1.291 0.000 1.291 0.198
#> age_group=18-34 0.379 1.502 0.316 1.186 1.595
#> bmi_category=normal 0.434 0.988 0.000 0.988 0.508
#>
#> Columns: Prev = prevalence MGI+ = gravitational mass MGI- = orbital drag dMGI = net gravity OS = orbital score
# Top satellites (highest orbital score)
head(grav[order(-grav$os), ], 5)
#>
#> === Modality Gravity Index ===
#> (5 nodes: 2 attractors, 0 neutral, 3 satellites)
#>
#> ATTRACTORS [dMGI > 0]
#> Node Prev MGI+ MGI- dMGI OS
#> ---------------------------------------------------------------------------------------------
#> age_group=18-34 0.379 1.502 0.316 1.186 1.595
#> smoking_status=current 0.257 0.579 0.161 0.418 1.451
#>
#> SATELLITES [dMGI < 0]
#> Node Prev MGI+ MGI- dMGI OS
#> ---------------------------------------------------------------------------------------------
#> bmi_category=obese 0.224 0.000 0.508 -0.508 1.112
#> age_group=55+ 0.239 0.232 0.739 -0.507 2.403
#> lung_disease=yes 0.145 0.000 0.331 -0.331 1.945
#>
#> Columns: Prev = prevalence MGI+ = gravitational mass MGI- = orbital drag dMGI = net gravity OS = orbital score