Generalized NDR: associations, communities, and latent scores

What ndr() estimates

Generalized network-based dimensionality reduction has three linked stages:

  1. estimate or receive an association matrix;
  2. detect communities in the squared-association network;
  3. construct one standardized, centrality-weighted score per retained community.

Squaring lets community detection use relationship strength. The unsquared association is retained for interpretation: positive edges are green, negative edges are red, and absolute magnitude controls width. Community membership is encoded by node colour only; indicators use one common shape by default. This visual grammar remains feasible when a model contains many communities.

AssociationVariables or observations become nodes.
CommunityStrongly connected nodes form modules.
ScoreEach retained module defines one latent score.

Full, partial, and semipartial networks

The association method and conditioning type are independent choices. cor_method supports Pearson, Spearman, Kendall, distance, Gaussian-rank, and biweight associations. cor_type supports full, partial, and semipartial forms.

fit_full <- ndr(
  swiss, cor_method = "pearson", cor_type = "full",
  centrality = "pagerank", seed = 42
)
fit_partial <- ndr(
  swiss, cor_method = "pearson", cor_type = "partial",
  centrality = "pagerank", seed = 42
)
fit_semipartial <- ndr(
  swiss, cor_method = "pearson", cor_type = "semipartial",
  centrality = "authority", seed = 42
)

comparison <- data.frame(
  network = c("full", "partial", "semipartial"),
  factors = c(fit_full$factors, fit_partial$factors,
              fit_semipartial$factors),
  retained = c(sum(fit_full$membership > 0),
               sum(fit_partial$membership > 0),
               sum(fit_semipartial$membership > 0)),
  directed = c(fit_full$stats$directed,
               fit_partial$stats$directed,
               fit_semipartial$stats$directed)
)
comparison
#>       network factors retained directed
#> 1        full       1        6    FALSE
#> 2     partial       2        6    FALSE
#> 3 semipartial       2        6     TRUE

Partial association asks whether two indicators remain related after the others are controlled on both sides. Semipartial association controls one side and may be directed; hub and authority centralities can therefore answer different questions.

Inspecting communities and latent scores

The full Pearson fit provides a compact example of the fitted object.

fit_full
#> Generalized network-based dimensionality reduction
#> Call:
#> ndr(r = swiss, cor_method = "pearson", cor_type = "full", seed = 42, 
#>     centrality = "pagerank")
#> 
#> Factors: 1 | Observations: 47 | Modularity: 0 
#> Association: full pearson | Centrality: pagerank | Null model: none 
#> Community sizes: 6 
#> 
#> Loadings:
#>                        NDA1
#> Fertility         0.2349525
#> Agriculture      -0.0149876
#> Examination       0.2113338
#> Education         0.3749632
#> Catholic          0.4953636
#> Infant.Mortality  0.4135369
#> 
#> Communalities:
#>        Fertility      Agriculture      Examination        Education 
#>        0.0552027        0.0002246        0.0446620        0.1405974 
#>         Catholic Infant.Mortality 
#>        0.2453851        0.1710128
summary(fit_full)
#> Generalized network-based dimensionality reduction
#> Call:
#> ndr(r = swiss, cor_method = "pearson", cor_type = "full", seed = 42, 
#>     centrality = "pagerank")
#> 
#> Factors: 1 | Observations: 47 | Modularity: 0 
#> Association: full pearson | Centrality: pagerank | Null model: none 
#> Community sizes: 6 
#> 
#> Loadings:
#>                        NDA1
#> Fertility         0.2349525
#> Agriculture      -0.0149876
#> Examination       0.2113338
#> Education         0.3749632
#> Catholic          0.4953636
#> Infant.Mortality  0.4135369
#> 
#> Communalities:
#>        Fertility      Agriculture      Examination        Education 
#>        0.0552027        0.0002246        0.0446620        0.1405974 
#>         Catholic Infant.Mortality 
#>        0.2453851        0.1710128
fit_full$membership
#> [1] 1 1 1 1 1 1
round(fit_full$loadings, 3)
#>                    NDA1
#> Fertility         0.235
#> Agriculture      -0.015
#> Examination       0.211
#> Education         0.375
#> Catholic          0.495
#> Infant.Mortality  0.414
round(fit_full$communality, 3)
#>        Fertility      Agriculture      Examination        Education 
#>            0.055            0.000            0.045            0.141 
#>         Catholic Infant.Mortality 
#>            0.245            0.171
fit_full$stats$community_sizes
#> 
#> 1 
#> 6

membership identifies the score to which an indicator contributes. loadings connect indicators to the resulting scores; communality describes how well each indicator is represented. A zero membership means exclusion.

For a confirmatory illustration, a fixed two-community structure makes the network and biplot stable across community-detection backends.

visual_fit <- ndr(
  swiss,
  cor_method = "pearson",
  membership = c(1, 1, 2, 2, 2, 0),
  centrality = "eigenvector",
  seed = 42
)
data.frame(
  indicator = colnames(visual_fit$R),
  community = unname(visual_fit$membership)
)
#>          indicator community
#> 1        Fertility         1
#> 2      Agriculture         1
#> 3      Examination         2
#> 4        Education         2
#> 5         Catholic         2
#> 6 Infant.Mortality         0

Predicting new observations

new_scores <- predict(visual_fit, swiss[1:5, , drop = FALSE])
round(new_scores, 3)
#>                NDA1   NDA2
#> Courtelary   -0.412 -0.344
#> Delemont      0.482 -0.568
#> Franches-Mnt  0.795 -0.797
#> Moutier       0.383 -0.654
#> Neuveville    0.137 -0.056
identical(predict(visual_fit), visual_fit$scores)
#> [1] TRUE

Prediction reuses the training means, scales, indicator weights, centrality weights, latent centring, latent scaling, and rotation. Consequently, scores for new observations remain on the fitted model’s coordinate system.

Supplying an arbitrary matrix and clustering observations

With covar = TRUE, ndr() accepts a square matrix directly. This makes the method usable beyond correlation matrices. The example below follows the clustering use described in Kosztyán (2023): Euclidean distances between the standardized Swiss observations are converted to similarities.

scaled_swiss <- scale(swiss)
distance_matrix <- as.matrix(dist(scaled_swiss))
similarity_matrix <- 1 - normalize(distance_matrix)
diag(similarity_matrix) <- 1

cluster_fit <- ndr(
  similarity_matrix,
  covar = TRUE,
  min_comm = 2,
  centrality = "eigenvector",
  seed = 42
)
cluster_fit$factors
#> [1] 2
table(cluster_fit$membership)
#> 
#>  1  2 
#> 30 17
head(cluster_fit$membership, 10)
#>  [1] 1 2 2 2 1 2 2 2 2 2
is.null(cluster_fit$scores)
#> [1] TRUE

Here the nodes are observations rather than indicators. The returned membership is therefore an observation clustering. Since an arbitrary matrix contains no original row-level transformation, latent scores for new rows are not available in this mode.

cluster_network <- plot(
  cluster_fit,
  cuts = 0.55,
  interactive = FALSE,
  show_weights = FALSE,
  shape = "automatic",
  vertex.label.size = 7,
  layout = "fr"
)
cluster_network
Observation clusters obtained from a normalized Euclidean similarity matrix.

Observation clusters obtained from a normalized Euclidean similarity matrix.

Static network and biplot

static_network <- plot(
  visual_fit,
  cuts = 0.3,
  interactive = FALSE,
  show_weights = TRUE,
  shape = "automatic"
)
static_network
NDR association network: colour denotes community, edge colour denotes sign, and width denotes absolute association.

NDR association network: colour denotes community, edge colour denotes sign, and width denotes absolute association.

All observed indicators use the same shape. The two communities differ only by node colour. Solid green and red edges distinguish positive and negative associations; their thickness is scaled between the requested minimum and maximum widths.

score_biplot <- biplot(
  visual_fit,
  view_3D = FALSE,
  interactive = FALSE
)
score_biplot
Two-factor NDR biplot for the fixed Swiss-data communities.

Two-factor NDR biplot for the fixed Swiss-data communities.

Nearby observation points have similar score profiles. Loading arrows indicate the direction of increasing indicator values. The graph explains association structure; the biplot explains observations and indicators in latent-score space. Neither should be read as a causal model.

Inference, filtering, and weighting

The optional style controls can be demonstrated on the same fitted network. All observed indicators remain rectangles, and community uses colour only. Shapes are supplied in association-matrix column order.

custom_network <- plot(
  visual_fit, interactive = FALSE,
  shape = rep("rectangle", ncol(visual_fit$R)),
  positive.color = "#007A53", negative.color = "#B71C1C",
  positive.lty = 1, negative.lty = 1,
  edge.width.range = c(1, 5), show_weights = TRUE
)
custom_network
Explicit common node shape, custom signed colours, and bounded edge widths.

Explicit common node shape, custom signed colours, and bounded edge widths.

For a four-node graph, an individual shape vector could instead be c("circle", "circle", "square", "square"); shapes are not assigned by community. Optional positive.lty and negative.lty control line types. Both default to 1 (solid). Widths are scaled within the displayed graph; separate graphs require a common scale for direct width comparisons.

Association tests and bootstrap intervals can be executed on a small example without dominating build time. The low replicate count below illustrates the returned structure; final inference should use a larger n_boot.

inference_fit <- ndr(
  swiss,
  cor_method = "pearson",
  test = TRUE,
  p_adjust = "BH",
  alpha = 0.10,
  bootstrap = TRUE,
  n_boot = 30,
  conf = 0.90,
  seed = 42
)
round(inference_fit$correlation_p, 3)
#>                  Fertility Agriculture Examination Education Catholic
#> Fertility            0.000       0.022       0.000     0.000    0.002
#> Agriculture          0.022       0.000       0.000     0.000    0.009
#> Examination          0.000       0.000       0.000     0.000    0.000
#> Education            0.000       0.000       0.000     0.000    0.377
#> Catholic             0.002       0.009       0.000     0.377    0.000
#> Infant.Mortality     0.007       0.684       0.514     0.543    0.325
#>                  Infant.Mortality
#> Fertility                   0.007
#> Agriculture                 0.684
#> Examination                 0.514
#> Education                   0.543
#> Catholic                    0.325
#> Infant.Mortality            0.000
head(inference_fit$stats$bootstrap$lower)
#>                         NDA1
#> Fertility        -0.15056415
#> Agriculture      -0.32327584
#> Examination      -0.01199384
#> Education         0.23361287
#> Catholic          0.26218893
#> Infant.Mortality  0.03305719
head(inference_fit$stats$bootstrap$upper)
#>                       NDA1
#> Fertility        0.3687283
#> Agriculture      0.2347789
#> Examination      0.5330512
#> Education        0.6611118
#> Catholic         0.6178982
#> Infant.Mortality 0.5202130

The principal filtering controls are min_R, min_evalue, min_communality, com_communalities, and min_comm. The weight argument supplies one finite score weight per indicator. These filters act at different stages: network formation, centrality screening, representation, loading separation, and minimum module size.

Sparse storage and reproducible settings

sparse_fit <- ndr(
  swiss,
  min_R = 0.15,
  sparsecalc = TRUE,
  seed = 42
)
inherits(sparse_fit$R, "sparseMatrix")
#> [1] TRUE
sparse_fit$factors
#> [1] 2
sparse_fit$stats$community_sizes
#> 
#> 1 2 
#> 3 3

Sparse storage is helpful after thresholding a large network. Parallel workers mainly benefit pairwise distance association and bootstrap calculations; small Pearson examples usually run faster sequentially. A fixed seed makes the stochastic parts reproducible.

References

The cited literature covers the original NDA method, the generalized association-matrix formulation, the clustering interpretation, the software interface, and the supervised extension (Kosztyán et al. 2022, 2024; Kosztyán 2023; Kosztyán 2026b, 2026a).

Kosztyán, Zsolt T. 2026a. “Network-Based Structural Equation Models for Supervised Machine Learning Problems.” Unpublished manuscript.
Kosztyán, Zsolt T. 2026b. “R and MATLAB Packages for Network-Based Dimensionality Reduction Analysis.” Unpublished manuscript.
Kosztyán, Zsolt Tibor. 2023. “Hálózatalapú Modell- És Adatredukciós Módszer.” Statisztikai Szemle 101 (4): 289–324. https://doi.org/10.20311/stat2023.04.hu0289.
Kosztyán, Zsolt T., Attila I. Katona, Marcell T. Kurbucz, and Zoltán Lantos. 2024. “Generalized Network-Based Dimensionality Analysis.” Expert Systems with Applications 238: 121779. https://doi.org/10.1016/j.eswa.2023.121779.
Kosztyán, Zsolt T., Marcell T. Kurbucz, and Attila I. Katona. 2022. “Network-Based Dimensionality Reduction of High-Dimensional, Low-Sample-Size Datasets.” Knowledge-Based Systems 251: 109180. https://doi.org/10.1016/j.knosys.2022.109180.