netmem: Network Measures using Matrices

CRAN status r-universe status badge Lifecycle: stable Codecov test coverage CodeFactor R-CMD-check License: GPL v3

The goal of netmem is to make available different measures to analyse and manipulate complex networks using matrices.

🖊 Author/maintainer: Alejandro Espinosa-Rada

đŸ« Current: Institute of Sociology, Pontificia Universidad CatĂłlica de Chile

đŸ« Before: Social Networks Lab, ETH ZĂŒrich

Follow on Bluesky Follow on X

The package implements different measures to analyse and manipulate complex multilayer networks, from an ego-centric perspective, considering one-mode networks, valued ties (i.e. weighted or multiplex) or with multiple levels.

The package comes with three vignettes, listed in the articles of the website and available from R once netmem is installed:

vignette("netmem") # Getting started with netmem
vignette("distinctive") # What netmem adds
vignette("multilayer") # Multilayer networks

Citation

Espinosa-Rada A (2026). netmem: Social Network Measures using Matrices. R package version 1.1-0, https://github.com/anespinosa/netmem.

@Manual{,
  title = {netmem: Social Network Measures using Matrices},
  author = {Alejandro Espinosa-Rada},
  year = {2026},
  note = {R package version 1.1-0},
  url = {https://github.com/anespinosa/netmem},
}

Functions currently available in netmem:

Utilities:

  1. matrix_report(): Matrix report

  2. matrix_adjlist(): Transform a matrix into an adjacency list

  3. matrix_projection(): Unipartite projections

  4. matrix_to_edgelist(): Transform a square matrix into an edge-list

  5. adj_to_matrix(): Transform an adjacency list into a matrix

  6. adj_to_incidence(): Transform an adjacency matrix into a incidence matrix

  7. cumulativeSumMatrices(): Cumulative sum of matrices

  8. edgelist_to_matrix(): Transform an edgelist into a matrix

  9. expand_matrix(): Expand matrix

  10. extract_component(): Extract components

  11. hypergraph(): Hypergraphs

  12. perm_matrix(): Permutation matrix

  13. perm_label(): Permute labels of a matrix

  14. power_function(): Power of a matrix

  15. meta_matrix(): Meta matrix for multilevel networks

  16. supra_adjacency(): Supra-adjacency matrix of the layers of a multiplex network

  17. aggregate_layers(): Aggregation of the layers into a single matrix

  18. minmax_overlap(): Minimum/maximum overlap

  19. mix_matrix(): Mixing matrix

  20. simplicial_complexes(): Simplicial complexes

  21. structural_na(): Structural missing data

  22. ego_net(): Ego network

  23. zone_sample(): Zone-2 sampling from second-mode

Ego and personal networks:

  1. eb_constraint(): Constraint

  2. ei_index(): Krackhardt and Stern’s E-I index

  3. heterogeneity(): Blau’s and IQV index

  4. redundancy(): Redundancy measures

  5. structural_holes(): Effective size, efficiency and constraint of every node, with overlapping categories

  6. alter_composition(): Categories of the alters, which can overlap

  7. alter_heterogeneity(): Heterogeneity of the alters, with overlapping categories

  8. alter_homophily(): E-I index and Yule’s Q of every node, with overlapping categories

  9. brokerage_roles(): Gould and Fernandez brokerage roles, with overlapping categories

Path distances:

  1. bfs_ugraph(): Breath-first algorithm

  2. compound_relation(): Relational composition

  3. count_geodesics(): Count geodesic distances

  4. short_path(): Shortest path

  5. wlocal_distances(): Dijkstra’s algorithm (one actor)

  6. wall_distances(): Dijkstra’s algorithm (all actors)

  7. geo_distances(): Matrix of geodesic distances

  8. geo_summary(): Diameter, average distance and reachability

Signed networks:

  1. posneg_index(): Positive-negative centrality

  2. struc_balance(): Structural balance

  3. eigenvector_centrality(signed = TRUE): Status with negative relations

Structural measures:

  1. gen_density(): Generalized density

  2. recip_coef(): Reciprocity

  3. trans_coef(): Transitivity

  4. trans_matrix(): Transitivity matrix

  5. components_id(): Components

  6. k_core(): Generalized k-core

  7. dyadic_census(): Dyad census

  8. multiplex_census(): Multiplex triad census

  9. mixed_census(): Multilevel triad and quadrilateral census

  10. krackhardt_index(): Connectedness, hierarchy, efficiency and upper boundedness

  11. core_periphery(): Core-periphery structures

Cohesive subgroups:

  1. clique_table(): Clique table

  2. dyad_triad_table(): Forbidden triad table

  3. percolation_clique(): Clique percolation

  4. q_analysis(): Q-analysis

  5. shared_partners(): Shared partners

  6. clique_max(): Maximal cliques

Similarity measures:

  1. bonacich_norm(): Bonacich normalization

  2. co_occurrence(): Co‐occurrence

  3. dist_sim_matrix(): Structural similarities

  4. fractional_approach(): Fractional approach

  5. jaccard(): Jaccard similarity

Network inference:

  1. kp_reciprocity(): Reciprocity of Katz and Powell

  2. z_arctest(): Z test of the number of arcs

  3. triad_uman(): Triad census analysis assuming U|MAN

  4. ind_rand_matrix(): Independent random matrix

  5. cug_test(): Conditional uniform graph test

  6. qap_cor(): QAP correlation

  7. qap_lm(): MRQAP regression, linear and logistic

  8. small_world(): Watts-Strogatz networks

  9. pref_attachment(): Barabasi-Albert networks

Centrality:

  1. gen_degree(): Generalized degree

  2. multilevel_degree(): Degree centrality for multilevel networks

  3. closeness_centrality(): Closeness and harmonic closeness

  4. betweenness_centrality(): Betweenness

  5. eigenvector_centrality(): Eigenvector centrality

  6. katz_centrality(): Katz centrality

  7. bonacich_power(): Bonacich power centrality

  8. page_rank_centrality(): PageRank

  9. centrality_centralization(): Centralization of the network

  10. partition_centrality(): Contribution of each category to the centrality of every node

Positions and dominance:

  1. neigh_inclusion(): Neighbourhood-inclusion preorder

  2. dir_inclusion(): Directed neighbourhood-inclusion criteria

  3. pos_dominance(): Positional dominance on indirect relations

  4. indirect_rel(): Indirect relations between the nodes

  5. set_inclusion(): Inclusion of neighbourhoods

  6. pareto_dominance(): Dominance across several relations

  7. hyperevent_dominance(): Dominance through citation chains

  8. dominance_pairs(): Comparable and incomparable pairs

  9. dominance_layers(): Layers and status of a dominance relation

  10. dominance_ranks(): Rank intervals

  11. preserved_order(): Whether a centrality preserves a dominance relation

Roles and positions:

  1. block_density(): Block densities and image matrix

  2. concor(): CONCOR

  3. rege(): Regular equivalence

Communities:

  1. leiden(): Leiden and Louvain communities

  2. leading_eigen(): Leading eigenvector communities

  3. community_greedy(): Agglomerative modularity

  4. community_label(): Label propagation

  5. community_betweenness(): Girvan-Newman edge betweenness

  6. modularity_score(): Modularity, including LinkRank

Segregation and homophily:

  1. segregation(): Assortativity, Gupta-Anderson-May, odds ratio, Coleman and Freeman

Social influence and diffusion:

  1. social_influence(): Assimilation, bounded confidence, repulsion and Friedkin-Johnsen

  2. threshold_diffusion(): Threshold models of diffusion

Citation networks:

  1. main_path(): Main path analysis

  2. traversal_weights(): Search path counts

  3. citation_decay(): Temporal decay of citations

  4. dag_check(): Directed acyclic graphs

  5. main_path_diag(): Diagnostics of the main path

Geographic information:

  1. dist_geographic(): Geographical distances

  2. spatial_cor(): Spatial autocorrelation

Data currently available:

  1. FIFAego: Ego FIFA

  2. FIFAex: Outside FIFA

  3. FIFAin: Inside FIFA

  4. krackhardt_friends: Krackhardt friends

  5. lazega_lawfirm: Lazega Law Firm

  6. campnet: Camp 92 network

Additional data in classicnets: Classic Data of Social Networks


Scope

The functions work on matrices, which keeps the code close to the algebra of the measures and makes them easy to read and to check. The results are compared with igraph, sna, netrankr and netseg in the validation scripts of the repository. The package is meant for the networks that are usually collected by hand, up to a few hundred nodes; for larger networks the compiled routines of igraph are orders of magnitude faster.


Quick overview of netmem: Network Measures using Matrices


Installation

From CRAN:

# install.packages("netmem")
library(netmem)

You can install the development version from GitHub with:

### OPTION 1
# install.packages("devtools")
devtools::install_github("anespinosa/netmem")

### OPTION 2
options(repos = c(
  netmem = "https://anespinosa.r-universe.dev",
  CRAN = "https://cloud.r-project.org"
))
install.packages("netmem")

Multilevel Networks

Connections between individuals are often embedded in complex structures, which shape actors’ expectations, behaviours and outcomes over time. These structures can themselves be interdependent and exist at different levels. Multilevel networks are a means by which we can represent this complex system by using nodes and edges of different types. Check this book edited by Emmanuel Lazega and Tom A.B. Snijders or this book edited by David Knoke, Mario Diani, James Hollway and Dimitris Christopoulos.

For multilevel structures, we tend to collect the data in different matrices representing the variation of ties within and between levels. Often, we describe the connection between actors as an adjacency matrix and the relations between levels through incidence matrices. The comfortable combination of these matrices into a common structure would represent the multilevel network that could be highly complex.

Example

Let’s assume that we have a multilevel network with two adjacency matrices, one valued matrix and two incidence matrices between them.

Create the data

A1 <- matrix(c(
  0, 1, 0, 0, 1,
  1, 0, 0, 1, 1,
  0, 0, 0, 1, 1,
  0, 1, 1, 0, 1,
  1, 1, 1, 1, 0
), byrow = TRUE, ncol = 5)

B1 <- matrix(c(
  1, 0, 0,
  1, 1, 0,
  0, 1, 0,
  0, 1, 0,
  0, 1, 1
), byrow = TRUE, ncol = 3)

A2 <- matrix(c(
  0, 1, 1,
  1, 0, 0,
  1, 0, 0
), byrow = TRUE, nrow = 3)

B2 <- matrix(c(
  1, 1, 0, 0,
  0, 0, 1, 0,
  0, 0, 1, 1
), byrow = TRUE, ncol = 4)

A3 <- matrix(c(
  0, 1, 3, 1,
  1, 0, 0, 0,
  3, 0, 0, 5,
  1, 0, 5, 0
), byrow = TRUE, ncol = 4)

We will start with a report of the matrices:

matrix_report(A1)
#> The matrix A might have the following characteristics:
#> --> The vectors of the matrix are `numeric`
#> --> No names assigned to the rows of the matrix
#> --> No names assigned to the columns of the matrix
#> --> Matrix is symmetric (network is undirected)
#> --> The matrix is square, 5 by 5
#>      nodes edges
#> [1,]     5     7
matrix_report(B1)
#> The matrix A might have the following characteristics:
#> --> The vectors of the matrix are `numeric`
#> --> No names assigned to the rows of the matrix
#> --> No names assigned to the columns of the matrix
#> --> The matrix is rectangular, 3 by 5
#>      nodes_rows nodes_columns incidence_lines
#> [1,]          3             5               7
matrix_report(A2)
#> The matrix A might have the following characteristics:
#> --> The vectors of the matrix are `numeric`
#> --> No names assigned to the rows of the matrix
#> --> No names assigned to the columns of the matrix
#> --> Matrix is symmetric (network is undirected)
#> --> The matrix is square, 3 by 3
#>      nodes edges
#> [1,]     3     2
matrix_report(B2)
#> The matrix A might have the following characteristics:
#> --> The vectors of the matrix are `numeric`
#> --> No names assigned to the rows of the matrix
#> --> No names assigned to the columns of the matrix
#> --> The matrix is rectangular, 4 by 3
#>      nodes_rows nodes_columns incidence_lines
#> [1,]          4             3               5
matrix_report(A3)
#> The matrix A might have the following characteristics:
#> --> The vectors of the matrix are `numeric`
#> --> No names assigned to the rows of the matrix
#> --> No names assigned to the columns of the matrix
#> --> Valued matrix
#> --> Matrix is symmetric (network is undirected)
#> --> The matrix is square, 4 by 4
#>      nodes edges
#> [1,]     4    10

What is the density of some of the matrices?

matrices <- list(A1, B1, A2, B2)
gen_density(matrices, multilayer = TRUE)
#> $`Density of matrix [[1]]`
#> [1] 0.7
#> 
#> $`Density of matrix [[2]]`
#> [1] 0.4666667
#> 
#> $`Density of matrix [[3]]`
#> [1] 0.6666667
#> 
#> $`Density of matrix [[4]]`
#> [1] 0.4166667

How about the degree centrality of the entire structure?

multilevel_degree(A1, B1, A2, B2, complete = TRUE)
#>    multilevel bipartiteB1 bipartiteB2 tripartiteB1B2 low_multilevel
#> n1          3           1          NA              1              3
#> n2          5           2          NA              2              5
#> n3          3           1          NA              1              3
#> n4          4           1          NA              1              4
#> n5          6           2          NA              2              6
#> m1          6           2           2              4              4
#> m2          6           4           1              5              5
#> m3          4           1           2              3              3
#> k1          1          NA           1              1              1
#> k2          1          NA           1              1              1
#> k3          2          NA           2              2              2
#> k4          1          NA           1              1              1
#>    meso_multilevel high_multilevel
#> n1               1               1
#> n2               2               2
#> n3               1               1
#> n4               1               1
#> n5               2               2
#> m1               6               4
#> m2               6               5
#> m3               4               3
#> k1               1               1
#> k2               1               1
#> k3               2               2
#> k4               1               1

Besides, we can perform a k-core analysis of one of the levels using the information of an incidence matrix

k_core(A1, B1, multilevel = TRUE)
#> [1] 3 3 3 3 3

This package also allows performing complex census for multilevel networks.

mixed_census(A2, t(B1), B2, quad = TRUE)
#>   000   100   001   010   020   200  11D0  11U0   120   210   220   002  01D1 
#>     2     6     1     0     0     2     0     0     4     0     1     1     0 
#>  01U1   012   021   022  101N  101P   201   102   202 11D1W 11U1P 11D1P 11U1W 
#>     0     0     8     0     3     0     1     3     1     0     0     0     0 
#>  121W  121P  21D1  21U1  11D2  11U2   221   122   212   222 
#>    11    13     0     0     0     0     3     0     0     0

Ego measures

When we are interested in one particular actor, we could perform different network measures. For example, actor e has connections with all the other actors in the network. Therefore, we could estimate some of Ronald Burt’s measures.

# First we will assign names to the matrix
rownames(A1) <- letters[1:nrow(A1)]
colnames(A1) <- letters[1:ncol(A1)]

eb_constraint(A1, ego = "e")
#> $results
#>   term1 term2 term3 constraint normalization
#> e  0.25 0.292 0.101      0.642         0.761
#> 
#> $maximum
#>     e 
#> 0.766
redundancy(A1, ego = "e")
#> $redundancy
#> [1] 1.5
#> 
#> $effective_size
#> [1] 2.5
#> 
#> $efficiency
#> [1] 0.625

Also, sometimes we might want to subset a group of actors surrounding an ego.

ego_net(A1, ego = "e")
#>   a b c d
#> a 0 1 0 0
#> b 1 0 0 1
#> c 0 0 0 1
#> d 0 1 1 0

One-mode network

This package expand some measures for one-mode networks, such as the generalized degree centrality. Suppose we consider a valued matrix A3. If alpha=0 then it would only count the direct connections. But, adding the tuning parameter alpha=0.5 would determine the relative importance of the number of ties compared to tie weights.

gen_degree(A3, digraph = FALSE, weighted = TRUE)
#> [1] 3.872983 1.000000 4.000000 3.464102

Also, we could conduct some exploratory analysis using the normalized degree of an incidence matrix.

gen_degree(B1, bipartite = TRUE, normalized = TRUE)
#> $bipartiteL1
#> [1] 0.3333333 0.6666667 0.3333333 0.3333333 0.6666667
#> 
#> $bipartiteL2
#> [1] 0.4 0.8 0.2

This package also implements some analysis of dyads.

# dyad census
dyadic_census(A1)
#>      Mutual Asymmetrics       Nulls 
#>           7           0           3

# Katz and Powell reciprocity
kp_reciprocity(A1)
#> [1] 1

# Z test of the number of arcs
z_arctest(A1)
#>     z     p 
#> 1.789 0.074

We can also check the triad census assuming conditional uniform distribution considering different types of dyads (U|MAN)

triad_uman(A1)
#>    label OBS   EXP   VAR   STD
#> 1    003   0 0.083 0.076 0.276
#> 2    012   0 0.000 0.000 0.000
#> 3    102   2 1.750 0.688 0.829
#> 4   021D   0 0.000 0.000 0.000
#> 5   021U   0 0.000 0.000 0.000
#> 6   021C   0 0.000 0.000 0.000
#> 7   111D   0 0.000 0.000 0.000
#> 8   111U   0 0.000 0.000 0.000
#> 9   030T   0 0.000 0.000 0.000
#> 10  030C   0 0.000 0.000 0.000
#> 11   201   5 5.250 1.688 1.299
#> 12  120D   0 0.000 0.000 0.000
#> 13  120U   0 0.000 0.000 0.000
#> 14  120C   0 0.000 0.000 0.000
#> 15   210   0 0.000 0.000 0.000
#> 16   300   3 2.917 0.410 0.640

Code of conduct

Please note that this project is released with a Contributor Code of Conduct. By participating in this project you agree to abide by its terms.


To-do list

# library(todor)
# todor::todor_package(c("TODO", "FIXME"))

mirror server hosted at Truenetwork, Russian Federation.