From a6d42cf8268886fc7281ef0a90ca0ca5eb2edf03 Mon Sep 17 00:00:00 2001 From: James Hollway Date: Thu, 19 Mar 2026 16:51:48 +0100 Subject: [PATCH 01/35] Fixed cat() call in net_by_scalefree() and enabled it to test power law fit beyond igraph algorithm --- R/measure_features.R | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/R/measure_features.R b/R/measure_features.R index 703531d..6248a2d 100644 --- a/R/measure_features.R +++ b/R/measure_features.R @@ -343,12 +343,12 @@ net_by_smallworld <- function(.data, net_by_scalefree <- function(.data){ .data <- manynet::expect_nodes(.data) out <- igraph::fit_power_law(node_by_deg(.data)) - if ("KS.p" %in% names(out)) { - if(out$KS.p < 0.05) - cat(paste("Note: Kolgomorov-Smirnov test that data", - "could have been drawn from a power-law", - "distribution rejected.\n")) - } + if (!"KS.p" %in% names(out)) out$KS.p <- ks.test(seq(0, 1 - out$KS.stat, + length.out = manynet::net_nodes(.data)), + "punif")$p.value + if(out$KS.p < 0.05) + snet_info("Note: Kolgomorov-Smirnov test that data could have been drawn", + "from a power-law distribution rejected.") make_network_measure(out$alpha, .data, call = deparse(sys.call())) } From f2b96e5353bc210d3d29322963c5cffd781cd5e1 Mon Sep 17 00:00:00 2001 From: James Hollway Date: Thu, 19 Mar 2026 16:52:02 +0100 Subject: [PATCH 02/35] #patch bump --- DESCRIPTION | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/DESCRIPTION b/DESCRIPTION index 5c8f140..aa64097 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,7 +1,7 @@ Package: netrics Title: Many Ways to Measure and Classify Membership for Networks, Nodes, and Ties -Version: 0.1.0 -Date: 2026-03-15 +Version: 0.1.1 +Date: 2026-03-19 Description: Many tools for calculating network, node, or tie marks, measures, motifs and memberships of many different types of networks. Marks identify structural positions, measures quantify network properties, From 57c4a928132a0844c3516e6b75977bb4afca2e51 Mon Sep 17 00:00:00 2001 From: James Hollway Date: Fri, 20 Mar 2026 21:16:13 +0100 Subject: [PATCH 03/35] Fixed startup messages --- R/zzz.R | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/R/zzz.R b/R/zzz.R index 6d5b5b0..634a480 100644 --- a/R/zzz.R +++ b/R/zzz.R @@ -23,14 +23,14 @@ # "i" = "To suppress package startup messages, use: `suppressPackageStartupMessages(library({.pkg netrics}))`.", # "i" = "Changing the theme of all your graphs is straightforward with `set_manynet_theme()`", # "i" = "If too many messages appear in the console, run `options(snet_verbosity = 'quiet')`", - "i" = "Explore the changes since the last version with {.code news(package = 'netrics')}.", + "i" = "Explore changes since the last version with {.code news(package = 'netrics')}.", "i" = "Visit the website to learn more: {.url https://stocnet.github.io/netrics/}.", "i" = "The 'Function Overview' may suggest new analytic opportunities: {.url https://stocnet.github.io/netrics/reference/index.html}." # "i" = "Discover {.emph stocnet} R packages at {.url https://github.com/stocnet/}." # "i" = "Star me at {.url https://github.com/users/follow?target=jhollway}.", # "i" = "You can list all the tutorials available in {.pkg netrics} using {.fn run_tute}, and run them too!" ) - manynet::snet_info(sample(tips, 1), class = "packageStartupMessage") + manynet::snet_info(sample(tips, 1)) } if (interactive()) { From c1580f7d2ea2a58d8bcfe80cb65864a4a1fa327e Mon Sep 17 00:00:00 2001 From: James Hollway Date: Fri, 20 Mar 2026 21:18:37 +0100 Subject: [PATCH 04/35] Added node_mark roxygen template --- R/mark_nodes.R | 155 +++++++++++++++++++--------------------- man-roxygen/node_mark.R | 6 ++ man/mark_diff.Rd | 10 +-- man/mark_nodes.Rd | 10 +-- man/mark_select.Rd | 20 ++++-- 5 files changed, 106 insertions(+), 95 deletions(-) create mode 100644 man-roxygen/node_mark.R diff --git a/R/mark_nodes.R b/R/mark_nodes.R index 730647e..d944bc3 100644 --- a/R/mark_nodes.R +++ b/R/mark_nodes.R @@ -1,76 +1,6 @@ -# Degree properties #### - -#' Marking nodes based on degree properties -#' -#' @description -#' These functions return logical vectors the length of the -#' nodes in a network identifying which hold certain properties or positions in the network. -#' -#' - `node_is_isolate()` marks nodes that are isolates, -#' with neither incoming nor outgoing ties. -#' - `node_is_pendant()` marks nodes that are pendants, -#' with exactly one incoming or outgoing tie. -#' - `node_is_universal()` identifies whether nodes are adjacent to all other -#' nodes in the network. -#' @param .data A network object of class `mnet`, `igraph`, `tbl_graph`, `network`, or similar. -#' For more information on the standard coercion possible, -#' see [manynet::as_tidygraph()]. -#' @family marks -#' @family degree -#' @name mark_degree -NULL - -#' @rdname mark_degree -#' @examples -#' node_is_isolate(ison_brandes) -#' @export -node_is_isolate <- function(.data){ - .data <- manynet::expect_nodes(.data) - mat <- abs(manynet::as_matrix(.data)) - if(manynet::is_twomode(.data)){ - out <- c(rowSums(mat)==0, colSums(mat)==0) - } else { - out <- rowSums(mat)==0 & colSums(mat)==0 - } - names(out) <- manynet::node_names(.data) - make_node_mark(out, .data) -} - -#' @rdname mark_degree -#' @export -node_is_pendant <- function(.data){ - .data <- manynet::expect_nodes(.data) - mat <- abs(manynet::as_matrix(.data)) - if(manynet::is_twomode(.data)){ - out <- c(rowSums(mat)==1, colSums(mat)==1) - } else { - out <- rowSums(mat)==1 & colSums(mat)==1 - } - make_node_mark(out, .data) -} - -#' @rdname mark_degree -#' @section Universal/dominating node: -#' A universal node is adjacent to all other nodes in the network. -#' It is also sometimes called the dominating vertex because it represents -#' a one-element dominating set. -#' A network with a universal node is called a cone, and its universal node -#' is called the apex of the cone. -#' A classic example of a cone is a star graph, -#' but friendship, wheel, and threshold graphs are also cones. -#' @examples -#' node_is_universal(create_star(11)) -#' @export -node_is_universal <- function(.data){ - .data <- manynet::expect_nodes(.data) - net <- manynet::to_undirected(manynet::to_unweighted(.data)) - make_node_mark(node_by_deg(net)==(manynet::net_nodes(net)-1), .data) -} - # Structural properties #### #' Marking nodes based on structural properties -#' #' @description #' These functions return logical vectors the length of the #' nodes in a network identifying which hold certain properties or positions in the network. @@ -83,10 +13,7 @@ node_is_universal <- function(.data){ #' triangles that are only connected by that node. #' - `node_is_mentor()` marks a proportion of high indegree nodes as 'mentors' (see details). #' - `node_is_neighbor()` marks nodes that are neighbours of a given node. -#' @param .data A network object of class `mnet`, `igraph`, `tbl_graph`, `network`, or similar. -#' For more information on the standard coercion possible, -#' see [manynet::as_tidygraph()]. -#' @family marks +#' @template node_mark #' @name mark_nodes NULL @@ -219,6 +146,74 @@ node_is_neighbor <- function(.data, node){ make_node_mark(out, .data) } +# Degree properties #### + +#' Marking nodes based on degree properties +#' +#' @description +#' These functions return logical vectors the length of the +#' nodes in a network identifying which hold certain properties or positions in the network. +#' +#' - `node_is_isolate()` marks nodes that are isolates, +#' with neither incoming nor outgoing ties. +#' - `node_is_pendant()` marks nodes that are pendants, +#' with exactly one incoming or outgoing tie. +#' - `node_is_universal()` identifies whether nodes are adjacent to all other +#' nodes in the network. +#' @param .data A network object of class `mnet`, `igraph`, `tbl_graph`, `network`, or similar. +#' For more information on what coercions are possible, see [manynet::as_tidygraph()]. +#' @template node_mark +#' @family degree +#' @name mark_degree +NULL + +#' @rdname mark_degree +#' @examples +#' node_is_isolate(ison_brandes) +#' @export +node_is_isolate <- function(.data){ + .data <- manynet::expect_nodes(.data) + mat <- abs(manynet::as_matrix(.data)) + if(manynet::is_twomode(.data)){ + out <- c(rowSums(mat)==0, colSums(mat)==0) + } else { + out <- rowSums(mat)==0 & colSums(mat)==0 + } + names(out) <- manynet::node_names(.data) + make_node_mark(out, .data) +} + +#' @rdname mark_degree +#' @export +node_is_pendant <- function(.data){ + .data <- manynet::expect_nodes(.data) + mat <- abs(manynet::as_matrix(.data)) + if(manynet::is_twomode(.data)){ + out <- c(rowSums(mat)==1, colSums(mat)==1) + } else { + out <- rowSums(mat)==1 & colSums(mat)==1 + } + make_node_mark(out, .data) +} + +#' @rdname mark_degree +#' @section Universal/dominating node: +#' A universal node is adjacent to all other nodes in the network. +#' It is also sometimes called the dominating vertex because it represents +#' a one-element dominating set. +#' A network with a universal node is called a cone, and its universal node +#' is called the apex of the cone. +#' A classic example of a cone is a star graph, +#' but friendship, wheel, and threshold graphs are also cones. +#' @examples +#' node_is_universal(create_star(11)) +#' @export +node_is_universal <- function(.data){ + .data <- manynet::expect_nodes(.data) + net <- manynet::to_undirected(manynet::to_unweighted(.data)) + make_node_mark(node_by_deg(net)==(manynet::net_nodes(net)-1), .data) +} + # Diffusion properties #### #' Marking nodes based on diffusion properties @@ -232,7 +227,7 @@ node_is_neighbor <- function(.data, node){ #' - `node_is_latent()` marks nodes that are latent at a particular time point. #' - `node_is_recovered()` marks nodes that are recovered at a particular time point. #' @inheritParams mark_nodes -#' @family marks +#' @template node_mark #' @family diffusion #' @name mark_diff NULL @@ -406,7 +401,6 @@ node_is_exposed <- function(.data, mark, time = 0){ # Selection properties #### #' Marking nodes based on measures -#' #' @description #' These functions return logical vectors the length of the #' nodes in a network identifying which hold certain properties or positions in the network. @@ -417,7 +411,8 @@ node_is_exposed <- function(.data, mark, time = 0){ #' They can be particularly useful for highlighting which node or nodes #' are key because they minimise or, more often, maximise some measure. #' @inheritParams mark_nodes -#' @family marks +#' @template node_mark +#' @family selection #' @name mark_select NULL @@ -442,7 +437,7 @@ node_is_random <- function(.data, size = 1){ #' three scores. #' By default, `ranks = 1`. #' @examples -#' #node_is_max(node_by_degree(ison_brandes)) +#' node_is_max(node_by_degree(ison_brandes)) #' @export node_is_max <- function(node_measure, ranks = 1){ if(!inherits(node_measure, "node_measure")) @@ -468,7 +463,7 @@ node_is_max <- function(node_measure, ranks = 1){ #' @rdname mark_select #' @examples -#' #node_is_min(node_by_degree(ison_brandes)) +#' node_is_min(node_by_degree(ison_brandes)) #' @export node_is_min <- function(node_measure, ranks = 1){ if(!inherits(node_measure, "node_measure")) @@ -494,7 +489,7 @@ node_is_min <- function(node_measure, ranks = 1){ #' @rdname mark_select #' @examples -#' #node_is_mean(node_degree(ison_brandes)) +#' node_is_mean(node_degree(ison_brandes)) #' @export node_is_mean <- function(node_measure, ranks = 1){ if(!inherits(node_measure, "node_measure")) diff --git a/man-roxygen/node_mark.R b/man-roxygen/node_mark.R new file mode 100644 index 0000000..74b4422 --- /dev/null +++ b/man-roxygen/node_mark.R @@ -0,0 +1,6 @@ +#' @template data +#' @family marks +#' @returns +#' A `node_mark` logical vector the length of the nodes in the network, +#' giving either TRUE or FALSE for each node depending on +#' whether the condition is matched. diff --git a/man/mark_diff.Rd b/man/mark_diff.Rd index 2f18f47..135cc71 100644 --- a/man/mark_diff.Rd +++ b/man/mark_diff.Rd @@ -17,14 +17,15 @@ node_is_recovered(.data, time = 0) node_is_exposed(.data, mark, time = 0) } \arguments{ -\item{.data}{A network object of class \code{mnet}, \code{igraph}, \code{tbl_graph}, \code{network}, or similar. -For more information on the standard coercion possible, -see \code{\link[manynet:manip_as]{manynet::as_tidygraph()}}.} - \item{time}{A time step at which nodes are identified.} \item{mark}{vector denoting which nodes are infected} } +\value{ +A \code{node_mark} logical vector the length of the nodes in the network, +giving either TRUE or FALSE for each node depending on +whether the condition is matched. +} \description{ These functions return logical vectors the length of the nodes in a network identifying which hold certain properties or positions in the network. @@ -61,6 +62,7 @@ in that diffusion. \seealso{ Other marks: \code{\link{mark_degree}}, +\code{\link{mark_dyads}}, \code{\link{mark_nodes}}, \code{\link{mark_select}}, \code{\link{mark_tie_select}}, diff --git a/man/mark_nodes.Rd b/man/mark_nodes.Rd index e878af7..194b49e 100644 --- a/man/mark_nodes.Rd +++ b/man/mark_nodes.Rd @@ -20,10 +20,6 @@ node_is_mentor(.data, elites = 0.1) node_is_neighbor(.data, node) } \arguments{ -\item{.data}{A network object of class \code{mnet}, \code{igraph}, \code{tbl_graph}, \code{network}, or similar. -For more information on the standard coercion possible, -see \code{\link[manynet:manip_as]{manynet::as_tidygraph()}}.} - \item{elites}{The proportion of nodes to be selected as mentors. By default this is set at 0.1. This means that the top 10\% of nodes in terms of degree, @@ -40,6 +36,11 @@ described in Valente and Davis (1999).} \item{node}{A node ID or name for which neighbors are to be marked.} } +\value{ +A \code{node_mark} logical vector the length of the nodes in the network, +giving either TRUE or FALSE for each node depending on +whether the condition is matched. +} \description{ These functions return logical vectors the length of the nodes in a network identifying which hold certain properties or positions in the network. @@ -95,6 +96,7 @@ Valente, Thomas, and Rebecca Davis. 1999. Other marks: \code{\link{mark_degree}}, \code{\link{mark_diff}}, +\code{\link{mark_dyads}}, \code{\link{mark_select}}, \code{\link{mark_tie_select}}, \code{\link{mark_ties}}, diff --git a/man/mark_select.Rd b/man/mark_select.Rd index c629763..8261de8 100644 --- a/man/mark_select.Rd +++ b/man/mark_select.Rd @@ -17,10 +17,6 @@ node_is_min(node_measure, ranks = 1) node_is_mean(node_measure, ranks = 1) } \arguments{ -\item{.data}{A network object of class \code{mnet}, \code{igraph}, \code{tbl_graph}, \code{network}, or similar. -For more information on the standard coercion possible, -see \code{\link[manynet:manip_as]{manynet::as_tidygraph()}}.} - \item{size}{The number of nodes to select (as TRUE).} \item{node_measure}{An object created by a \code{node_} measure.} @@ -31,6 +27,11 @@ scores equal to any of the top (or, for \code{node_is_min()}, bottom) three scores. By default, \code{ranks = 1}.} } +\value{ +A \code{node_mark} logical vector the length of the nodes in the network, +giving either TRUE or FALSE for each node depending on +whether the condition is matched. +} \description{ These functions return logical vectors the length of the nodes in a network identifying which hold certain properties or positions in the network. @@ -44,17 +45,22 @@ are key because they minimise or, more often, maximise some measure. } \examples{ node_is_random(ison_brandes, 2) -#node_is_max(node_by_degree(ison_brandes)) -#node_is_min(node_by_degree(ison_brandes)) -#node_is_mean(node_degree(ison_brandes)) +node_is_max(node_by_degree(ison_brandes)) +node_is_min(node_by_degree(ison_brandes)) +node_is_mean(node_degree(ison_brandes)) } \seealso{ Other marks: \code{\link{mark_degree}}, \code{\link{mark_diff}}, +\code{\link{mark_dyads}}, \code{\link{mark_nodes}}, \code{\link{mark_tie_select}}, \code{\link{mark_ties}}, \code{\link{mark_triangles}} + +Other selection: +\code{\link{mark_tie_select}} } \concept{marks} +\concept{selection} From 5181e9bd5554906ad5ab7dbece3fe3dd64ad6628 Mon Sep 17 00:00:00 2001 From: James Hollway Date: Fri, 20 Mar 2026 21:19:15 +0100 Subject: [PATCH 05/35] Added tie_mark roxygen template --- R/mark_ties.R | 86 +++++++++++++++++++++++------------------- man-roxygen/tie_mark.R | 5 +++ man/mark_degree.Rd | 9 ++++- man/mark_dyads.Rd | 48 +++++++++++++++++++++++ man/mark_tie_select.Rd | 16 ++++++-- man/mark_ties.Rd | 17 +++------ man/mark_triangles.Rd | 11 +++--- 7 files changed, 131 insertions(+), 61 deletions(-) create mode 100644 man-roxygen/tie_mark.R create mode 100644 man/mark_dyads.Rd diff --git a/R/mark_ties.R b/R/mark_ties.R index d237656..61da8a9 100644 --- a/R/mark_ties.R +++ b/R/mark_ties.R @@ -1,35 +1,22 @@ # Structural properties #### #' Marking ties based on structural properties -#' #' @description #' These functions return logical vectors the length of the ties #' in a network identifying which hold certain properties or positions in the network. #' -#' - `tie_is_multiple()` marks ties that are multiples. #' - `tie_is_loop()` marks ties that are loops. -#' - `tie_is_reciprocated()` marks ties that are mutual/reciprocated. #' - `tie_is_feedback()` marks ties that are feedback arcs causing the network to not be acyclic. #' - `tie_is_bridge()` marks ties that cut or act as articulation points in a network. #' - `tie_is_path()` marks ties on a path from one node to another. #' #' They are most useful in highlighting parts of the network that #' are particularly well- or poorly-connected. -#' @inheritParams mark_nodes -#' @family marks +#' @template param_data +#' @template tie_mark #' @name mark_ties NULL -#' @rdname mark_ties -#' @importFrom igraph which_multiple -#' @examples -#' tie_is_multiple(fict_marvel) -#' @export -tie_is_multiple <- function(.data){ - .data <- manynet::expect_ties(.data) - make_tie_mark(igraph::which_multiple(manynet::as_igraph(.data)), .data) -} - #' @rdname mark_ties #' @importFrom igraph which_loop #' @examples @@ -40,16 +27,6 @@ tie_is_loop <- function(.data){ make_tie_mark(igraph::which_loop(manynet::as_igraph(.data)), .data) } -#' @rdname mark_ties -#' @importFrom igraph which_mutual -#' @examples -#' tie_is_reciprocated(ison_algebra) -#' @export -tie_is_reciprocated <- function(.data){ - .data <- manynet::expect_ties(.data) - make_tie_mark(igraph::which_mutual(manynet::as_igraph(.data)), .data) -} - #' @rdname mark_ties #' @importFrom igraph feedback_arc_set #' @examples @@ -87,7 +64,6 @@ tie_is_bridge <- function(.data){ #' @examples #' ison_adolescents %>% #' mutate_ties(route = tie_is_path(from = "Jane", to = 7)) -#' #graphr(edge_colour = "route") #' @export tie_is_path <- function(.data, from, to, all_paths = FALSE){ .data <- manynet::expect_ties(.data) @@ -99,6 +75,44 @@ tie_is_path <- function(.data, from, to, all_paths = FALSE){ make_tie_mark(out, .data) } +# Dyadic properties #### + +#' Marking ties based on dyadic properties +#' +#' @description +#' These functions return logical vectors the length of the ties +#' in a network identifying which are embedded within particular dyads. +#' +#' - `tie_is_multiple()` marks ties that are multiples. +#' - `tie_is_reciprocated()` marks ties that are mutual/reciprocated. +#' +#' They are most useful in highlighting parts of the network where +#' relationships are denser. +#' @template param_data +#' @template tie_mark +#' @name mark_dyads +NULL + +#' @rdname mark_dyads +#' @importFrom igraph which_multiple +#' @examples +#' tie_is_multiple(fict_marvel) +#' @export +tie_is_multiple <- function(.data){ + .data <- manynet::expect_ties(.data) + make_tie_mark(igraph::which_multiple(manynet::as_igraph(.data)), .data) +} + +#' @rdname mark_dyads +#' @importFrom igraph which_mutual +#' @examples +#' tie_is_reciprocated(ison_algebra) +#' @export +tie_is_reciprocated <- function(.data){ + .data <- manynet::expect_ties(.data) + make_tie_mark(igraph::which_mutual(manynet::as_igraph(.data)), .data) +} + # Triangular properties #### #' Marking ties based on triangular properties @@ -118,8 +132,8 @@ tie_is_path <- function(.data, from, to, all_paths = FALSE){ #' #' They are most useful in highlighting parts of the network that #' are cohesively connected. -#' @inheritParams mark_nodes -#' @family marks +#' @template param_data +#' @template tie_mark #' @family cohesion #' @name mark_triangles NULL @@ -129,7 +143,6 @@ NULL #' @examples #' ison_monks %>% to_uniplex("like") %>% #' mutate_ties(tri = tie_is_triangular()) -#' #graphr(edge_color = "tri") #' @export tie_is_triangular <- function(.data){ .data <- manynet::expect_ties(.data) @@ -150,7 +163,6 @@ tie_is_triangular <- function(.data){ #' @examples #' ison_adolescents %>% to_directed() %>% #' mutate_ties(trans = tie_is_transitive()) -#' #graphr(edge_color = "trans") #' @export tie_is_transitive <- function(.data){ .data <- manynet::expect_ties(.data) @@ -167,7 +179,6 @@ tie_is_transitive <- function(.data){ #' @examples #' ison_adolescents %>% to_directed() %>% #' mutate_ties(trip = tie_is_triplet()) -#' #graphr(edge_color = "trip") #' @export tie_is_triplet <- function(.data){ .data <- manynet::expect_ties(.data) @@ -189,7 +200,6 @@ tie_is_triplet <- function(.data){ #' @examples #' ison_adolescents %>% to_directed() %>% #' mutate_ties(cyc = tie_is_cyclical()) -#' #graphr(edge_color = "cyc") #' @export tie_is_cyclical <- function(.data){ .data <- manynet::expect_ties(.data) @@ -206,7 +216,6 @@ tie_is_cyclical <- function(.data){ #' @examples #' ison_monks %>% to_uniplex("like") %>% #' mutate_ties(simmel = tie_is_simmelian()) -#' #graphr(edge_color = "simmel") #' @export tie_is_simmelian <- function(.data){ .data <- manynet::expect_ties(.data) @@ -222,7 +231,6 @@ tie_is_simmelian <- function(.data){ # #' @examples # #' generate_random(8, directed = TRUE) %>% # #' mutate_ties(forbid = tie_is_forbidden()) -# #' #graphr(edge_color = "forbid") # #' @export # tie_is_forbidden <- function(.data){ # .data <- manynet::expect_ties(.data) @@ -316,7 +324,6 @@ tie_is_imbalanced <- function(.data){ # Selection properties #### #' Marking ties based on measures -#' #' @description #' These functions return logical vectors the length of the ties in a network: #' @@ -325,8 +332,9 @@ tie_is_imbalanced <- function(.data){ #' for converting the results from some tie measure into a mark-class object. #' They can be particularly useful for highlighting which tie or ties #' are key because they minimise or, more often, maximise some measure. -#' @inheritParams mark_select -#' @family marks +#' @template param_data +#' @template tie_mark +#' @family selection #' @name mark_tie_select NULL @@ -343,7 +351,7 @@ tie_is_random <- function(.data, size = 1){ #' @rdname mark_tie_select #' @param tie_measure An object created by a `tie_` measure. #' @examples -#' # tie_is_max(tie_by_betweenness(ison_brandes)) +#' tie_is_max(tie_by_betweenness(ison_brandes)) #' @export tie_is_max <- function(tie_measure){ out <- as.numeric(tie_measure) == max(as.numeric(tie_measure)) @@ -353,7 +361,7 @@ tie_is_max <- function(tie_measure){ #' @rdname mark_tie_select #' @examples -#' #tie_is_min(tie_by_betweenness(ison_brandes)) +#' tie_is_min(tie_by_betweenness(ison_brandes)) #' @export tie_is_min <- function(tie_measure){ out <- as.numeric(tie_measure) == min(as.numeric(tie_measure)) diff --git a/man-roxygen/tie_mark.R b/man-roxygen/tie_mark.R new file mode 100644 index 0000000..8c75b0a --- /dev/null +++ b/man-roxygen/tie_mark.R @@ -0,0 +1,5 @@ +#' @family marks +#' @returns +#' A `tie_mark` logical vector the length of the ties in the network, +#' giving either TRUE or FALSE for each tie depending on +#' whether the condition is matched. diff --git a/man/mark_degree.Rd b/man/mark_degree.Rd index d19c5a3..2938978 100644 --- a/man/mark_degree.Rd +++ b/man/mark_degree.Rd @@ -15,8 +15,12 @@ node_is_universal(.data) } \arguments{ \item{.data}{A network object of class \code{mnet}, \code{igraph}, \code{tbl_graph}, \code{network}, or similar. -For more information on the standard coercion possible, -see \code{\link[manynet:manip_as]{manynet::as_tidygraph()}}.} +For more information on what coercions are possible, see \code{\link[manynet:manip_as]{manynet::as_tidygraph()}}.} +} +\value{ +A \code{node_mark} logical vector the length of the nodes in the network, +giving either TRUE or FALSE for each node depending on +whether the condition is matched. } \description{ These functions return logical vectors the length of the @@ -48,6 +52,7 @@ node_is_universal(create_star(11)) \seealso{ Other marks: \code{\link{mark_diff}}, +\code{\link{mark_dyads}}, \code{\link{mark_nodes}}, \code{\link{mark_select}}, \code{\link{mark_tie_select}}, diff --git a/man/mark_dyads.Rd b/man/mark_dyads.Rd new file mode 100644 index 0000000..c5b9723 --- /dev/null +++ b/man/mark_dyads.Rd @@ -0,0 +1,48 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/mark_ties.R +\name{mark_dyads} +\alias{mark_dyads} +\alias{tie_is_multiple} +\alias{tie_is_reciprocated} +\title{Marking ties based on dyadic properties} +\usage{ +tie_is_multiple(.data) + +tie_is_reciprocated(.data) +} +\arguments{ +\item{.data}{A network object of class \code{mnet}, \code{igraph}, \code{tbl_graph}, \code{network}, or similar. +For more information on the standard coercion possible, +see \code{\link[manynet:manip_as]{manynet::as_tidygraph()}}.} +} +\value{ +A \code{tie_mark} logical vector the length of the ties in the network, +giving either TRUE or FALSE for each tie depending on +whether the condition is matched. +} +\description{ +These functions return logical vectors the length of the ties +in a network identifying which are embedded within particular dyads. +\itemize{ +\item \code{tie_is_multiple()} marks ties that are multiples. +\item \code{tie_is_reciprocated()} marks ties that are mutual/reciprocated. +} + +They are most useful in highlighting parts of the network where +relationships are denser. +} +\examples{ +tie_is_multiple(fict_marvel) +tie_is_reciprocated(ison_algebra) +} +\seealso{ +Other marks: +\code{\link{mark_degree}}, +\code{\link{mark_diff}}, +\code{\link{mark_nodes}}, +\code{\link{mark_select}}, +\code{\link{mark_tie_select}}, +\code{\link{mark_ties}}, +\code{\link{mark_triangles}} +} +\concept{marks} diff --git a/man/mark_tie_select.Rd b/man/mark_tie_select.Rd index debb95e..d9ce0d1 100644 --- a/man/mark_tie_select.Rd +++ b/man/mark_tie_select.Rd @@ -18,10 +18,13 @@ tie_is_min(tie_measure) For more information on the standard coercion possible, see \code{\link[manynet:manip_as]{manynet::as_tidygraph()}}.} -\item{size}{The number of nodes to select (as TRUE).} - \item{tie_measure}{An object created by a \code{tie_} measure.} } +\value{ +A \code{tie_mark} logical vector the length of the ties in the network, +giving either TRUE or FALSE for each tie depending on +whether the condition is matched. +} \description{ These functions return logical vectors the length of the ties in a network: \itemize{ @@ -33,16 +36,21 @@ are key because they minimise or, more often, maximise some measure. } } \examples{ -# tie_is_max(tie_by_betweenness(ison_brandes)) -#tie_is_min(tie_by_betweenness(ison_brandes)) +tie_is_max(tie_by_betweenness(ison_brandes)) +tie_is_min(tie_by_betweenness(ison_brandes)) } \seealso{ Other marks: \code{\link{mark_degree}}, \code{\link{mark_diff}}, +\code{\link{mark_dyads}}, \code{\link{mark_nodes}}, \code{\link{mark_select}}, \code{\link{mark_ties}}, \code{\link{mark_triangles}} + +Other selection: +\code{\link{mark_select}} } \concept{marks} +\concept{selection} diff --git a/man/mark_ties.Rd b/man/mark_ties.Rd index c064e58..e11c055 100644 --- a/man/mark_ties.Rd +++ b/man/mark_ties.Rd @@ -2,20 +2,14 @@ % Please edit documentation in R/mark_ties.R \name{mark_ties} \alias{mark_ties} -\alias{tie_is_multiple} \alias{tie_is_loop} -\alias{tie_is_reciprocated} \alias{tie_is_feedback} \alias{tie_is_bridge} \alias{tie_is_path} \title{Marking ties based on structural properties} \usage{ -tie_is_multiple(.data) - tie_is_loop(.data) -tie_is_reciprocated(.data) - tie_is_feedback(.data) tie_is_bridge(.data) @@ -34,13 +28,16 @@ see \code{\link[manynet:manip_as]{manynet::as_tidygraph()}}.} \item{all_paths}{Whether to return a list of paths or sample just one. By default FALSE, sampling just a single path.} } +\value{ +A \code{tie_mark} logical vector the length of the ties in the network, +giving either TRUE or FALSE for each tie depending on +whether the condition is matched. +} \description{ These functions return logical vectors the length of the ties in a network identifying which hold certain properties or positions in the network. \itemize{ -\item \code{tie_is_multiple()} marks ties that are multiples. \item \code{tie_is_loop()} marks ties that are loops. -\item \code{tie_is_reciprocated()} marks ties that are mutual/reciprocated. \item \code{tie_is_feedback()} marks ties that are feedback arcs causing the network to not be acyclic. \item \code{tie_is_bridge()} marks ties that cut or act as articulation points in a network. \item \code{tie_is_path()} marks ties on a path from one node to another. @@ -50,19 +47,17 @@ They are most useful in highlighting parts of the network that are particularly well- or poorly-connected. } \examples{ -tie_is_multiple(fict_marvel) tie_is_loop(fict_marvel) -tie_is_reciprocated(ison_algebra) tie_is_feedback(ison_algebra) tie_is_bridge(ison_brandes) ison_adolescents \%>\% mutate_ties(route = tie_is_path(from = "Jane", to = 7)) - #graphr(edge_colour = "route") } \seealso{ Other marks: \code{\link{mark_degree}}, \code{\link{mark_diff}}, +\code{\link{mark_dyads}}, \code{\link{mark_nodes}}, \code{\link{mark_select}}, \code{\link{mark_tie_select}}, diff --git a/man/mark_triangles.Rd b/man/mark_triangles.Rd index 8a1ef60..660b370 100644 --- a/man/mark_triangles.Rd +++ b/man/mark_triangles.Rd @@ -27,6 +27,11 @@ tie_is_imbalanced(.data) For more information on the standard coercion possible, see \code{\link[manynet:manip_as]{manynet::as_tidygraph()}}.} } +\value{ +A \code{tie_mark} logical vector the length of the ties in the network, +giving either TRUE or FALSE for each tie depending on +whether the condition is matched. +} \description{ These functions return logical vectors the length of the ties in a network identifying which hold certain properties or positions in the network. @@ -46,25 +51,21 @@ are cohesively connected. \examples{ ison_monks \%>\% to_uniplex("like") \%>\% mutate_ties(tri = tie_is_triangular()) - #graphr(edge_color = "tri") ison_adolescents \%>\% to_directed() \%>\% mutate_ties(trans = tie_is_transitive()) - #graphr(edge_color = "trans") ison_adolescents \%>\% to_directed() \%>\% mutate_ties(trip = tie_is_triplet()) - #graphr(edge_color = "trip") ison_adolescents \%>\% to_directed() \%>\% mutate_ties(cyc = tie_is_cyclical()) - #graphr(edge_color = "cyc") ison_monks \%>\% to_uniplex("like") \%>\% mutate_ties(simmel = tie_is_simmelian()) - #graphr(edge_color = "simmel") fict_marvel \%>\% to_uniplex("relationship") \%>\% tie_is_imbalanced() } \seealso{ Other marks: \code{\link{mark_degree}}, \code{\link{mark_diff}}, +\code{\link{mark_dyads}}, \code{\link{mark_nodes}}, \code{\link{mark_select}}, \code{\link{mark_tie_select}}, From be828105216fba13a85a1dac218f87f6f6b7f85a Mon Sep 17 00:00:00 2001 From: James Hollway Date: Fri, 20 Mar 2026 21:20:52 +0100 Subject: [PATCH 06/35] Added gap method for cluster k-selection, renamed some arguments to be clearer about inheritance and avoid base function conflicts --- R/{model_k.R => method_k.R} | 123 ++++++++++++++++++++++++++++++++---- man/method_kselect.Rd | 107 +++++++++++++++++++++++++++++++ man/model_kselect.Rd | 59 ----------------- 3 files changed, 217 insertions(+), 72 deletions(-) rename R/{model_k.R => method_k.R} (50%) create mode 100644 man/method_kselect.Rd delete mode 100644 man/model_kselect.Rd diff --git a/R/model_k.R b/R/method_k.R similarity index 50% rename from R/model_k.R rename to R/method_k.R index cd49b59..a71e70e 100644 --- a/R/model_k.R +++ b/R/method_k.R @@ -1,6 +1,8 @@ #' Methods for selecting clusters #' #' @description +#' Finding the optimal number of clusters is generally a balance between +#' optimal fit statistics, parsimony, and interpretability. #' These functions help select the number of clusters to return from `hc`, #' some hierarchical clustering object: #' @@ -9,17 +11,27 @@ #' - `k_elbow()` selects a number of clusters in which there is #' a fair trade-off between parsimony and fit according to the elbow method. #' - `k_silhouette()` selects a number of clusters that -#' optimises the silhouette score. +#' maximises the silhouette score. #' #' These functions are generally not user-facing but used internally #' in e.g. the `*_equivalence()` functions. #' #' @inheritParams mark_nodes #' @param hc A hierarchical clustering object. -#' @name model_kselect +#' @returns +#' A single integer indicating the number of clusters to return. +#' @name method_kselect NULL -#' @rdname model_kselect +#' @rdname method_kselect +#' @section Strict method: +#' The strict method selects the number of clusters in which there is no +#' distance between cluster members. +#' This is a very conservative method that may be appropriate when the goal is +#' to identify clusters of nodes that are exactly the same. +#' However, it may not be appropriate in cases where the data is noisy or +#' when the clusters are not well-defined, +#' as it may result in a large number of small clusters. #' @export k_strict <- function(hc, .data){ zero_merged <- hc$merge[round(hc$height,4) == 0,] @@ -27,10 +39,19 @@ k_strict <- function(hc, .data){ k } -#' @rdname model_kselect -#' @param census A motif census object. -#' @param range An integer indicating the maximum number of options to consider. +#' @rdname method_kselect +#' @param motif A motif census object. +#' @param Kmax An integer indicating the maximum number of options to consider. #' The minimum of this and the number of nodes in the network is used. +#' @section Elbow method: +#' The elbow method is a heuristic used in cluster analysis to determine the optimal number of clusters. +#' It is based on the idea of plotting the within cluster correlation +#' as a function of the number of clusters and looking for an "elbow" +#' where there is a significant decrease in the rate of improvement in +#' correlation as the number of clusters increases. +#' The point at which the elbow occurs is often considered a good choice for +#' the number of clusters, as it represents a balance between +#' model complexity and fit to the data. #' @references #' ## On the elbow method #' Thorndike, Robert L. 1953. @@ -38,7 +59,7 @@ k_strict <- function(hc, .data){ #' _Psychometrika_, 18(4): 267–76. #' \doi{10.1007/BF02289263}. #' @export -k_elbow <- function(hc, .data, census, range){ +k_elbow <- function(hc, .data, motif, Kmax){ thisRequires("sna") @@ -82,11 +103,11 @@ k_elbow <- function(hc, .data, census, range){ } vertices <- manynet::net_nodes(.data) - observedcorrelation <- cor(t(census)) + observedcorrelation <- cor(t(motif)) resultlist <- list() correlations <- vector() - for (i in 2:min(range, vertices)) { + for (i in 2:min(Kmax, vertices)) { cluster_result <- list(label = NA, clusters = NA, correlation = NA) cluster_result$label <- paste("number of clusters: ", i) @@ -100,7 +121,7 @@ k_elbow <- function(hc, .data, census, range){ } resultlist$correlations <- c(correlations) - dafr <- data.frame(clusters = 2:min(range, vertices), + dafr <- data.frame(clusters = 2:min(Kmax, vertices), correlations = c(correlations)) correct <- NULL # to satisfy the error god @@ -108,7 +129,25 @@ k_elbow <- function(hc, .data, census, range){ elbow_finder(dafr$clusters, dafr$correlations) } -#' @rdname model_kselect +#' @rdname method_kselect +#' @section Silhouette method: +#' The silhouette method is based on the concept of cohesion and separation. +#' Cohesion refers to how closely related the nodes within a cluster are, +#' while separation refers to how distinct the clusters are from each other. +#' The silhouette score combines these two concepts into a single metric that +#' can be used to evaluate the quality of a clustering solution. +#' The silhouette score is calculated as follows: +#' For each node, calculate the average distance to all other nodes in the same cluster (a) +#' and the average distance to all other nodes in the next nearest cluster (b). +#' The silhouette score for each node is then calculated as: +#' \deqn{S(i) = \frac{b - a}{\max(a, b)}} +#' A higher silhouette score indicates that the node is well-matched to its +#' own cluster and poorly matched to neighboring clusters. +#' The silhouette score for the entire clustering is the average silhouette score across all nodes. +#' Maximizing the silhouette score across a range of potential clusterings +#' allows researchers to identify the number of clusters that best captures +#' the underlying structure of the data. +#' It is particularly useful when the clusters are well-separated. #' @references #' ## On the silhouette method #' Rousseeuw, Peter J. 1987. @@ -116,8 +155,10 @@ k_elbow <- function(hc, .data, census, range){ #' _Journal of Computational and Applied Mathematics_, 20: 53–65. #' \doi{10.1016/0377-0427(87)90125-7}. #' @export -k_silhouette <- function(hc, .data, range){ - kcs <- 2:min(range, manynet::net_nodes(.data)) +k_silhouette <- function(hc, .data, Kmax){ + if(missing(Kmax)) Kmax <- length(hc$order) else + Kmax <- min(Kmax, length(hc$order)) + kcs <- 2:min(Kmax, manynet::net_nodes(.data)) ns <- seq_len(manynet::net_nodes(.data)) distances <- hc$distances ks <- vector() @@ -143,3 +184,59 @@ k_silhouette <- function(hc, .data, range){ k <- which(ks == max(ks)) + 1 k } + +#' @rdname method_kselect +#' @export +k_gap <- function(hc, motif, Kmax, B = 100) { + + if(missing(Kmax)) Kmax <- length(hc$order) else + Kmax <- min(Kmax, length(hc$order)) + + # --- helper: within-cluster dispersion Wk --- + within_disp <- function(motif, clusters) { + sum(sapply(split(motif, clusters), function(group) { + group <- matrix(group, ncol = ncol(motif)) + if (nrow(group) <= 1) return(0) + center <- colMeans(group) + sum(rowSums((group - center)^2)) + })) + } + + n <- nrow(motif) + p <- ncol(motif) + + # bounding box for reference datasets + mins <- apply(motif, 2, min) + maxs <- apply(motif, 2, max) + + # storage + logW <- numeric(Kmax) + logW_ref <- matrix(0, nrow = B, ncol = Kmax) + + # --- real data W_k --- + for (k in 1:Kmax) { + cl <- cutree(hc, k) + logW[k] <- log(within_disp(motif, cl)) + } + + # --- reference datasets --- + for (b in 1:B) { + ref <- matrix(runif(n * p, mins, maxs), nrow = n) + d_ref <- dist(ref) + hc_ref <- hclust(d_ref, method = hc$method) + + for (k in 1:Kmax) { + cl_ref <- cutree(hc_ref, k) + logW_ref[b, k] <- log(within_disp(ref, cl_ref)) + } + } + + # --- gap statistic --- + gap <- colMeans(logW_ref) - logW + se <- sqrt(1 + 1/B) * apply(logW_ref, 2, sd) + + # --- Tibshirani 1-SE rule --- + k <- which(gap[-Kmax] >= gap[-1] - se[-1])[1] + k +} + diff --git a/man/method_kselect.Rd b/man/method_kselect.Rd new file mode 100644 index 0000000..81d09de --- /dev/null +++ b/man/method_kselect.Rd @@ -0,0 +1,107 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/method_k.R +\name{method_kselect} +\alias{method_kselect} +\alias{k_strict} +\alias{k_elbow} +\alias{k_silhouette} +\alias{k_gap} +\title{Methods for selecting clusters} +\usage{ +k_strict(hc, .data) + +k_elbow(hc, .data, motif, Kmax) + +k_silhouette(hc, .data, Kmax) + +k_gap(hc, motif, Kmax, B = 100) +} +\arguments{ +\item{hc}{A hierarchical clustering object.} + +\item{motif}{A motif census object.} + +\item{Kmax}{An integer indicating the maximum number of options to consider. +The minimum of this and the number of nodes in the network is used.} +} +\value{ +A single integer indicating the number of clusters to return. +} +\description{ +Finding the optimal number of clusters is generally a balance between +optimal fit statistics, parsimony, and interpretability. +These functions help select the number of clusters to return from \code{hc}, +some hierarchical clustering object: +\itemize{ +\item \code{k_strict()} selects a number of clusters in which there is no +distance between cluster members. +\item \code{k_elbow()} selects a number of clusters in which there is +a fair trade-off between parsimony and fit according to the elbow method. +\item \code{k_silhouette()} selects a number of clusters that +maximises the silhouette score. +} + +These functions are generally not user-facing but used internally +in e.g. the \verb{*_equivalence()} functions. +} +\section{Strict method}{ + +The strict method selects the number of clusters in which there is no +distance between cluster members. +This is a very conservative method that may be appropriate when the goal is +to identify clusters of nodes that are exactly the same. +However, it may not be appropriate in cases where the data is noisy or +when the clusters are not well-defined, +as it may result in a large number of small clusters. +} + +\section{Elbow method}{ + +The elbow method is a heuristic used in cluster analysis to determine the optimal number of clusters. +It is based on the idea of plotting the within cluster correlation +as a function of the number of clusters and looking for an "elbow" +where there is a significant decrease in the rate of improvement in +correlation as the number of clusters increases. +The point at which the elbow occurs is often considered a good choice for +the number of clusters, as it represents a balance between +model complexity and fit to the data. +} + +\section{Silhouette method}{ + +The silhouette method is based on the concept of cohesion and separation. +Cohesion refers to how closely related the nodes within a cluster are, +while separation refers to how distinct the clusters are from each other. +The silhouette score combines these two concepts into a single metric that +can be used to evaluate the quality of a clustering solution. +The silhouette score is calculated as follows: +For each node, calculate the average distance to all other nodes in the same cluster (a) +and the average distance to all other nodes in the next nearest cluster (b). +The silhouette score for each node is then calculated as: +\deqn{S(i) = \frac{b - a}{\max(a, b)}} +A higher silhouette score indicates that the node is well-matched to its +own cluster and poorly matched to neighboring clusters. +The silhouette score for the entire clustering is the average silhouette score across all nodes. +Maximizing the silhouette score across a range of potential clusterings +allows researchers to identify the number of clusters that best captures +the underlying structure of the data. +It is particularly useful when the clusters are well-separated. +} + +\references{ +\subsection{On the elbow method}{ + +Thorndike, Robert L. 1953. +"Who Belongs in the Family?". +\emph{Psychometrika}, 18(4): 267–76. +\doi{10.1007/BF02289263}. +} + +\subsection{On the silhouette method}{ + +Rousseeuw, Peter J. 1987. +“Silhouettes: A Graphical Aid to the Interpretation and Validation of Cluster Analysis.” +\emph{Journal of Computational and Applied Mathematics}, 20: 53–65. +\doi{10.1016/0377-0427(87)90125-7}. +} +} diff --git a/man/model_kselect.Rd b/man/model_kselect.Rd deleted file mode 100644 index 4b0f4dc..0000000 --- a/man/model_kselect.Rd +++ /dev/null @@ -1,59 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/model_k.R -\name{model_kselect} -\alias{model_kselect} -\alias{k_strict} -\alias{k_elbow} -\alias{k_silhouette} -\title{Methods for selecting clusters} -\usage{ -k_strict(hc, .data) - -k_elbow(hc, .data, census, range) - -k_silhouette(hc, .data, range) -} -\arguments{ -\item{hc}{A hierarchical clustering object.} - -\item{.data}{A network object of class \code{mnet}, \code{igraph}, \code{tbl_graph}, \code{network}, or similar. -For more information on the standard coercion possible, -see \code{\link[manynet:manip_as]{manynet::as_tidygraph()}}.} - -\item{census}{A motif census object.} - -\item{range}{An integer indicating the maximum number of options to consider. -The minimum of this and the number of nodes in the network is used.} -} -\description{ -These functions help select the number of clusters to return from \code{hc}, -some hierarchical clustering object: -\itemize{ -\item \code{k_strict()} selects a number of clusters in which there is no -distance between cluster members. -\item \code{k_elbow()} selects a number of clusters in which there is -a fair trade-off between parsimony and fit according to the elbow method. -\item \code{k_silhouette()} selects a number of clusters that -optimises the silhouette score. -} - -These functions are generally not user-facing but used internally -in e.g. the \verb{*_equivalence()} functions. -} -\references{ -\subsection{On the elbow method}{ - -Thorndike, Robert L. 1953. -"Who Belongs in the Family?". -\emph{Psychometrika}, 18(4): 267–76. -\doi{10.1007/BF02289263}. -} - -\subsection{On the silhouette method}{ - -Rousseeuw, Peter J. 1987. -“Silhouettes: A Graphical Aid to the Interpretation and Validation of Cluster Analysis.” -\emph{Journal of Computational and Applied Mathematics}, 20: 53–65. -\doi{10.1016/0377-0427(87)90125-7}. -} -} From 53157c6f56b7b39656d4b4c66e829bec8e499794 Mon Sep 17 00:00:00 2001 From: James Hollway Date: Sat, 21 Mar 2026 10:57:56 +0100 Subject: [PATCH 07/35] Separated out centrality scripts and separated out net/node/tie documentation --- R/measure_centrality.R | 1246 ------------------------- R/measure_centrality_betweenness.R | 270 ++++++ R/measure_centrality_closeness.R | 480 ++++++++++ R/measure_centrality_degree.R | 317 +++++++ R/measure_centrality_eigen.R | 330 +++++++ man/measure_central_between.Rd | 109 ++- man/measure_central_close.Rd | 111 ++- man/measure_central_degree.Rd | 115 ++- man/measure_central_eigen.Rd | 95 +- man/measure_centralisation_between.Rd | 86 ++ man/measure_centralisation_close.Rd | 96 ++ man/measure_centralisation_degree.Rd | 97 ++ man/measure_centralisation_eigen.Rd | 84 ++ man/measure_centralities_between.Rd | 101 ++ man/measure_centralities_close.Rd | 102 ++ man/measure_centralities_degree.Rd | 98 ++ man/measure_centralities_eigen.Rd | 98 ++ 17 files changed, 2445 insertions(+), 1390 deletions(-) delete mode 100644 R/measure_centrality.R create mode 100644 R/measure_centrality_betweenness.R create mode 100644 R/measure_centrality_closeness.R create mode 100644 R/measure_centrality_degree.R create mode 100644 R/measure_centrality_eigen.R create mode 100644 man/measure_centralisation_between.Rd create mode 100644 man/measure_centralisation_close.Rd create mode 100644 man/measure_centralisation_degree.Rd create mode 100644 man/measure_centralisation_eigen.Rd create mode 100644 man/measure_centralities_between.Rd create mode 100644 man/measure_centralities_close.Rd create mode 100644 man/measure_centralities_degree.Rd create mode 100644 man/measure_centralities_eigen.Rd diff --git a/R/measure_centrality.R b/R/measure_centrality.R deleted file mode 100644 index 60b5db4..0000000 --- a/R/measure_centrality.R +++ /dev/null @@ -1,1246 +0,0 @@ -# Degree-like centralities #### - -#' Measures of degree-like centrality and centralisation -#' -#' @description -#' These functions calculate common degree-related centrality measures for one- and two-mode networks: -#' -#' - `node_degree()` measures the degree centrality of nodes in an unweighted network, -#' or weighted degree/strength of nodes in a weighted network; -#' there are several related shortcut functions: -#' - `node_deg()` returns the unnormalised results. -#' - `node_indegree()` returns the `direction = 'in'` results. -#' - `node_outdegree()` returns the `direction = 'out'` results. -#' - `node_multidegree()` measures the ratio between types of ties in a multiplex network. -#' - `node_posneg()` measures the PN (positive-negative) centrality of a signed network. -#' - `node_leverage()` measures the leverage centrality of nodes in a network. -#' - `tie_degree()` measures the degree centrality of ties in a network -#' - `net_degree()` measures a network's degree centralization; -#' there are several related shortcut functions: -#' - `net_indegree()` returns the `direction = 'out'` results. -#' - `net_outdegree()` returns the `direction = 'out'` results. -#' -#' All measures attempt to use as much information as they are offered, -#' including whether the networks are directed, weighted, or multimodal. -#' If this would produce unintended results, -#' first transform the salient properties using e.g. [manynet::to_undirected()] functions. -#' All centrality and centralization measures return normalized measures by default, -#' including for two-mode networks. -#' @name measure_central_degree -#' @family centrality -#' @family measures -#' @family degree -#' @inheritParams mark_nodes -#' @param normalized Logical scalar, whether the centrality scores are normalized. -#' Different denominators are used depending on whether the object is one-mode or two-mode, -#' the type of centrality, and other arguments. -#' @param alpha Numeric scalar, the positive tuning parameter introduced in -#' Opsahl et al (2010) for trading off between degree and strength centrality measures. -#' By default, `alpha = 0`, which ignores tie weights and the measure is solely based -#' upon degree (the number of ties). -#' `alpha = 1` ignores the number of ties and provides the sum of the tie weights -#' as strength centrality. -#' Values between 0 and 1 reflect different trade-offs in the relative contributions of -#' degree and strength to the final outcome, with 0.5 as the middle ground. -#' Values above 1 penalise for the number of ties. -#' Of two nodes with the same sum of tie weights, the node with fewer ties will obtain -#' the higher score. -#' This argument is ignored except in the case of a weighted network. -#' @param direction Character string, “out” bases the measure on outgoing ties, -#' “in” on incoming ties, and "all" on either/the sum of the two. -#' For two-mode networks, "all" uses as numerator the sum of differences -#' between the maximum centrality score for the mode -#' against all other centrality scores in the network, -#' whereas "in" uses as numerator the sum of differences -#' between the maximum centrality score for the mode -#' against only the centrality scores of the other nodes in that mode. -#' @return A single centralization score if the object was one-mode, -#' and two centralization scores if the object was two-mode. -#' @importFrom igraph graph_from_incidence_matrix is_bipartite degree V -#' @references -#' ## On multimodal centrality -#' Faust, Katherine. 1997. -#' "Centrality in affiliation networks." -#' _Social Networks_ 19(2): 157-191. -#' \doi{10.1016/S0378-8733(96)00300-0} -#' -#' Borgatti, Stephen P., and Martin G. Everett. 1997. -#' "Network analysis of 2-mode data." -#' _Social Networks_ 19(3): 243-270. -#' \doi{10.1016/S0378-8733(96)00301-2} -#' -#' Borgatti, Stephen P., and Daniel S. Halgin. 2011. -#' "Analyzing affiliation networks." -#' In _The SAGE Handbook of Social Network Analysis_, -#' edited by John Scott and Peter J. Carrington, 417–33. -#' London, UK: Sage. -#' \doi{10.4135/9781446294413.n28} -#' -#' ## On strength centrality -#' Opsahl, Tore, Filip Agneessens, and John Skvoretz. 2010. -#' "Node centrality in weighted networks: Generalizing degree and shortest paths." -#' _Social Networks_ 32, 245-251. -#' \doi{10.1016/j.socnet.2010.03.006} -#' @examples -#' node_by_degree(ison_southern_women) -#' @return Depending on how and what kind of an object is passed to the function, -#' the function will return a `tidygraph` object where the nodes have been updated -NULL - -#' @rdname measure_central_degree -#' @section Degree centrality: -#' `r manynet:::glossies$degree` -#' It is also sometimes called the valency of a node, \eqn{d(v)}. -#' The maximum degree in a network is often denoted \eqn{\Delta (G)} and -#' the minimum degree in a network \eqn{\delta (G)}. -#' The total degree of a network is the sum of all degrees, \eqn{\sum_v d(v)}. -#' The degree sequence is the set of all nodes' degrees, -#' ordered from largest to smallest. -#' Directed networks discriminate between -#' outdegree (degree of outgoing ties) and -#' indegree (degree of incoming ties). -#' @importFrom manynet as_igraph is_weighted tie_weights is_twomode is_complex -#' @export -node_by_degree <- function (.data, normalized = TRUE, alpha = 1, - direction = c("all","out","in")){ - .data <- manynet::expect_nodes(.data) - graph <- manynet::as_igraph(.data) - weights <- `if`(manynet::is_weighted(.data), - manynet::tie_weights(.data), NA) - direction <- match.arg(direction) - - # Do the calculations - if (manynet::is_twomode(graph) & normalized){ - degrees <- igraph::degree(graph = graph, - v = igraph::V(graph), - mode = direction, - loops = manynet::is_complex(.data)) - other_set_size <- ifelse(igraph::V(graph)$type, - sum(!igraph::V(graph)$type), - sum(igraph::V(graph)$type)) - out <- degrees/other_set_size - } else { - if (all(is.na(weights))) { - out <- igraph::degree(graph = graph, v = igraph::V(graph), - mode = direction, - loops = manynet::is_complex(.data), - normalized = normalized) - } - else { - ki <- igraph::degree(graph = graph, v = igraph::V(graph), - mode = direction, - loops = manynet::is_complex(.data)) - si <- igraph::strength(graph = graph, vids = igraph::V(graph), - mode = direction, - loops = manynet::is_complex(.data), weights = weights) - out <- ki * (si/ki)^alpha - out[is.nan(out)] <- 0 - if(normalized) out <- out/max(out) - } - } - out <- make_node_measure(out, .data) - out -} - -#' @rdname measure_central_degree -#' @export -node_by_deg <- function (.data, alpha = 0, direction = c("all","out","in")){ - .data <- manynet::expect_nodes(.data) - node_by_degree(.data, normalized = FALSE, alpha = alpha, direction = direction) -} - -#' @rdname measure_central_degree -#' @export -node_by_outdegree <- function (.data, normalized = TRUE, alpha = 0){ - .data <- manynet::expect_nodes(.data) - node_by_degree(.data, normalized = normalized, alpha = alpha, direction = "out") -} - -#' @rdname measure_central_degree -#' @export -node_by_indegree <- function (.data, normalized = TRUE, alpha = 0){ - .data <- manynet::expect_nodes(.data) - node_by_degree(.data, normalized = normalized, alpha = alpha, direction = "in") -} - -#' @rdname measure_central_degree -#' @param tie1 Character string indicating the first uniplex network. -#' @param tie2 Character string indicating the second uniplex network. -#' @export -node_by_multidegree <- function (.data, tie1, tie2){ - .data <- manynet::expect_nodes(.data) - stopifnot(manynet::is_multiplex(.data)) - out <- node_by_degree(manynet::to_uniplex(.data, tie1)) - - node_by_degree(manynet::to_uniplex(.data, tie2)) - make_node_measure(out, .data) -} - -#' @rdname measure_central_degree -#' @references -#' ## On signed centrality -#' Everett, Martin G., and Stephen P. Borgatti. 2014. -#' “Networks Containing Negative Ties.” -#' _Social Networks_ 38:111–20. -#' \doi{10.1016/j.socnet.2014.03.005} -#' @export -node_by_posneg <- function(.data){ - .data <- manynet::expect_nodes(.data) - stopifnot(manynet::is_signed(.data)) - pos <- manynet::as_matrix(manynet::to_unsigned(.data, keep = "positive")) - neg <- manynet::as_matrix(manynet::to_unsigned(.data, keep = "negative")) - nn <- manynet::net_nodes(.data) - pn <- pos-neg*2 - diag(pn) <- 0 - idmat <- diag(nn) - v1 <- matrix(1,nn,1) - out <- solve(idmat - ((pn%*%t(pn))/(4*(nn-1)^2))) %*% (idmat+( pn/(2*(nn-1)) )) %*% v1 - make_node_measure(out, .data) -} - -#' @rdname measure_central_degree -#' @section Leverage centrality: -#' Leverage centrality concerns the degree of a node compared with that of its -#' neighbours, \eqn{J}: -#' \deqn{C_L(i) = \frac{1}{d(i)} \sum_{j \in J(i)} \frac{d(i) - d(j)}{d(i) + d(j)}} -#' @references -#' ## On leverage centrality -#' Joyce, Karen E., Paul J. Laurienti, Jonathan H. Burdette, and Satoru Hayasaka. 2010. -#' "A New Measure of Centrality for Brain Networks". -#' _PLoS ONE_ 5(8): e12200. -#' \doi{10.1371/journal.pone.0012200} -#' @export -node_by_leverage <- function(.data){ - .data <- manynet::expect_nodes(.data) - out <- (node_by_deg(.data) - node_by_neighbours_degree(.data))/ - (node_by_deg(.data) + node_by_neighbours_degree(.data)) - make_node_measure(out, .data) -} - -#' @rdname measure_central_degree -#' @examples -#' tie_by_degree(ison_adolescents) -#' @export -tie_by_degree <- function(.data, normalized = TRUE){ - .data <- manynet::expect_ties(.data) - edge_adj <- manynet::to_ties(.data) - out <- node_by_degree(edge_adj, normalized = normalized) - class(out) <- "numeric" - make_tie_measure(out, .data) -} - -#' @rdname measure_central_degree -#' @examples -#' net_by_degree(ison_southern_women, direction = "in") -#' @export -net_by_degree <- function(.data, normalized = TRUE, - direction = c("all", "out", "in")){ - - .data <- manynet::expect_nodes(.data) - direction <- match.arg(direction) - - if (manynet::is_twomode(.data)) { - mat <- manynet::as_matrix(.data) - mode <- c(rep(FALSE, nrow(mat)), rep(TRUE, ncol(mat))) - - out <- list() - if (direction == "all") { - if (!normalized) { - allcent <- c(rowSums(mat), colSums(mat)) - out$nodes1 <- sum(max(allcent[!mode]) - allcent)/((nrow(mat) + ncol(mat))*ncol(mat) - 2*(ncol(mat) + nrow(mat) - 1)) - out$nodes2 <- sum(max(allcent[mode]) - allcent)/((nrow(mat) + ncol(mat))*nrow(mat) - 2*(ncol(mat) + nrow(mat) - 1)) - } else if (normalized) { - allcent <- node_by_degree(.data, normalized = TRUE) - out$nodes1 <- sum(max(allcent[!mode]) - allcent)/((nrow(mat) + ncol(mat) - 1) - (ncol(mat) - 1) / nrow(mat) - (ncol(mat) + nrow(mat) - 1)/nrow(mat)) - out$nodes2 <- sum(max(allcent[mode]) - allcent)/((ncol(mat) + nrow(mat) - 1) - (nrow(mat) - 1) / ncol(mat) - (nrow(mat) + ncol(mat) - 1)/ncol(mat)) - } - } else if (direction == "in" | direction == "out") { - out$nodes1 <- sum(max(rowSums(mat)) - rowSums(mat))/((ncol(mat) - 1)*(nrow(mat) - 1)) - out$nodes2 <- sum(max(colSums(mat)) - colSums(mat))/((ncol(mat) - 1)*(nrow(mat) - 1)) - } - out <- c("Mode 1" = out$nodes1, "Mode 2" = out$nodes2) - } else { - out <- igraph::centr_degree(graph = .data, mode = direction, - normalized = normalized)$centralization - } - out <- make_network_measure(out, .data, call = deparse(sys.call())) - out -} - -#' @rdname measure_central_degree -#' @export -net_by_outdegree <- function(.data, normalized = TRUE){ - .data <- manynet::expect_nodes(.data) - net_by_degree(.data, normalized = normalized, direction = "out") -} - -#' @rdname measure_central_degree -#' @export -net_by_indegree <- function(.data, normalized = TRUE){ - .data <- manynet::expect_nodes(.data) - net_by_degree(.data, normalized = normalized, direction = "in") -} - -# Betweenness-like centralities #### - -#' Measures of betweenness-like centrality and centralisation -#' @description -#' These functions calculate common betweenness-related centrality measures for one- and two-mode networks: -#' -#' - `node_betweenness()` measures the betweenness centralities of nodes in a network. -#' - `node_induced()` measures the induced betweenness centralities of nodes in a network. -#' - `node_flow()` measures the flow betweenness centralities of nodes in a network, -#' which uses an electrical current model for information spreading -#' in contrast to the shortest paths model used by normal betweenness centrality. -#' - `node_stress()` measures the stress centrality of nodes in a network. -#' - `tie_betweenness()` measures the number of shortest paths going through a tie. -#' - `net_betweenness()` measures the betweenness centralization for a network. -#' -#' All measures attempt to use as much information as they are offered, -#' including whether the networks are directed, weighted, or multimodal. -#' If this would produce unintended results, -#' first transform the salient properties using e.g. [to_undirected()] functions. -#' All centrality and centralization measures return normalized measures by default, -#' including for two-mode networks. -#' @name measure_central_between -#' @family centrality -#' @family measures -#' @family betweenness -#' @inheritParams measure_central_degree -#' @param cutoff The maximum path length to consider when calculating betweenness. -#' If negative or NULL (the default), there's no limit to the path lengths considered. -NULL - -#' @rdname measure_central_between -#' @section Betweenness centrality: -#' Betweenness centrality is based on the number of shortest paths between -#' other nodes that a node lies upon: -#' \deqn{C_B(i) = \sum_{j,k:j \neq k, j \neq i, k \neq i} \frac{g_{jik}}{g_{jk}}} -#' @references -#' ## On betweenness centrality -#' Freeman, Linton. 1977. -#' "A set of measures of centrality based on betweenness". -#' _Sociometry_, 40(1): 35–41. -#' \doi{10.2307/3033543} -#' @examples -#' node_by_betweenness(ison_southern_women) -#' @return A numeric vector giving the betweenness centrality measure of each node. -#' @export -node_by_betweenness <- function(.data, normalized = TRUE, - cutoff = NULL){ - - .data <- manynet::expect_nodes(.data) - weights <- `if`(manynet::is_weighted(.data), - manynet::tie_weights(.data), NA) - graph <- manynet::as_igraph(.data) - - # Do the calculations - if (manynet::is_twomode(graph) & normalized){ - betw_scores <- igraph::betweenness(graph = graph, v = igraph::V(graph), - directed = manynet::is_directed(graph)) - other_set_size <- ifelse(igraph::V(graph)$type, sum(!igraph::V(graph)$type), sum(igraph::V(graph)$type)) - set_size <- ifelse(igraph::V(graph)$type, sum(igraph::V(graph)$type), sum(!igraph::V(graph)$type)) - out <- ifelse(set_size > other_set_size, - betw_scores/(2*(set_size-1)*(other_set_size-1)), - betw_scores/(1/2*other_set_size*(other_set_size-1)+1/2*(set_size-1)*(set_size-2)+(set_size-1)*(other_set_size-1))) - } else { - if (is.null(cutoff)) { - out <- igraph::betweenness(graph = graph, v = igraph::V(graph), - directed = manynet::is_directed(graph), weights = weights, - normalized = normalized) - } else { - out <- igraph::betweenness(graph = graph, v = igraph::V(graph), - directed = manynet::is_directed(graph), - cutoff = cutoff, - weights = weights) - } - } - out <- make_node_measure(out, .data) - out -} - -#' @rdname measure_central_between -#' @section Induced centrality: -#' Induced centrality or vitality centrality concerns the change in -#' total betweenness centrality between networks with and without a given node: -#' \deqn{C_I(i) = C_B(G) - C_B(G\ i)} -#' @references -#' ## On induced centrality -#' Everett, Martin and Steve Borgatti. 2010. -#' "Induced, endogenous and exogenous centrality" -#' _Social Networks_, 32: 339-344. -#' \doi{10.1016/j.socnet.2010.06.004} -#' @examples -#' node_by_induced(ison_adolescents) -#' @export -node_by_induced <- function(.data, normalized = TRUE, - cutoff = NULL){ - .data <- manynet::expect_nodes(.data) - endog <- sum(node_by_betweenness(.data, normalized = normalized, cutoff = cutoff), - na.rm = TRUE) - exog <- vapply(seq.int(manynet::net_nodes(.data)), - function(x) sum(node_by_betweenness(manynet::delete_nodes(.data, x), - normalized = normalized, cutoff = cutoff), - na.rm = TRUE), - FUN.VALUE = numeric(1)) - out <- endog - exog - make_node_measure(out, .data) -} - -#' @rdname measure_central_between -#' @section Flow betweenness centrality: -#' Flow betweenness centrality concerns the total maximum flow, \eqn{f}, -#' between other nodes \eqn{j,k} in a network \eqn{G} that a given node mediates: -#' \deqn{C_F(i) = \sum_{j,k:j\neq k, j\neq i, k\neq i} f(j,k,G) - f(j,k,G\ i)} -#' When normalized (by default) this sum of differences is divided by the -#' sum of flows \eqn{f(i,j,G)}. -#' @references -#' ## On flow centrality -#' Freeman, Lin, Stephen Borgatti, and Douglas White. 1991. -#' "Centrality in Valued Graphs: A Measure of Betweenness Based on Network Flow". -#' _Social Networks_, 13(2), 141-154. -#' -#' Koschutzki, D., K.A. Lehmann, L. Peeters, S. Richter, D. Tenfelde-Podehl, and O. Zlotowski. 2005. -#' "Centrality Indices". -#' In U. Brandes and T. Erlebach (eds.), _Network Analysis: Methodological Foundations_. -#' Berlin: Springer. -#' @export -node_by_flow <- function(.data, normalized = TRUE){ - .data <- manynet::expect_nodes(.data) - thisRequires("sna") - out <- sna::flowbet(manynet::as_network(.data), - gmode = ifelse(manynet::is_directed(.data), "digraph", "graph"), - diag = manynet::is_complex(.data), - cmode = ifelse(normalized, "normflow", "rawflow")) - make_node_measure(out, .data) -} - -#' @rdname measure_central_between -#' @section Stress centrality: -#' Stress centrality is the number of all shortest paths or geodesics, \eqn{g}, -#' between other nodes that a given node mediates: -#' \deqn{C_S(i) = \sum_{j,k:j \neq k, j \neq i, k \neq i} g_{jik}} -#' High stress nodes lie on a large number of shortest paths between other -#' nodes, and thus associated with bridging or spanning boundaries. -#' @references -#' ## On stress centrality -#' Shimbel, A. 1953. -#' "Structural Parameters of Communication Networks". -#' _Bulletin of Mathematical Biophysics_, 15:501-507. -#' \doi{10.1007/BF02476438} -#' @export -node_by_stress <- function(.data, normalized = TRUE){ - .data <- manynet::expect_nodes(.data) - thisRequires("sna") - out <- sna::stresscent(manynet::as_network(.data), - gmode = ifelse(manynet::is_directed(.data), "digraph", "graph"), - diag = manynet::is_complex(.data), - rescale = normalized) - make_node_measure(out, .data) -} - -#' @rdname measure_central_between -#' @importFrom igraph edge_betweenness -#' @examples -#' (tb <- tie_by_betweenness(ison_adolescents)) -#' ison_adolescents %>% mutate_ties(weight = tb) -#' @export -tie_by_betweenness <- function(.data, normalized = TRUE){ - .data <- manynet::expect_ties(.data) - .data <- manynet::as_igraph(.data) - eddies <- manynet::as_edgelist(.data) - eddies <- paste(eddies[["from"]], eddies[["to"]], sep = "-") - out <- igraph::edge_betweenness(.data) - names(out) <- eddies - make_tie_measure(out, .data) -} - -#' @rdname measure_central_between -#' @examples -#' net_by_betweenness(ison_southern_women, direction = "in") -#' @export -net_by_betweenness <- function(.data, normalized = TRUE, - direction = c("all", "out", "in")) { - .data <- manynet::expect_nodes(.data) - direction <- match.arg(direction) - graph <- manynet::as_igraph(.data) - - if (manynet::is_twomode(.data)) { - becent <- node_by_betweenness(graph, normalized = FALSE) - mode <- igraph::V(graph)$type - mode1 <- length(mode) - sum(mode) - mode2 <- sum(mode) - out <- list() - if (direction == "all") { - if (!normalized) { - out$nodes1 <- sum(max(becent[!mode]) - becent) / ((1/2 * mode2 * (mode2 - 1) + 1/2 * (mode1 - 1)*(mode1 - 2) + (mode1 - 1) * (mode2 - 2))*(mode1 + mode2 - 1) + (mode1 - 1)) - out$nodes2 <- sum(max(becent[mode]) - becent) / ((1/2 * mode1 * (mode1 - 1) + 1/2 * (mode2 - 1)*(mode2 - 2) + (mode2 - 1) * (mode1 - 2))*(mode2 + mode1 - 1) + (mode2 - 1)) - if (mode1 > mode2) { - out$nodes1 <- sum(max(becent[!mode]) - becent) / (2 * (mode1 - 1) * (mode2 - 1) * (mode1 + mode2 - 1) - (mode2 - 1) * (mode1 + mode2 - 2) - 1/2 * (mode1 - mode2) * (mode1 + 3*mode2 - 3)) - } - if (mode2 > mode1) { - out$nodes2 <- sum(max(becent[mode]) - becent) / (2 * (mode2 - 1) * (mode1 - 1) * (mode2 + mode1 - 1) - (mode1 - 1) * (mode2 + mode1 - 2) - 1/2 * (mode2 - mode1) * (mode2 + 3*mode1 - 3)) - } - } else if (normalized) { - out$nodes1 <- sum(max(becent[!mode]) - becent) / ((1/2 * mode2 * (mode2 - 1) + 1/2 * (mode1 - 1)*(mode1 - 2) + (mode1 - 1) * (mode2 - 2))*(mode1 + mode2 - 1) + (mode1 - 1)) - out$nodes2 <- sum(max(becent[mode]) - becent) / ((1/2 * mode1 * (mode1 - 1) + 1/2 * (mode2 - 1)*(mode2 - 2) + (mode2 - 1) * (mode1 - 2))*(mode2 + mode1 - 1) + (mode2 - 1)) - if (mode1 > mode2) { - becent <- node_by_betweenness(graph, normalized = TRUE) - out$nodes1 <- sum(max(becent[!mode]) - becent) / ((mode1 + mode2 - 1) - (((mode2 - 1)*(mode1 + mode2 - 2) + 1/2*(mode1 - mode2)*(mode1 + (3*mode2) - 3)) / (1/2*(mode1*(mode1 - 1)) + 1/2*(mode2 - 1) * (mode2 - 2) + (mode1 - 1) * (mode2 - 1)))) - } - if (mode2 > mode1) { - becent <- node_by_betweenness(graph, normalized = TRUE) - out$nodes2 <- sum(max(becent[mode]) - becent) / ((mode1 + mode2 - 1)*((mode1 - 1)*(mode1 + mode2 - 2) / 2*(mode1 - 1)*(mode2 - 1))) - } - } - } else if (direction == "in") { - out$nodes1 <- sum(max(becent[!mode]) - becent[!mode])/((mode1 - 1)*(1/2*mode2*(mode2 - 1) + 1/2*(mode1 - 1)*(mode1 - 2) + (mode1 - 1)*(mode2 - 1))) - out$nodes2 <- sum(max(becent[mode]) - becent[mode])/((mode2 - 1)*(1/2*mode1*(mode1 - 1) + 1/2 * (mode2 - 1) * (mode2 - 2) + (mode2 - 1) * (mode1 - 1))) - if (mode1 > mode2) { - out$nodes1 <- sum(max(becent[!mode]) - becent[!mode]) / (2 * (mode1 - 1)^2 * (mode2 - 1)) - } - if (mode2 > mode1) { - out$nodes2 <- sum(max(becent[mode]) - becent[mode]) / (2 * (mode2 - 1)^2 * (mode1 - 1)) - } - } - out <- c("Mode 1" = out$nodes1, "Mode 2" = out$nodes2) - } else { - out <- igraph::centr_betw(graph = graph)$centralization - } - out <- make_network_measure(out, .data, call = deparse(sys.call())) - out -} - -# Closeness-like centralities #### - -#' Measures of closeness-like centrality and centralisation -#' @description -#' These functions calculate common closeness-related centrality measures -#' that rely on path-length for one- and two-mode networks: -#' -#' - `node_by_closeness()` measures the closeness centrality of nodes in a -#' network. -#' - `node_by_harmonic()` measures nodes' harmonic centrality or valued -#' centrality, which is thought to behave better than reach centrality -#' for disconnected networks. -#' - `node_by_reach()` measures nodes' reach centrality, -#' or how many nodes they can reach within _k_ steps. -#' - `node_by_information()` measures nodes' information centrality or -#' current-flow closeness centrality. -#' - `node_by_eccentricity()` measures nodes' eccentricity or maximum distance -#' from another node in the network. -#' - `node_by_distance()` measures nodes' geodesic distance from or to a -#' given node. -#' - `node_by_vitality()` measures a network's closeness vitality centrality, -#' or the change in closeness centrality between networks with and without a -#' given node. -#' - `tie_by_closeness()` measures the closeness of each tie to other ties -#' in the network. -#' - `net_by_closeness()` measures a network's closeness centralization. -#' - `net_by_reach()` measures a network's reach centralization. -#' - `net_by_harmonic()` measures a network's harmonic centralization. -#' -#' All measures attempt to use as much information as they are offered, -#' including whether the networks are directed, weighted, or multimodal. -#' If this would produce unintended results, -#' first transform the salient properties using e.g. [to_undirected()] functions. -#' All centrality and centralization measures return normalized measures by default, -#' including for two-mode networks. -#' @name measure_central_close -#' @family centrality -#' @family measures -#' @inheritParams measure_central_degree -NULL - -#' @rdname measure_central_close -#' @param cutoff Maximum path length to use during calculations. -#' @section Closeness centrality: -#' Closeness centrality, status centrality, or barycenter centrality is -#' defined as the reciprocal of the farness or distance, \eqn{d}, -#' from a node to all other nodes in the network: -#' \deqn{C_C(i) = \frac{1}{\sum_j d(i,j)}} -#' When (more commonly) normalised, the numerator is instead \eqn{N-1}. -#' @references -#' ## On closeness centrality -#' Bavelas, Alex. 1950. -#' "Communication Patterns in Task‐Oriented Groups". -#' _The Journal of the Acoustical Society of America_, 22(6): 725–730. -#' \doi{10.1121/1.1906679} -#' -#' Harary, Frank. 1959. -#' "Status and Contrastatus". -#' _Sociometry_, 22(1): 23–43. -#' \doi{10.2307/2785610} -#' @examples -#' node_by_closeness(ison_southern_women) -#' @export -node_by_closeness <- function(.data, normalized = TRUE, - direction = "out", cutoff = NULL){ - - .data <- manynet::expect_nodes(.data) - weights <- `if`(manynet::is_weighted(.data), - manynet::tie_weights(.data), NA) - graph <- manynet::as_igraph(.data) - - # Do the calculations - if (manynet::is_twomode(graph) & normalized){ - # farness <- rowSums(igraph::distances(graph = graph)) - closeness <- igraph::closeness(graph = graph, vids = igraph::V(graph), mode = direction) - other_set_size <- ifelse(igraph::V(graph)$type, sum(!igraph::V(graph)$type), sum(igraph::V(graph)$type)) - set_size <- ifelse(igraph::V(graph)$type, sum(igraph::V(graph)$type), sum(!igraph::V(graph)$type)) - out <- closeness/(1/(other_set_size+2*set_size-2)) - } else { - cutoff <- if (is.null(cutoff)) -1 else cutoff - out <- igraph::closeness(graph = graph, vids = igraph::V(graph), mode = direction, - cutoff = cutoff, weights = weights, normalized = normalized) - } - out <- make_node_measure(out, .data) - out -} - -#' @rdname measure_central_close -#' @section Harmonic centrality: -#' Harmonic centrality or valued centrality reverses the sum and reciprocal -#' operations compared to closeness centrality: -#' \deqn{C_H(i) = \sum_{i, i \neq j} \frac{1}{d(i,j)}} -#' where \eqn{\frac{1}{d(i,j)} = 0} where there is no path between \eqn{i} and -#' \eqn{j}. Normalization is by \eqn{N-1}. -#' Since the harmonic mean performs better than the arithmetic mean on -#' unconnected networks, i.e. networks with infinite distances, -#' harmonic centrality is to be preferred in these cases. -#' @references -#' ## On harmonic centrality -#' Marchiori, Massimo, and Vito Latora. 2000. -#' "Harmony in the small-world". -#' _Physica A_ 285: 539-546. -#' \doi{10.1016/S0378-4371(00)00311-3} -#' -#' Dekker, Anthony. 2005. -#' "Conceptual distance in social network analysis". -#' _Journal of Social Structure_ 6(3). -#' @export -node_by_harmonic <- function(.data, normalized = TRUE, cutoff = -1){ - .data <- manynet::expect_nodes(.data) - out <- igraph::harmonic_centrality(as_igraph(.data), # weighted if present - normalized = normalized, cutoff = cutoff) - out <- make_node_measure(out, .data) - out -} - -#' @rdname measure_central_close -#' @section Reach centrality: -#' In some cases, longer path lengths are irrelevant and 'closeness' should -#' be defined as how many others are in a local neighbourhood. -#' How many steps out this neighbourhood should be defined as is given by -#' the 'cutoff' parameter. -#' This is usually termed \eqn{k} or \eqn{m} in equations, -#' which is why this is sometimes called (\eqn{m}- or) -#' \eqn{k}-step reach centrality: -#' \deqn{C_R(i) = \sum_j d(i,j) \leq k} -#' The maximum reach score is \eqn{N-1}, achieved when the node can reach all -#' other nodes in the network in \eqn{k} steps or less, -#' but the normalised version, \eqn{\frac{C_R}{N-1}}, is more common. -#' Note that if \eqn{k = 1} (i.e. cutoff = 1), then this returns the node's degree. -#' At higher cutoff reach centrality returns the size of the node's component. -#' @references -#' ## On reach centrality -#' Borgatti, Stephen P., Martin G. Everett, and J.C. Johnson. 2013. -#' _Analyzing social networks_. -#' London: SAGE Publications Limited. -#' @examples -#' node_by_reach(ison_adolescents) -#' @export -node_by_reach <- function(.data, normalized = TRUE, cutoff = 2){ - .data <- manynet::expect_nodes(.data) - if(manynet::is_weighted(.data)){ - tore <- manynet::as_matrix(.data)/mean(manynet::as_matrix(.data)) - out <- 1/tore - } else out <- igraph::distances(manynet::as_igraph(.data)) - diag(out) <- 0 - out <- rowSums(out <= cutoff) - if(normalized) out <- out/(manynet::net_nodes(.data)-1) - out <- make_node_measure(out, .data) - out -} - -#' @rdname measure_central_close -#' @section Information centrality: -#' Information centrality, also known as current-flow centrality, -#' is a hybrid measure relating to both path-length and walk-based measures. -#' The information centrality of a node is the harmonic average of the -#' “bandwidth” or inverse path-length for all paths originating from the node. -#' -#' As described in the `{sna}` package, -#' information centrality works on an undirected but potentially weighted -#' network excluding isolates (which take scores of zero). -#' It is defined as: -#' \deqn{C_I = \frac{1}{T + \frac{\sum T - 2 \sum C_1}{|N|}}} -#' where \eqn{C = B^-1} with \eqn{B} is a pseudo-adjacency matrix replacing -#' the diagonal of \eqn{1-A} with \eqn{1+k}, -#' and \eqn{T} is the trace of \eqn{C} and \eqn{S_R} an arbitrary row sum -#' (all rows in \eqn{C} have the same sum). -#' -#' Nodes with higher information centrality have a large number of short paths -#' to many others in the network, and are thus considered to have greater -#' control of the flow of information. -#' @references -#' ## On information centrality -#' Stephenson, Karen, and Marvin Zelen. 1989. -#' "Rethinking centrality: Methods and examples". -#' _Social Networks_ 11(1):1-37. -#' \doi{10.1016/0378-8733(89)90016-6} -#' -#' Brandes, Ulrik, and Daniel Fleischer. 2005. -#' "Centrality Measures Based on Current Flow". -#' _Proc. 22nd Symp. Theoretical Aspects of Computer Science_ LNCS 3404: 533-544. -#' \doi{10.1007/978-3-540-31856-9_44} -#' @export -node_by_information <- function(.data, normalized = TRUE){ - .data <- manynet::expect_nodes(.data) - thisRequires("sna") - out <- sna::infocent(manynet::as_network(.data), - gmode = ifelse(manynet::is_directed(.data), "digraph", "graph"), - diag = manynet::is_complex(.data), - rescale = normalized) - make_node_measure(out, .data) -} - -#' @rdname measure_central_close -#' @section Eccentricity centrality: -#' Eccentricity centrality, graph centrality, or the Koenig number, -#' is the (if normalized, inverse of) the distance to the furthest node: -#' \deqn{C_E(i) = \frac{1}{max_{j \in N} d(i,j)}} -#' where the distance from \eqn{i} to \eqn{j} is \eqn{\infty} if unconnected. -#' As such it is only well defined for connected networks. -#' @references -#' ## On eccentricity centrality -#' Hage, Per, and Frank Harary. 1995. -#' "Eccentricity and centrality in networks". -#' _Social Networks_, 17(1): 57-63. -#' \doi{10.1016/0378-8733(94)00248-9} -#' @export -node_by_eccentricity <- function(.data, normalized = TRUE){ - .data <- manynet::expect_nodes(.data) - if(!manynet::is_connected(.data)) - manynet::snet_unavailable("Eccentricity centrality is only available for connected networks.") - disties <- igraph::distances(as_igraph(.data)) - out <- apply(disties, 1, max) - if(normalized) out <- 1/out - make_node_measure(out, .data) -} - -# - `node_eccentricity()` measures nodes' eccentricity or Koenig number, -# a measure of farness based on number of links needed to reach -# most distant node in the network. -# #' @rdname measure_holes -# #' @importFrom igraph eccentricity -# #' @export -# cnode_eccentricity <- function(.data){ -# if(missing(.data)) {expect_nodes(); .data <- .G()} -# out <- igraph::eccentricity(manynet::as_igraph(.data), -# mode = "out") -# make_node_measure(out, .data) -# } - -#' @rdname measure_central_close -#' @param from,to Index or name of a node to calculate distances from or to. -#' @export -node_by_distance <- function(.data, from, to, normalized = TRUE){ - .data <- manynet::expect_nodes(.data) - if(missing(from) && missing(to)) manynet::snet_abort("Either 'from' or 'to' must be specified.") - if(!missing(from)) out <- igraph::distances(manynet::as_igraph(.data), v = from) else - if(!missing(to)) out <- igraph::distances(manynet::as_igraph(.data), to = to) - if(normalized) out <- out/max(out) - make_node_measure(out, .data) -} - -#' @rdname measure_central_close -#' @section Closeness vitality centrality: -#' The closeness vitality of a node is the change in the sum of all distances -#' in a network, also known as the Wiener Index, when that node is removed. -#' Note that the closeness vitality may be negative infinity if -#' removing that node would disconnect the network. -#' Formally: -#' \deqn{C_V(i) = \sum_{j,k} d(j,k) - \sum_{j,k} d(j,k,G\ i)} -#' where \eqn{d(j,k,G\ i)} is the distance between nodes \eqn{j} and \eqn{k} -#' in the network with node \eqn{i} removed. -#' @references -#' ## On closeness vitality centrality -#' Koschuetzki, Dirk, Katharina Lehmann, Leon Peeters, Stefan Richter, -#' Dagmar Tenfelde-Podehl, and Oliver Zlotowski. 2005. -#' "Centrality Indices", in -#' Brandes, Ulrik, and Thomas Erlebach (eds.). -#' _Network Analysis: Methodological Foundations_. -#' Springer: Berlin, pp. 16-61. -#' @export -node_by_vitality <- function(.data, normalized = TRUE){ - .data <- manynet::expect_nodes(.data) - .data <- manynet::as_igraph(.data) - out <- vapply(manynet::snet_progress_nodes(.data), function(x){ - sum(igraph::distances(.data)) - - sum(igraph::distances(manynet::delete_nodes(.data, x))) - }, FUN.VALUE = numeric(1)) - if(normalized) out <- out/max(out) - make_node_measure(out, .data) -} - -#' @rdname measure_central_close -#' @section Random walk closeness centrality: -#' Random walk closeness centrality is based on the average length of -#' random walks starting at all other nodes to reach a given node. -#' It is defined as the inverse of the average hitting time to a node. -#' This means that higher values are given to nodes that can be reached -#' more quickly on average by random walks starting at other nodes. -#' Formally: -#' \deqn{C_{RW}(i) = \frac{1}{\frac{1}{N-1} \sum_{j \neq i} H_{ji}}} -#' where \eqn{H_{ji}} is the hitting time from node \eqn{j} to node \eqn{i}. -#' @references -#' ## On random walk closeness centrality -#' Noh, J.D. and R. Rieger. 2004. -#' "Random Walks on Complex Networks". -#' _Physical Review Letters_, 92(11): 118701. -#' \doi{10.1103/PhysRevLett.92.118701} -#' @export -node_by_randomwalk <- function(.data, normalized = TRUE){ - .data <- manynet::expect_nodes(.data) - # adjacency and degree matrices - A <- manynet::as_matrix(manynet::to_multilevel(.data)) - degs <- node_by_deg(.data) - D <- diag(degs) - - # Laplacian - L <- D - A - - # pseudoinverse of Laplacian - Lplus <- .ginv(L) - - volG <- sum(degs) # total degree (2 * edges) - n <- manynet::net_nodes(.data) - - out <- numeric(n) - - for (i in 1:n) { - # hitting time from j to i - hitting_times <- sapply(1:n, function(j) { - if (i == j) return(0) - volG * (Lplus[j, j] + Lplus[i, i] - 2 * Lplus[i, j]) - }) - # average hitting time to node i - avg_ht <- mean(hitting_times[-i]) - out[i] <- 1 / avg_ht - } - - make_node_measure(out, .data) -} - -# This is a helper function to compute the Moore-Penrose generalized inverse -# of a matrix using its singular value decomposition (SVD). -.ginv <- function (X, tol = sqrt(.Machine$double.eps)){ - if (length(dim(X)) > 2L || !(is.numeric(X) || is.complex(X))) - stop("'X' must be a numeric or complex matrix") - if (!is.matrix(X)) - X <- as.matrix(X) - Xsvd <- svd(X) - if (is.complex(X)) - Xsvd$u <- Conj(Xsvd$u) - Positive <- Xsvd$d > max(tol * Xsvd$d[1L], 0) - if (all(Positive)) - Xsvd$v %*% (1/Xsvd$d * t(Xsvd$u)) - else if (!any(Positive)) - array(0, dim(X)[2L:1L]) - else Xsvd$v[, Positive, drop = FALSE] %*% ((1/Xsvd$d[Positive]) * - t(Xsvd$u[, Positive, drop = FALSE])) -} - -#' @rdname measure_central_close -#' @examples -#' (ec <- tie_by_closeness(ison_adolescents)) -#' ison_adolescents %>% mutate_ties(weight = ec) -#' @export -tie_by_closeness <- function(.data, normalized = TRUE){ - .data <- manynet::expect_ties(.data) - edge_adj <- manynet::to_ties(.data) - out <- node_by_closeness(edge_adj, normalized = normalized) - class(out) <- "numeric" - make_tie_measure(out, .data) -} - -#' @rdname measure_central_close -#' @examples -#' net_by_closeness(ison_southern_women, direction = "in") -#' @export -net_by_closeness <- function(.data, normalized = TRUE, - direction = c("all", "out", "in")){ - - .data <- manynet::expect_nodes(.data) - direction <- match.arg(direction) - graph <- manynet::as_igraph(.data) - - if (manynet::is_twomode(.data)) { - clcent <- node_by_closeness(graph, normalized = TRUE) - mode <- igraph::V(graph)$type - mode1 <- length(mode) - sum(mode) - mode2 <- sum(mode) - out <- list() - if (direction == "in") { - out$nodes1 <- sum(max(clcent[!mode]) - clcent[!mode])/(((mode1 - 2)*(mode1 - 1))/(2 * mode1 - 3)) - out$nodes2 <- sum(max(clcent[mode]) - clcent[mode])/(((mode2 - 2)*(mode2 - 1))/(2 * mode2 - 3)) - if (mode1 > mode2) { #28.43 - lhs <- ((mode2 - 1)*(mode1 - 2) / (2 * mode1 - 3)) - rhs <- ((mode2 - 1)*(mode1 - mode2) / (mode1 + mode2 - 2)) - out$nodes1 <- sum(max(clcent[!mode]) - clcent[!mode])/( lhs + rhs) # 0.2135 - } - if (mode2 > mode1) { - lhs <- ((mode1 - 1)*(mode2 - 2) / (2 * mode2 - 3)) - rhs <- ((mode1 - 1)*(mode2 - mode1) / (mode2 + mode1 - 2)) - out$nodes2 <- sum(max(clcent[mode]) - clcent[mode])/( lhs + rhs) - } - } else { - term1 <- 2*(mode1 - 1) * (mode2 + mode1 - 4)/(3*mode2 + 4*mode1 - 8) - term2 <- 2*(mode1 - 1) * (mode1 - 2)/(2*mode2 + 3*mode1 - 6) - term3 <- 2*(mode1 - 1) * (mode2 - mode1 + 1)/(2*mode2 + 3*mode1 - 4) - out$nodes1 <- sum(max(clcent[!mode]) - clcent) / sum(term1, term2, term3) - term1 <- 2*(mode2 - 1) * (mode1 + mode2 - 4)/(3*mode1 + 4*mode2 - 8) - term2 <- 2*(mode2 - 1) * (mode2 - 2)/(2*mode1 + 3*mode2 - 6) - term3 <- 2*(mode2 - 1) * (mode1 - mode2 + 1)/(2*mode1 + 3*mode2 - 4) - out$nodes2 <- sum(max(clcent[mode]) - clcent) / sum(term1, term2, term3) - - if (mode1 > mode2) { - term1 <- 2*(mode2 - 1) * (mode2 + mode1 - 2) / (3 * mode2 + 4 * mode1 - 8) - term2 <- 2*(mode1 - mode2) * (2 * mode2 - 1) / (5 * mode2 + 2 * mode1 - 6) - term3 <- 2*(mode2 - 1) * (mode1 - 2) / (2 * mode2 + 3 * mode1 - 6) - term4 <- 2 * (mode2 - 1) / (mode1 + 4 * mode2 - 4) - out$nodes1 <- sum(max(clcent[!mode]) - clcent) / sum(term1, term2, term3, term4) - } - if (mode2 > mode1) { - term1 <- 2*(mode1 - 1) * (mode1 + mode2 - 2) / (3 * mode1 + 4 * mode2 - 8) - term2 <- 2*(mode2 - mode1) * (2 * mode1 - 1) / (5 * mode1 + 2 * mode2 - 6) - term3 <- 2*(mode1 - 1) * (mode2 - 2) / (2 * mode1 + 3 * mode2 - 6) - term4 <- 2 * (mode1 - 1) / (mode2 + 4 * mode1 - 4) - out$nodes2 <- sum(max(clcent[mode]) - clcent) / sum(term1, term2, term3, term4) - } - } - out <- c("Mode 1" = out$nodes1, "Mode 2" = out$nodes2) - } else { - out <- igraph::centr_clo(graph = graph, - mode = direction, - normalized = normalized)$centralization - } - out <- make_network_measure(out, .data, call = deparse(sys.call())) - out -} - -#' @rdname measure_central_close -#' @export -net_by_reach <- function(.data, normalized = TRUE, cutoff = 2){ - .data <- manynet::expect_nodes(.data) - reaches <- node_by_reach(.data, normalized = FALSE, cutoff = cutoff) - out <- sum(max(reaches) - reaches) - if(normalized) out <- out / sum(manynet::net_nodes(.data) - reaches) - make_network_measure(out, .data, call = deparse(sys.call())) -} - -#' @rdname measure_central_close -#' @export -net_by_harmonic <- function(.data, normalized = TRUE, cutoff = 2){ - .data <- manynet::expect_nodes(.data) - harm <- node_by_harmonic(.data, normalized = FALSE, cutoff = cutoff) - out <- sum(max(harm) - harm) - if(normalized) out <- out / sum(manynet::net_nodes(.data) - harm) - make_network_measure(out, .data, call = deparse(sys.call())) -} - -# Eigenvector-like centralities #### - -#' Measures of eigenvector-like centrality and centralisation -#' @description -#' These functions calculate common eigenvector-related centrality -#' measures, or walk-based eigenmeasures, for one- and two-mode networks: -#' -#' - `node_eigenvector()` measures the eigenvector centrality of nodes -#' in a network. -#' - `node_power()` measures the Bonacich, beta, or power centrality of -#' nodes in a network. -#' - `node_alpha()` measures the alpha or Katz centrality of nodes in a -#' network. -#' - `node_pagerank()` measures the pagerank centrality of nodes in a network. -#' - `node_hub()` measures how well nodes in a network serve as hubs pointing -#' to many authorities. -#' - `node_authority()` measures how well nodes in a network serve as -#' authorities from many hubs. -#' - `tie_eigenvector()` measures the eigenvector centrality of ties in a -#' network. -#' - `net_eigenvector()` measures the eigenvector centralization for a -#' network. -#' -#' All measures attempt to use as much information as they are offered, -#' including whether the networks are directed, weighted, or multimodal. -#' If this would produce unintended results, -#' first transform the salient properties using e.g. [to_undirected()] functions. -#' All centrality and centralization measures return normalized measures -#' by default, including for two-mode networks. -#' @name measure_central_eigen -#' @family centrality -#' @family measures -#' @inheritParams measure_central_degree -NULL - -#' @rdname measure_central_eigen -#' @section Eigenvector centrality: -#' Eigenvector centrality operates as a measure of a node's influence in a network. -#' The idea is that being connected to well-connected others results in a higher score. -#' Each node's eigenvector centrality can be defined as: -#' \deqn{x_i = \frac{1}{\lambda} \sum_{j \in N} a_{i,j} x_j} -#' where \eqn{a_{i,j} = 1} if \eqn{i} is linked to \eqn{j} and 0 otherwise, -#' and \eqn{\lambda} is a constant representing the principal eigenvalue. -#' Rather than performing this iteration, -#' most routines solve the eigenvector equation \eqn{Ax = \lambda x}. -#' Note that since `{igraph}` v2.1.1, -#' the values will always be rescaled so that the maximum is 1. -#' @param scale Logical scalar, whether to rescale the vector so the maximum score is 1. -#' @details -#' We use `{igraph}` routines behind the scenes here for consistency and because they are often faster. -#' For example, `igraph::eigencentrality()` is approximately 25% faster than `sna::evcent()`. -#' @references -#' ## On eigenvector centrality -#' Bonacich, Phillip. 1991. -#' “Simultaneous Group and Individual Centralities.” -#' _Social Networks_ 13(2):155–68. -#' \doi{10.1016/0378-8733(91)90018-O} -#' @examples -#' node_by_eigenvector(ison_southern_women) -#' @return A numeric vector giving the eigenvector centrality measure of each node. -#' @export -node_by_eigenvector <- function(.data, normalized = TRUE, scale = TRUE){ - - .data <- manynet::expect_nodes(.data) - weights <- `if`(manynet::is_weighted(.data), - manynet::tie_weights(.data), NA) - graph <- manynet::as_igraph(.data) - - if(!normalized) manynet::snet_info("This function always returns a normalized value now.") - if(!scale) manynet::snet_info("This function always returns a scaled value now.") - - if(!manynet::is_connected(.data)) - manynet::snet_warn("Unconnected networks will only allow nodes from one component to have non-zero eigenvector scores.") - - # Do the calculations - if (!manynet::is_twomode(graph)){ - out <- igraph::eigen_centrality(graph = graph, - directed = manynet::is_directed(graph), - options = igraph::arpack_defaults())$vector - } else { - eigen1 <- manynet::to_mode1(graph) - eigen1 <- igraph::eigen_centrality(graph = eigen1, - directed = manynet::is_directed(eigen1), - options = igraph::arpack_defaults())$vector - eigen2 <- manynet::to_mode2(graph) - eigen2 <- igraph::eigen_centrality(graph = eigen2, - directed = manynet::is_directed(eigen2), - options = igraph::arpack_defaults())$vector - out <- c(eigen1, eigen2) - } - out <- make_node_measure(out, .data) - out -} - -#' @rdname measure_central_eigen -#' @param exponent Decay rate or attentuation factor for -#' the Bonacich power centrality score. -#' Can be positive or negative. -#' @section Power or beta (or Bonacich) centrality: -#' Power centrality includes an exponent that weights contributions to a node's -#' centrality based on how far away those other nodes are. -#' \deqn{c_b(i) = \sum A(i,j) (\alpha = \beta c(j))} -#' Where \eqn{\beta} is positive, this means being connected to central people -#' increases centrality. -#' Where \eqn{\beta} is negative, this means being connected to central people -#' decreases centrality -#' (and being connected to more peripheral actors increases centrality). -#' When \eqn{\beta = 0}, this is the outdegree. -#' \eqn{\alpha} is calculated to make sure the root mean square equals -#' the network size. -#' @references -#' ## On power centrality -#' Bonacich, Phillip. 1987. -#' “Power and Centrality: A Family of Measures.” -#' _The American Journal of Sociology_, 92(5): 1170–82. -#' \doi{10.1086/228631}. -#' @importFrom igraph power_centrality -#' @examples -#' node_by_power(ison_southern_women, exponent = 0.5) -#' @return A numeric vector giving each node's power centrality measure. -#' @export -node_by_power <- function(.data, normalized = TRUE, scale = FALSE, exponent = 1){ - - .data <- manynet::expect_nodes(.data) - weights <- `if`(manynet::is_weighted(.data), - manynet::tie_weights(.data), NA) - graph <- manynet::as_igraph(.data) - - if(var(node_by_deg(graph))==0){ - manynet::snet_minor_info("All nodes have the same degree, so power centrality equals degree centrality.") - exponent <- 0 - } - - # Do the calculations - if (!manynet::is_twomode(graph)){ - out <- igraph::power_centrality(graph = graph, - exponent = exponent, - rescale = scale) - if (normalized) out <- out / sqrt(1/2) - } else { - eigen1 <- manynet::to_mode1(graph) - eigen1 <- igraph::power_centrality(graph = eigen1, - exponent = exponent, - rescale = scale) - eigen2 <- manynet::to_mode2(graph) - eigen2 <- igraph::power_centrality(graph = eigen2, - exponent = exponent, - rescale = scale) - out <- c(eigen1, eigen2) - if (normalized) out <- out / sqrt(1/2) - } - out <- make_node_measure(out, .data) - out -} - -#' @rdname measure_central_eigen -#' @param alpha A constant that trades off the importance of external influence against the importance of connection. -#' When \eqn{\alpha = 0}, only the external influence matters. -#' As \eqn{\alpha} gets larger, only the connectivity matters and we reduce to eigenvector centrality. -#' By default \eqn{\alpha = 0.85}. -#' @section Alpha centrality: -#' Alpha or Katz (or Katz-Bonacich) centrality operates better than -#' eigenvector centrality for directed networks because eigenvector centrality -#' will return 0s for all nodes not in the main strongly-connected component. -#' Each node's alpha centrality can be defined as: -#' \deqn{x_i = \frac{1}{\lambda} \sum_{j \in N} a_{i,j} x_j + e_i} -#' where \eqn{a_{i,j} = 1} if \eqn{i} is linked to \eqn{j} and 0 otherwise, -#' \eqn{\lambda} is a constant representing the principal eigenvalue, -#' and \eqn{e_i} is some external influence used to ensure that even nodes beyond the main -#' strongly connected component begin with some basic influence. -#' Note that many equations replace \eqn{\frac{1}{\lambda}} with \eqn{\alpha}, -#' hence the name. -#' -#' For example, if \eqn{\alpha = 0.5}, then each direct connection (or alter) would be worth \eqn{(0.5)^1 = 0.5}, -#' each secondary connection (or tertius) would be worth \eqn{(0.5)^2 = 0.25}, -#' each tertiary connection would be worth \eqn{(0.5)^3 = 0.125}, and so on. -#' -#' Rather than performing this iteration though, -#' most routines solve the equation \eqn{x = (I - \frac{1}{\lambda} A^T)^{-1} e}. -#' @importFrom igraph alpha_centrality -#' @references -#' ## On alpha centrality -#' Katz, Leo 1953. -#' "A new status index derived from sociometric analysis". -#' _Psychometrika_. 18(1): 39–43. -#' -#' Bonacich, P. and Lloyd, P. 2001. -#' “Eigenvector-like measures of centrality for asymmetric relations” -#' _Social Networks_. 23(3):191-201. -#' @export -node_by_alpha <- function(.data, alpha = 0.85){ - .data <- manynet::expect_nodes(.data) - make_node_measure(igraph::alpha_centrality(manynet::as_igraph(.data), - alpha = alpha), - .data) -} - -#' @rdname measure_central_eigen -#' @references -#' ## On pagerank centrality -#' Brin, Sergey and Page, Larry. 1998. -#' "The anatomy of a large-scale hypertextual web search engine". -#' _Proceedings of the 7th World-Wide Web Conference_. Brisbane, Australia. -#' @export -node_by_pagerank <- function(.data){ - .data <- manynet::expect_nodes(.data) - make_node_measure(igraph::page_rank(manynet::as_igraph(.data))$vector, - .data) -} - -#' @rdname measure_central_eigen -#' @references -#' ## On hub and authority centrality -#' Kleinberg, Jon. 1999. -#' "Authoritative sources in a hyperlinked environment". -#' _Journal of the ACM_ 46(5): 604–632. -#' \doi{10.1145/324133.324140} -#' @export -node_by_authority <- function(.data){ - .data <- manynet::expect_nodes(.data) - make_node_measure(igraph::hits_scores(manynet::as_igraph(.data))$authority, - .data) -} - -#' @rdname measure_central_eigen -#' @export -node_by_hub <- function(.data){ - .data <- manynet::expect_nodes(.data) - make_node_measure(igraph::hits_scores(manynet::as_igraph(.data))$hub, - .data) -} - -#' @rdname measure_central_eigen -#' @section Subgraph centrality: -#' Subgraph centrality measures the participation of a node in all subgraphs -#' in the network, giving higher weight to smaller subgraphs. -#' It is defined as: -#' \deqn{C_S(i) = \sum_{k=0}^{\infty} \frac{(A^k)_{ii}}{k!}} -#' where \eqn{(A^k)_{ii}} is the \eqn{i}th diagonal element of the \eqn{k}th power -#' of the adjacency matrix \eqn{A}, representing the number of closed walks -#' of length \eqn{k} starting and ending at node \eqn{i}. -#' Weighting by \eqn{\frac{1}{k!}} ensures that shorter walks contribute more -#' to the centrality score than longer walks. -#' -#' Subgraph centrality is a good choice of measure when the focus is on -#' local connectivity and clustering around a node, -#' as it captures the extent to which a node is embedded in tightly-knit -#' groups within the network. -#' Note though that because of the way spectral decomposition is used to -#' calculate this measure, this is not a good measure for very large graphs. -#' @references -#' ## On subgraph centrality -#' Estrada, Ernesto and Rodríguez-Velázquez, Juan A. 2005. -#' "Subgraph centrality in complex networks". -#' _Physical Review E_ 71(5): 056103. -#' \doi{10.1103/PhysRevE.71.056103} -#' @export -node_by_subgraph <- function(.data){ - .data <- manynet::expect_nodes(.data) - make_node_measure(igraph::subgraph_centrality(manynet::as_igraph(.data)), - .data) -} - -#' @rdname measure_central_eigen -#' @examples -#' tie_by_eigenvector(ison_adolescents) -#' @export -tie_by_eigenvector <- function(.data, normalized = TRUE){ - .data <- manynet::expect_ties(.data) - edge_adj <- manynet::to_ties(.data) - out <- node_by_eigenvector(edge_adj, normalized = normalized) - class(out) <- "numeric" - make_tie_measure(out, .data) -} - -#' @rdname measure_central_eigen -#' @examples -#' net_by_eigenvector(ison_southern_women) -#' @export -net_by_eigenvector <- function(.data, normalized = TRUE){ - .data <- manynet::expect_nodes(.data) - if (manynet::is_twomode(.data)) { - out <- c(igraph::centr_eigen(manynet::as_igraph(manynet::to_mode1(.data)), - normalized = normalized)$centralization, - igraph::centr_eigen(manynet::as_igraph(manynet::to_mode2(.data)), - normalized = normalized)$centralization) - } else { - out <- igraph::centr_eigen(manynet::as_igraph(.data), - normalized = normalized)$centralization - } - out <- make_network_measure(out, .data, call = deparse(sys.call())) - out -} - - diff --git a/R/measure_centrality_betweenness.R b/R/measure_centrality_betweenness.R new file mode 100644 index 0000000..36eca9d --- /dev/null +++ b/R/measure_centrality_betweenness.R @@ -0,0 +1,270 @@ +# Betweenness centrality #### + +#' Measuring nodes betweenness-like centrality +#' @name measure_central_between +#' @description +#' These functions calculate common betweenness-related centrality measures for one- and two-mode networks: +#' +#' - `node_by_betweenness()` measures the betweenness centralities of nodes in a network. +#' - `node_by_induced()` measures the induced betweenness centralities of nodes in a network. +#' - `node_by_flow()` measures the flow betweenness centralities of nodes in a network, +#' which uses an electrical current model for information spreading +#' in contrast to the shortest paths model used by normal betweenness centrality. +#' - `node_by_stress()` measures the stress centrality of nodes in a network. +#' - `tie_by_betweenness()` measures the number of shortest paths going through a tie. +#' +#' All measures attempt to use as much information as they are offered, +#' including whether the networks are directed, weighted, or multimodal. +#' If this would produce unintended results, +#' first transform the salient properties using e.g. [to_undirected()] functions. +#' All centrality and centralization measures return normalized measures by default, +#' including for two-mode networks. +#' @template param_data +#' @family betweenness +#' @family centrality +#' @template node_measure +#' @param cutoff The maximum path length to consider when calculating betweenness. +#' If negative or NULL (the default), there's no limit to the path lengths considered. +NULL + +#' @rdname measure_central_between +#' @section Betweenness centrality: +#' Betweenness centrality is based on the number of shortest paths between +#' other nodes that a node lies upon: +#' \deqn{C_B(i) = \sum_{j,k:j \neq k, j \neq i, k \neq i} \frac{g_{jik}}{g_{jk}}} +#' @references +#' ## On betweenness centrality +#' Freeman, Linton. 1977. +#' "A set of measures of centrality based on betweenness". +#' _Sociometry_, 40(1): 35–41. +#' \doi{10.2307/3033543} +#' @examples +#' node_by_betweenness(ison_southern_women) +#' @export +node_by_betweenness <- function(.data, normalized = TRUE, + cutoff = NULL){ + + .data <- manynet::expect_nodes(.data) + weights <- `if`(manynet::is_weighted(.data), + manynet::tie_weights(.data), NA) + graph <- manynet::as_igraph(.data) + + # Do the calculations + if (manynet::is_twomode(graph) & normalized){ + betw_scores <- igraph::betweenness(graph = graph, v = igraph::V(graph), + directed = manynet::is_directed(graph)) + other_set_size <- ifelse(igraph::V(graph)$type, sum(!igraph::V(graph)$type), sum(igraph::V(graph)$type)) + set_size <- ifelse(igraph::V(graph)$type, sum(igraph::V(graph)$type), sum(!igraph::V(graph)$type)) + out <- ifelse(set_size > other_set_size, + betw_scores/(2*(set_size-1)*(other_set_size-1)), + betw_scores/(1/2*other_set_size*(other_set_size-1)+1/2*(set_size-1)*(set_size-2)+(set_size-1)*(other_set_size-1))) + } else { + if (is.null(cutoff)) { + out <- igraph::betweenness(graph = graph, v = igraph::V(graph), + directed = manynet::is_directed(graph), weights = weights, + normalized = normalized) + } else { + out <- igraph::betweenness(graph = graph, v = igraph::V(graph), + directed = manynet::is_directed(graph), + cutoff = cutoff, + weights = weights) + } + } + out <- make_node_measure(out, .data) + out +} + +#' @rdname measure_central_between +#' @section Induced centrality: +#' Induced centrality or vitality centrality concerns the change in +#' total betweenness centrality between networks with and without a given node: +#' \deqn{C_I(i) = C_B(G) - C_B(G\ i)} +#' @references +#' ## On induced centrality +#' Everett, Martin and Steve Borgatti. 2010. +#' "Induced, endogenous and exogenous centrality" +#' _Social Networks_, 32: 339-344. +#' \doi{10.1016/j.socnet.2010.06.004} +#' @examples +#' node_by_induced(ison_adolescents) +#' @export +node_by_induced <- function(.data, normalized = TRUE, + cutoff = NULL){ + .data <- manynet::expect_nodes(.data) + endog <- sum(node_by_betweenness(.data, normalized = normalized, cutoff = cutoff), + na.rm = TRUE) + exog <- vapply(seq.int(manynet::net_nodes(.data)), + function(x) sum(node_by_betweenness(manynet::delete_nodes(.data, x), + normalized = normalized, cutoff = cutoff), + na.rm = TRUE), + FUN.VALUE = numeric(1)) + out <- endog - exog + make_node_measure(out, .data) +} + +#' @rdname measure_central_between +#' @section Flow betweenness centrality: +#' Flow betweenness centrality concerns the total maximum flow, \eqn{f}, +#' between other nodes \eqn{j,k} in a network \eqn{G} that a given node mediates: +#' \deqn{C_F(i) = \sum_{j,k:j\neq k, j\neq i, k\neq i} f(j,k,G) - f(j,k,G\ i)} +#' When normalized (by default) this sum of differences is divided by the +#' sum of flows \eqn{f(i,j,G)}. +#' @references +#' ## On flow centrality +#' Freeman, Lin, Stephen Borgatti, and Douglas White. 1991. +#' "Centrality in Valued Graphs: A Measure of Betweenness Based on Network Flow". +#' _Social Networks_, 13(2), 141-154. +#' +#' Koschutzki, D., K.A. Lehmann, L. Peeters, S. Richter, D. Tenfelde-Podehl, and O. Zlotowski. 2005. +#' "Centrality Indices". +#' In U. Brandes and T. Erlebach (eds.), _Network Analysis: Methodological Foundations_. +#' Berlin: Springer. +#' @export +node_by_flow <- function(.data, normalized = TRUE){ + .data <- manynet::expect_nodes(.data) + thisRequires("sna") + out <- sna::flowbet(manynet::as_network(.data), + gmode = ifelse(manynet::is_directed(.data), "digraph", "graph"), + diag = manynet::is_complex(.data), + cmode = ifelse(normalized, "normflow", "rawflow")) + make_node_measure(out, .data) +} + +#' @rdname measure_central_between +#' @section Stress centrality: +#' Stress centrality is the number of all shortest paths or geodesics, \eqn{g}, +#' between other nodes that a given node mediates: +#' \deqn{C_S(i) = \sum_{j,k:j \neq k, j \neq i, k \neq i} g_{jik}} +#' High stress nodes lie on a large number of shortest paths between other +#' nodes, and thus associated with bridging or spanning boundaries. +#' @references +#' ## On stress centrality +#' Shimbel, A. 1953. +#' "Structural Parameters of Communication Networks". +#' _Bulletin of Mathematical Biophysics_, 15:501-507. +#' \doi{10.1007/BF02476438} +#' @export +node_by_stress <- function(.data, normalized = TRUE){ + .data <- manynet::expect_nodes(.data) + thisRequires("sna") + out <- sna::stresscent(manynet::as_network(.data), + gmode = ifelse(manynet::is_directed(.data), "digraph", "graph"), + diag = manynet::is_complex(.data), + rescale = normalized) + make_node_measure(out, .data) +} + +# Tie betweenness centrality #### + +#' Measuring ties betweenness-like centrality +#' @name measure_centralities_between +#' @description +#' `tie_by_betweenness()` measures the number of shortest paths going through a tie. +#' +#' All measures attempt to use as much information as they are offered, +#' including whether the networks are directed, weighted, or multimodal. +#' If this would produce unintended results, +#' first transform the salient properties using e.g. [to_undirected()] functions. +#' All centrality and centralization measures return normalized measures by default, +#' including for two-mode networks. +#' @template param_data +#' @family betweenness +#' @family centrality +#' @template tie_measure +#' @param cutoff The maximum path length to consider when calculating betweenness. +#' If negative or NULL (the default), there's no limit to the path lengths considered. +NULL + +#' @rdname measure_centralities_between +#' @importFrom igraph edge_betweenness +#' @examples +#' (tb <- tie_by_betweenness(ison_adolescents)) +#' ison_adolescents %>% mutate_ties(weight = tb) +#' @export +tie_by_betweenness <- function(.data, normalized = TRUE){ + .data <- manynet::expect_ties(.data) + .data <- manynet::as_igraph(.data) + eddies <- manynet::as_edgelist(.data) + eddies <- paste(eddies[["from"]], eddies[["to"]], sep = "-") + out <- igraph::edge_betweenness(.data) + names(out) <- eddies + make_tie_measure(out, .data) +} + +# Betweenness centralisation #### + +#' Measuring networks betweenness-like centralisation +#' @name measure_centralisation_between +#' @description +#' `net_by_betweenness()` measures the betweenness centralization for a network. +#' +#' All measures attempt to use as much information as they are offered, +#' including whether the networks are directed, weighted, or multimodal. +#' If this would produce unintended results, +#' first transform the salient properties using e.g. [to_undirected()] functions. +#' All centrality and centralization measures return normalized measures by default, +#' including for two-mode networks. +#' @template param_data +#' @family betweenness +#' @family centrality +#' @template net_measure +#' @param cutoff The maximum path length to consider when calculating betweenness. +#' If negative or NULL (the default), there's no limit to the path lengths considered. +NULL + +#' @rdname measure_centralisation_between +#' @examples +#' net_by_betweenness(ison_southern_women, direction = "in") +#' @export +net_by_betweenness <- function(.data, normalized = TRUE, + direction = c("all", "out", "in")) { + .data <- manynet::expect_nodes(.data) + direction <- match.arg(direction) + graph <- manynet::as_igraph(.data) + + if (manynet::is_twomode(.data)) { + becent <- node_by_betweenness(graph, normalized = FALSE) + mode <- igraph::V(graph)$type + mode1 <- length(mode) - sum(mode) + mode2 <- sum(mode) + out <- list() + if (direction == "all") { + if (!normalized) { + out$nodes1 <- sum(max(becent[!mode]) - becent) / ((1/2 * mode2 * (mode2 - 1) + 1/2 * (mode1 - 1)*(mode1 - 2) + (mode1 - 1) * (mode2 - 2))*(mode1 + mode2 - 1) + (mode1 - 1)) + out$nodes2 <- sum(max(becent[mode]) - becent) / ((1/2 * mode1 * (mode1 - 1) + 1/2 * (mode2 - 1)*(mode2 - 2) + (mode2 - 1) * (mode1 - 2))*(mode2 + mode1 - 1) + (mode2 - 1)) + if (mode1 > mode2) { + out$nodes1 <- sum(max(becent[!mode]) - becent) / (2 * (mode1 - 1) * (mode2 - 1) * (mode1 + mode2 - 1) - (mode2 - 1) * (mode1 + mode2 - 2) - 1/2 * (mode1 - mode2) * (mode1 + 3*mode2 - 3)) + } + if (mode2 > mode1) { + out$nodes2 <- sum(max(becent[mode]) - becent) / (2 * (mode2 - 1) * (mode1 - 1) * (mode2 + mode1 - 1) - (mode1 - 1) * (mode2 + mode1 - 2) - 1/2 * (mode2 - mode1) * (mode2 + 3*mode1 - 3)) + } + } else if (normalized) { + out$nodes1 <- sum(max(becent[!mode]) - becent) / ((1/2 * mode2 * (mode2 - 1) + 1/2 * (mode1 - 1)*(mode1 - 2) + (mode1 - 1) * (mode2 - 2))*(mode1 + mode2 - 1) + (mode1 - 1)) + out$nodes2 <- sum(max(becent[mode]) - becent) / ((1/2 * mode1 * (mode1 - 1) + 1/2 * (mode2 - 1)*(mode2 - 2) + (mode2 - 1) * (mode1 - 2))*(mode2 + mode1 - 1) + (mode2 - 1)) + if (mode1 > mode2) { + becent <- node_by_betweenness(graph, normalized = TRUE) + out$nodes1 <- sum(max(becent[!mode]) - becent) / ((mode1 + mode2 - 1) - (((mode2 - 1)*(mode1 + mode2 - 2) + 1/2*(mode1 - mode2)*(mode1 + (3*mode2) - 3)) / (1/2*(mode1*(mode1 - 1)) + 1/2*(mode2 - 1) * (mode2 - 2) + (mode1 - 1) * (mode2 - 1)))) + } + if (mode2 > mode1) { + becent <- node_by_betweenness(graph, normalized = TRUE) + out$nodes2 <- sum(max(becent[mode]) - becent) / ((mode1 + mode2 - 1)*((mode1 - 1)*(mode1 + mode2 - 2) / 2*(mode1 - 1)*(mode2 - 1))) + } + } + } else if (direction == "in") { + out$nodes1 <- sum(max(becent[!mode]) - becent[!mode])/((mode1 - 1)*(1/2*mode2*(mode2 - 1) + 1/2*(mode1 - 1)*(mode1 - 2) + (mode1 - 1)*(mode2 - 1))) + out$nodes2 <- sum(max(becent[mode]) - becent[mode])/((mode2 - 1)*(1/2*mode1*(mode1 - 1) + 1/2 * (mode2 - 1) * (mode2 - 2) + (mode2 - 1) * (mode1 - 1))) + if (mode1 > mode2) { + out$nodes1 <- sum(max(becent[!mode]) - becent[!mode]) / (2 * (mode1 - 1)^2 * (mode2 - 1)) + } + if (mode2 > mode1) { + out$nodes2 <- sum(max(becent[mode]) - becent[mode]) / (2 * (mode2 - 1)^2 * (mode1 - 1)) + } + } + out <- c("Mode 1" = out$nodes1, "Mode 2" = out$nodes2) + } else { + out <- igraph::centr_betw(graph = graph)$centralization + } + out <- make_network_measure(out, .data, call = deparse(sys.call())) + out +} + diff --git a/R/measure_centrality_closeness.R b/R/measure_centrality_closeness.R new file mode 100644 index 0000000..6c0dc62 --- /dev/null +++ b/R/measure_centrality_closeness.R @@ -0,0 +1,480 @@ +# Closeness-like centralities #### + +#' Measuring nodes closeness-like centrality +#' @description +#' These functions calculate common closeness-related centrality measures +#' that rely on path-length for one- and two-mode networks: +#' +#' - `node_by_closeness()` measures the closeness centrality of nodes in a +#' network. +#' - `node_by_harmonic()` measures nodes' harmonic centrality or valued +#' centrality, which is thought to behave better than reach centrality +#' for disconnected networks. +#' - `node_by_reach()` measures nodes' reach centrality, +#' or how many nodes they can reach within _k_ steps. +#' - `node_by_information()` measures nodes' information centrality or +#' current-flow closeness centrality. +#' - `node_by_eccentricity()` measures nodes' eccentricity or maximum distance +#' from another node in the network. +#' - `node_by_distance()` measures nodes' geodesic distance from or to a +#' given node. +#' - `node_by_vitality()` measures a network's closeness vitality centrality, +#' or the change in closeness centrality between networks with and without a +#' given node. +#' +#' All measures attempt to use as much information as they are offered, +#' including whether the networks are directed, weighted, or multimodal. +#' If this would produce unintended results, +#' first transform the salient properties using e.g. [to_undirected()] functions. +#' All centrality and centralization measures return normalized measures by default, +#' including for two-mode networks. +#' @name measure_central_close +#' @template param_data +#' @family closeness +#' @family centrality +#' @template node_measure +NULL + +#' @rdname measure_central_close +#' @param cutoff Maximum path length to use during calculations. +#' @section Closeness centrality: +#' Closeness centrality, status centrality, or barycenter centrality is +#' defined as the reciprocal of the farness or distance, \eqn{d}, +#' from a node to all other nodes in the network: +#' \deqn{C_C(i) = \frac{1}{\sum_j d(i,j)}} +#' When (more commonly) normalised, the numerator is instead \eqn{N-1}. +#' @references +#' ## On closeness centrality +#' Bavelas, Alex. 1950. +#' "Communication Patterns in Task‐Oriented Groups". +#' _The Journal of the Acoustical Society of America_, 22(6): 725–730. +#' \doi{10.1121/1.1906679} +#' +#' Harary, Frank. 1959. +#' "Status and Contrastatus". +#' _Sociometry_, 22(1): 23–43. +#' \doi{10.2307/2785610} +#' @examples +#' node_by_closeness(ison_southern_women) +#' @export +node_by_closeness <- function(.data, normalized = TRUE, + direction = "out", cutoff = NULL){ + + .data <- manynet::expect_nodes(.data) + weights <- `if`(manynet::is_weighted(.data), + manynet::tie_weights(.data), NA) + graph <- manynet::as_igraph(.data) + + # Do the calculations + if (manynet::is_twomode(graph) & normalized){ + # farness <- rowSums(igraph::distances(graph = graph)) + closeness <- igraph::closeness(graph = graph, vids = igraph::V(graph), mode = direction) + other_set_size <- ifelse(igraph::V(graph)$type, sum(!igraph::V(graph)$type), sum(igraph::V(graph)$type)) + set_size <- ifelse(igraph::V(graph)$type, sum(igraph::V(graph)$type), sum(!igraph::V(graph)$type)) + out <- closeness/(1/(other_set_size+2*set_size-2)) + } else { + cutoff <- if (is.null(cutoff)) -1 else cutoff + out <- igraph::closeness(graph = graph, vids = igraph::V(graph), mode = direction, + cutoff = cutoff, weights = weights, normalized = normalized) + } + out <- make_node_measure(out, .data) + out +} + +#' @rdname measure_central_close +#' @section Harmonic centrality: +#' Harmonic centrality or valued centrality reverses the sum and reciprocal +#' operations compared to closeness centrality: +#' \deqn{C_H(i) = \sum_{i, i \neq j} \frac{1}{d(i,j)}} +#' where \eqn{\frac{1}{d(i,j)} = 0} where there is no path between \eqn{i} and +#' \eqn{j}. Normalization is by \eqn{N-1}. +#' Since the harmonic mean performs better than the arithmetic mean on +#' unconnected networks, i.e. networks with infinite distances, +#' harmonic centrality is to be preferred in these cases. +#' @references +#' ## On harmonic centrality +#' Marchiori, Massimo, and Vito Latora. 2000. +#' "Harmony in the small-world". +#' _Physica A_ 285: 539-546. +#' \doi{10.1016/S0378-4371(00)00311-3} +#' +#' Dekker, Anthony. 2005. +#' "Conceptual distance in social network analysis". +#' _Journal of Social Structure_ 6(3). +#' @export +node_by_harmonic <- function(.data, normalized = TRUE, cutoff = -1){ + .data <- manynet::expect_nodes(.data) + out <- igraph::harmonic_centrality(as_igraph(.data), # weighted if present + normalized = normalized, cutoff = cutoff) + out <- make_node_measure(out, .data) + out +} + +#' @rdname measure_central_close +#' @section Reach centrality: +#' In some cases, longer path lengths are irrelevant and 'closeness' should +#' be defined as how many others are in a local neighbourhood. +#' How many steps out this neighbourhood should be defined as is given by +#' the 'cutoff' parameter. +#' This is usually termed \eqn{k} or \eqn{m} in equations, +#' which is why this is sometimes called (\eqn{m}- or) +#' \eqn{k}-step reach centrality: +#' \deqn{C_R(i) = \sum_j d(i,j) \leq k} +#' The maximum reach score is \eqn{N-1}, achieved when the node can reach all +#' other nodes in the network in \eqn{k} steps or less, +#' but the normalised version, \eqn{\frac{C_R}{N-1}}, is more common. +#' Note that if \eqn{k = 1} (i.e. cutoff = 1), then this returns the node's degree. +#' At higher cutoff reach centrality returns the size of the node's component. +#' @references +#' ## On reach centrality +#' Borgatti, Stephen P., Martin G. Everett, and J.C. Johnson. 2013. +#' _Analyzing social networks_. +#' London: SAGE Publications Limited. +#' @examples +#' node_by_reach(ison_adolescents) +#' @export +node_by_reach <- function(.data, normalized = TRUE, cutoff = 2){ + .data <- manynet::expect_nodes(.data) + if(manynet::is_weighted(.data)){ + tore <- manynet::as_matrix(.data)/mean(manynet::as_matrix(.data)) + out <- 1/tore + } else out <- igraph::distances(manynet::as_igraph(.data)) + diag(out) <- 0 + out <- rowSums(out <= cutoff) + if(normalized) out <- out/(manynet::net_nodes(.data)-1) + out <- make_node_measure(out, .data) + out +} + +#' @rdname measure_central_close +#' @section Information centrality: +#' Information centrality, also known as current-flow centrality, +#' is a hybrid measure relating to both path-length and walk-based measures. +#' The information centrality of a node is the harmonic average of the +#' “bandwidth” or inverse path-length for all paths originating from the node. +#' +#' As described in the `{sna}` package, +#' information centrality works on an undirected but potentially weighted +#' network excluding isolates (which take scores of zero). +#' It is defined as: +#' \deqn{C_I = \frac{1}{T + \frac{\sum T - 2 \sum C_1}{|N|}}} +#' where \eqn{C = B^-1} with \eqn{B} is a pseudo-adjacency matrix replacing +#' the diagonal of \eqn{1-A} with \eqn{1+k}, +#' and \eqn{T} is the trace of \eqn{C} and \eqn{S_R} an arbitrary row sum +#' (all rows in \eqn{C} have the same sum). +#' +#' Nodes with higher information centrality have a large number of short paths +#' to many others in the network, and are thus considered to have greater +#' control of the flow of information. +#' @references +#' ## On information centrality +#' Stephenson, Karen, and Marvin Zelen. 1989. +#' "Rethinking centrality: Methods and examples". +#' _Social Networks_ 11(1):1-37. +#' \doi{10.1016/0378-8733(89)90016-6} +#' +#' Brandes, Ulrik, and Daniel Fleischer. 2005. +#' "Centrality Measures Based on Current Flow". +#' _Proc. 22nd Symp. Theoretical Aspects of Computer Science_ LNCS 3404: 533-544. +#' \doi{10.1007/978-3-540-31856-9_44} +#' @export +node_by_information <- function(.data, normalized = TRUE){ + .data <- manynet::expect_nodes(.data) + thisRequires("sna") + out <- sna::infocent(manynet::as_network(.data), + gmode = ifelse(manynet::is_directed(.data), "digraph", "graph"), + diag = manynet::is_complex(.data), + rescale = normalized) + make_node_measure(out, .data) +} + +#' @rdname measure_central_close +#' @section Eccentricity centrality: +#' Eccentricity centrality, graph centrality, or the Koenig number, +#' is the (if normalized, inverse of) the distance to the furthest node: +#' \deqn{C_E(i) = \frac{1}{max_{j \in N} d(i,j)}} +#' where the distance from \eqn{i} to \eqn{j} is \eqn{\infty} if unconnected. +#' As such it is only well defined for connected networks. +#' @references +#' ## On eccentricity centrality +#' Hage, Per, and Frank Harary. 1995. +#' "Eccentricity and centrality in networks". +#' _Social Networks_, 17(1): 57-63. +#' \doi{10.1016/0378-8733(94)00248-9} +#' @export +node_by_eccentricity <- function(.data, normalized = TRUE){ + .data <- manynet::expect_nodes(.data) + if(!manynet::is_connected(.data)) + manynet::snet_unavailable("Eccentricity centrality is only available for connected networks.") + disties <- igraph::distances(as_igraph(.data)) + out <- apply(disties, 1, max) + if(normalized) out <- 1/out + make_node_measure(out, .data) +} + +# - `node_eccentricity()` measures nodes' eccentricity or Koenig number, +# a measure of farness based on number of links needed to reach +# most distant node in the network. +# #' @rdname measure_holes +# #' @importFrom igraph eccentricity +# #' @export +# cnode_eccentricity <- function(.data){ +# if(missing(.data)) {expect_nodes(); .data <- .G()} +# out <- igraph::eccentricity(manynet::as_igraph(.data), +# mode = "out") +# make_node_measure(out, .data) +# } + +#' @rdname measure_central_close +#' @param from,to Index or name of a node to calculate distances from or to. +#' @export +node_by_distance <- function(.data, from, to, normalized = TRUE){ + .data <- manynet::expect_nodes(.data) + if(missing(from) && missing(to)) manynet::snet_abort("Either 'from' or 'to' must be specified.") + if(!missing(from)) out <- igraph::distances(manynet::as_igraph(.data), v = from) else + if(!missing(to)) out <- igraph::distances(manynet::as_igraph(.data), to = to) + if(normalized) out <- out/max(out) + make_node_measure(out, .data) +} + +#' @rdname measure_central_close +#' @section Closeness vitality centrality: +#' The closeness vitality of a node is the change in the sum of all distances +#' in a network, also known as the Wiener Index, when that node is removed. +#' Note that the closeness vitality may be negative infinity if +#' removing that node would disconnect the network. +#' Formally: +#' \deqn{C_V(i) = \sum_{j,k} d(j,k) - \sum_{j,k} d(j,k,G\ i)} +#' where \eqn{d(j,k,G\ i)} is the distance between nodes \eqn{j} and \eqn{k} +#' in the network with node \eqn{i} removed. +#' @references +#' ## On closeness vitality centrality +#' Koschuetzki, Dirk, Katharina Lehmann, Leon Peeters, Stefan Richter, +#' Dagmar Tenfelde-Podehl, and Oliver Zlotowski. 2005. +#' "Centrality Indices", in +#' Brandes, Ulrik, and Thomas Erlebach (eds.). +#' _Network Analysis: Methodological Foundations_. +#' Springer: Berlin, pp. 16-61. +#' @export +node_by_vitality <- function(.data, normalized = TRUE){ + .data <- manynet::expect_nodes(.data) + .data <- manynet::as_igraph(.data) + out <- vapply(manynet::snet_progress_nodes(.data), function(x){ + sum(igraph::distances(.data)) - + sum(igraph::distances(manynet::delete_nodes(.data, x))) + }, FUN.VALUE = numeric(1)) + if(normalized) out <- out/max(out) + make_node_measure(out, .data) +} + +#' @rdname measure_central_close +#' @section Random walk closeness centrality: +#' Random walk closeness centrality is based on the average length of +#' random walks starting at all other nodes to reach a given node. +#' It is defined as the inverse of the average hitting time to a node. +#' This means that higher values are given to nodes that can be reached +#' more quickly on average by random walks starting at other nodes. +#' Formally: +#' \deqn{C_{RW}(i) = \frac{1}{\frac{1}{N-1} \sum_{j \neq i} H_{ji}}} +#' where \eqn{H_{ji}} is the hitting time from node \eqn{j} to node \eqn{i}. +#' @references +#' ## On random walk closeness centrality +#' Noh, J.D. and R. Rieger. 2004. +#' "Random Walks on Complex Networks". +#' _Physical Review Letters_, 92(11): 118701. +#' \doi{10.1103/PhysRevLett.92.118701} +#' @export +node_by_randomwalk <- function(.data, normalized = TRUE){ + .data <- manynet::expect_nodes(.data) + # adjacency and degree matrices + A <- manynet::as_matrix(manynet::to_multilevel(.data)) + degs <- node_by_deg(.data) + D <- diag(degs) + + # Laplacian + L <- D - A + + # pseudoinverse of Laplacian + Lplus <- .ginv(L) + + volG <- sum(degs) # total degree (2 * edges) + n <- manynet::net_nodes(.data) + + out <- numeric(n) + + for (i in 1:n) { + # hitting time from j to i + hitting_times <- sapply(1:n, function(j) { + if (i == j) return(0) + volG * (Lplus[j, j] + Lplus[i, i] - 2 * Lplus[i, j]) + }) + # average hitting time to node i + avg_ht <- mean(hitting_times[-i]) + out[i] <- 1 / avg_ht + } + + make_node_measure(out, .data) +} + +# This is a helper function to compute the Moore-Penrose generalized inverse +# of a matrix using its singular value decomposition (SVD). +.ginv <- function (X, tol = sqrt(.Machine$double.eps)){ + if (length(dim(X)) > 2L || !(is.numeric(X) || is.complex(X))) + stop("'X' must be a numeric or complex matrix") + if (!is.matrix(X)) + X <- as.matrix(X) + Xsvd <- svd(X) + if (is.complex(X)) + Xsvd$u <- Conj(Xsvd$u) + Positive <- Xsvd$d > max(tol * Xsvd$d[1L], 0) + if (all(Positive)) + Xsvd$v %*% (1/Xsvd$d * t(Xsvd$u)) + else if (!any(Positive)) + array(0, dim(X)[2L:1L]) + else Xsvd$v[, Positive, drop = FALSE] %*% ((1/Xsvd$d[Positive]) * + t(Xsvd$u[, Positive, drop = FALSE])) +} + +# Tie closeness centrality #### + +#' Measuring ties closeness-like centrality +#' @name measure_centralities_close +#' @description +#' `tie_by_closeness()` measures the closeness of each tie to other ties +#' in the network. +#' +#' All measures attempt to use as much information as they are offered, +#' including whether the networks are directed, weighted, or multimodal. +#' If this would produce unintended results, +#' first transform the salient properties using e.g. [to_undirected()] functions. +#' All centrality and centralization measures return normalized measures by default, +#' including for two-mode networks. +#' @template param_data +#' @family closeness +#' @family centrality +#' @template tie_measure +#' @param cutoff The maximum path length to consider when calculating betweenness. +#' If negative or NULL (the default), there's no limit to the path lengths considered. +NULL + +#' @rdname measure_centralities_close +#' @examples +#' (ec <- tie_by_closeness(ison_adolescents)) +#' ison_adolescents %>% mutate_ties(weight = ec) +#' @export +tie_by_closeness <- function(.data, normalized = TRUE){ + .data <- manynet::expect_ties(.data) + edge_adj <- manynet::to_ties(.data) + out <- node_by_closeness(edge_adj, normalized = normalized) + class(out) <- "numeric" + make_tie_measure(out, .data) +} + +# Closeness centralisation #### + +#' Measuring networks closeness-like centralisation +#' @name measure_centralisation_close +#' @description +#' - `net_by_closeness()` measures a network's closeness centralization. +#' - `net_by_reach()` measures a network's reach centralization. +#' - `net_by_harmonic()` measures a network's harmonic centralization. +#' +#' All measures attempt to use as much information as they are offered, +#' including whether the networks are directed, weighted, or multimodal. +#' If this would produce unintended results, +#' first transform the salient properties using e.g. [to_undirected()] functions. +#' All centrality and centralization measures return normalized measures by default, +#' including for two-mode networks. +#' @template param_data +#' @family closeness +#' @family centrality +#' @template net_measure +#' @param cutoff The maximum path length to consider when calculating betweenness. +#' If negative or NULL (the default), there's no limit to the path lengths considered. +NULL + +#' @rdname measure_centralisation_close +#' @examples +#' net_by_closeness(ison_southern_women, direction = "in") +#' @export +net_by_closeness <- function(.data, normalized = TRUE, + direction = c("all", "out", "in")){ + + .data <- manynet::expect_nodes(.data) + direction <- match.arg(direction) + graph <- manynet::as_igraph(.data) + + if (manynet::is_twomode(.data)) { + clcent <- node_by_closeness(graph, normalized = TRUE) + mode <- igraph::V(graph)$type + mode1 <- length(mode) - sum(mode) + mode2 <- sum(mode) + out <- list() + if (direction == "in") { + out$nodes1 <- sum(max(clcent[!mode]) - clcent[!mode])/(((mode1 - 2)*(mode1 - 1))/(2 * mode1 - 3)) + out$nodes2 <- sum(max(clcent[mode]) - clcent[mode])/(((mode2 - 2)*(mode2 - 1))/(2 * mode2 - 3)) + if (mode1 > mode2) { #28.43 + lhs <- ((mode2 - 1)*(mode1 - 2) / (2 * mode1 - 3)) + rhs <- ((mode2 - 1)*(mode1 - mode2) / (mode1 + mode2 - 2)) + out$nodes1 <- sum(max(clcent[!mode]) - clcent[!mode])/( lhs + rhs) # 0.2135 + } + if (mode2 > mode1) { + lhs <- ((mode1 - 1)*(mode2 - 2) / (2 * mode2 - 3)) + rhs <- ((mode1 - 1)*(mode2 - mode1) / (mode2 + mode1 - 2)) + out$nodes2 <- sum(max(clcent[mode]) - clcent[mode])/( lhs + rhs) + } + } else { + term1 <- 2*(mode1 - 1) * (mode2 + mode1 - 4)/(3*mode2 + 4*mode1 - 8) + term2 <- 2*(mode1 - 1) * (mode1 - 2)/(2*mode2 + 3*mode1 - 6) + term3 <- 2*(mode1 - 1) * (mode2 - mode1 + 1)/(2*mode2 + 3*mode1 - 4) + out$nodes1 <- sum(max(clcent[!mode]) - clcent) / sum(term1, term2, term3) + term1 <- 2*(mode2 - 1) * (mode1 + mode2 - 4)/(3*mode1 + 4*mode2 - 8) + term2 <- 2*(mode2 - 1) * (mode2 - 2)/(2*mode1 + 3*mode2 - 6) + term3 <- 2*(mode2 - 1) * (mode1 - mode2 + 1)/(2*mode1 + 3*mode2 - 4) + out$nodes2 <- sum(max(clcent[mode]) - clcent) / sum(term1, term2, term3) + + if (mode1 > mode2) { + term1 <- 2*(mode2 - 1) * (mode2 + mode1 - 2) / (3 * mode2 + 4 * mode1 - 8) + term2 <- 2*(mode1 - mode2) * (2 * mode2 - 1) / (5 * mode2 + 2 * mode1 - 6) + term3 <- 2*(mode2 - 1) * (mode1 - 2) / (2 * mode2 + 3 * mode1 - 6) + term4 <- 2 * (mode2 - 1) / (mode1 + 4 * mode2 - 4) + out$nodes1 <- sum(max(clcent[!mode]) - clcent) / sum(term1, term2, term3, term4) + } + if (mode2 > mode1) { + term1 <- 2*(mode1 - 1) * (mode1 + mode2 - 2) / (3 * mode1 + 4 * mode2 - 8) + term2 <- 2*(mode2 - mode1) * (2 * mode1 - 1) / (5 * mode1 + 2 * mode2 - 6) + term3 <- 2*(mode1 - 1) * (mode2 - 2) / (2 * mode1 + 3 * mode2 - 6) + term4 <- 2 * (mode1 - 1) / (mode2 + 4 * mode1 - 4) + out$nodes2 <- sum(max(clcent[mode]) - clcent) / sum(term1, term2, term3, term4) + } + } + out <- c("Mode 1" = out$nodes1, "Mode 2" = out$nodes2) + } else { + out <- igraph::centr_clo(graph = graph, + mode = direction, + normalized = normalized)$centralization + } + out <- make_network_measure(out, .data, call = deparse(sys.call())) + out +} + +#' @rdname measure_centralisation_close +#' @export +net_by_reach <- function(.data, normalized = TRUE, cutoff = 2){ + .data <- manynet::expect_nodes(.data) + reaches <- node_by_reach(.data, normalized = FALSE, cutoff = cutoff) + out <- sum(max(reaches) - reaches) + if(normalized) out <- out / sum(manynet::net_nodes(.data) - reaches) + make_network_measure(out, .data, call = deparse(sys.call())) +} + +#' @rdname measure_centralisation_close +#' @export +net_by_harmonic <- function(.data, normalized = TRUE, cutoff = 2){ + .data <- manynet::expect_nodes(.data) + harm <- node_by_harmonic(.data, normalized = FALSE, cutoff = cutoff) + out <- sum(max(harm) - harm) + if(normalized) out <- out / sum(manynet::net_nodes(.data) - harm) + make_network_measure(out, .data, call = deparse(sys.call())) +} + diff --git a/R/measure_centrality_degree.R b/R/measure_centrality_degree.R new file mode 100644 index 0000000..50639e3 --- /dev/null +++ b/R/measure_centrality_degree.R @@ -0,0 +1,317 @@ +# Degree-like centralities #### + +#' Measuring nodes degree-like centrality +#' @name measure_central_degree +#' @description +#' These functions calculate common degree-related centrality measures for one- and two-mode networks: +#' +#' - `node_by_degree()` measures the degree centrality of nodes in an unweighted network, +#' or weighted degree/strength of nodes in a weighted network; +#' there are several related shortcut functions: +#' - `node_by_deg()` returns the unnormalised results. +#' - `node_by_indegree()` returns the `direction = 'in'` results. +#' - `node_by_outdegree()` returns the `direction = 'out'` results. +#' - `node_by_multidegree()` measures the ratio between types of ties in a multiplex network. +#' - `node_by_posneg()` measures the PN (positive-negative) centrality of a signed network. +#' - `node_by_leverage()` measures the leverage centrality of nodes in a network. +#' +#' All measures attempt to use as much information as they are offered, +#' including whether the networks are directed, weighted, or multimodal. +#' If this would produce unintended results, +#' first transform the salient properties using e.g. [manynet::to_undirected()] functions. +#' All centrality and centralization measures return normalized measures by default, +#' including for two-mode networks. +#' @template param_data +#' @family degree +#' @family centrality +#' @template node_measure +#' @param normalized Logical scalar, whether the centrality scores are normalized. +#' Different denominators are used depending on whether the object is one-mode or two-mode, +#' the type of centrality, and other arguments. +#' @param alpha Numeric scalar, the positive tuning parameter introduced in +#' Opsahl et al (2010) for trading off between degree and strength centrality measures. +#' By default, `alpha = 0`, which ignores tie weights and the measure is solely based +#' upon degree (the number of ties). +#' `alpha = 1` ignores the number of ties and provides the sum of the tie weights +#' as strength centrality. +#' Values between 0 and 1 reflect different trade-offs in the relative contributions of +#' degree and strength to the final outcome, with 0.5 as the middle ground. +#' Values above 1 penalise for the number of ties. +#' Of two nodes with the same sum of tie weights, the node with fewer ties will obtain +#' the higher score. +#' This argument is ignored except in the case of a weighted network. +#' @param direction Character string, “out” bases the measure on outgoing ties, +#' “in” on incoming ties, and "all" on either/the sum of the two. +#' For two-mode networks, "all" uses as numerator the sum of differences +#' between the maximum centrality score for the mode +#' against all other centrality scores in the network, +#' whereas "in" uses as numerator the sum of differences +#' between the maximum centrality score for the mode +#' against only the centrality scores of the other nodes in that mode. +#' @return A single centralization score if the object was one-mode, +#' and two centralization scores if the object was two-mode. +#' @importFrom igraph graph_from_incidence_matrix is_bipartite degree V +#' @references +#' ## On multimodal centrality +#' Faust, Katherine. 1997. +#' "Centrality in affiliation networks." +#' _Social Networks_ 19(2): 157-191. +#' \doi{10.1016/S0378-8733(96)00300-0} +#' +#' Borgatti, Stephen P., and Martin G. Everett. 1997. +#' "Network analysis of 2-mode data." +#' _Social Networks_ 19(3): 243-270. +#' \doi{10.1016/S0378-8733(96)00301-2} +#' +#' Borgatti, Stephen P., and Daniel S. Halgin. 2011. +#' "Analyzing affiliation networks." +#' In _The SAGE Handbook of Social Network Analysis_, +#' edited by John Scott and Peter J. Carrington, 417–33. +#' London, UK: Sage. +#' \doi{10.4135/9781446294413.n28} +#' +#' ## On strength centrality +#' Opsahl, Tore, Filip Agneessens, and John Skvoretz. 2010. +#' "Node centrality in weighted networks: Generalizing degree and shortest paths." +#' _Social Networks_ 32, 245-251. +#' \doi{10.1016/j.socnet.2010.03.006} +#' @examples +#' node_by_degree(ison_southern_women) +#' @return Depending on how and what kind of an object is passed to the function, +#' the function will return a `tidygraph` object where the nodes have been updated +NULL + +#' @rdname measure_central_degree +#' @section Degree centrality: +#' `r manynet:::glossies$degree` +#' It is also sometimes called the valency of a node, \eqn{d(v)}. +#' The maximum degree in a network is often denoted \eqn{\Delta (G)} and +#' the minimum degree in a network \eqn{\delta (G)}. +#' The total degree of a network is the sum of all degrees, \eqn{\sum_v d(v)}. +#' The degree sequence is the set of all nodes' degrees, +#' ordered from largest to smallest. +#' Directed networks discriminate between +#' outdegree (degree of outgoing ties) and +#' indegree (degree of incoming ties). +#' @importFrom manynet as_igraph is_weighted tie_weights is_twomode is_complex +#' @export +node_by_degree <- function (.data, normalized = TRUE, alpha = 1, + direction = c("all","out","in")){ + .data <- manynet::expect_nodes(.data) + graph <- manynet::as_igraph(.data) + weights <- `if`(manynet::is_weighted(.data), + manynet::tie_weights(.data), NA) + direction <- match.arg(direction) + + # Do the calculations + if (manynet::is_twomode(graph) & normalized){ + degrees <- igraph::degree(graph = graph, + v = igraph::V(graph), + mode = direction, + loops = manynet::is_complex(.data)) + other_set_size <- ifelse(igraph::V(graph)$type, + sum(!igraph::V(graph)$type), + sum(igraph::V(graph)$type)) + out <- degrees/other_set_size + } else { + if (all(is.na(weights))) { + out <- igraph::degree(graph = graph, v = igraph::V(graph), + mode = direction, + loops = manynet::is_complex(.data), + normalized = normalized) + } + else { + ki <- igraph::degree(graph = graph, v = igraph::V(graph), + mode = direction, + loops = manynet::is_complex(.data)) + si <- igraph::strength(graph = graph, vids = igraph::V(graph), + mode = direction, + loops = manynet::is_complex(.data), weights = weights) + out <- ki * (si/ki)^alpha + out[is.nan(out)] <- 0 + if(normalized) out <- out/max(out) + } + } + out <- make_node_measure(out, .data) + out +} + +#' @rdname measure_central_degree +#' @export +node_by_deg <- function (.data, alpha = 0, direction = c("all","out","in")){ + .data <- manynet::expect_nodes(.data) + node_by_degree(.data, normalized = FALSE, alpha = alpha, direction = direction) +} + +#' @rdname measure_central_degree +#' @export +node_by_outdegree <- function (.data, normalized = TRUE, alpha = 0){ + .data <- manynet::expect_nodes(.data) + node_by_degree(.data, normalized = normalized, alpha = alpha, direction = "out") +} + +#' @rdname measure_central_degree +#' @export +node_by_indegree <- function (.data, normalized = TRUE, alpha = 0){ + .data <- manynet::expect_nodes(.data) + node_by_degree(.data, normalized = normalized, alpha = alpha, direction = "in") +} + +#' @rdname measure_central_degree +#' @param tie1 Character string indicating the first uniplex network. +#' @param tie2 Character string indicating the second uniplex network. +#' @export +node_by_multidegree <- function (.data, tie1, tie2){ + .data <- manynet::expect_nodes(.data) + stopifnot(manynet::is_multiplex(.data)) + out <- node_by_degree(manynet::to_uniplex(.data, tie1)) - + node_by_degree(manynet::to_uniplex(.data, tie2)) + make_node_measure(out, .data) +} + +#' @rdname measure_central_degree +#' @references +#' ## On signed centrality +#' Everett, Martin G., and Stephen P. Borgatti. 2014. +#' “Networks Containing Negative Ties.” +#' _Social Networks_ 38:111–20. +#' \doi{10.1016/j.socnet.2014.03.005} +#' @export +node_by_posneg <- function(.data){ + .data <- manynet::expect_nodes(.data) + stopifnot(manynet::is_signed(.data)) + pos <- manynet::as_matrix(manynet::to_unsigned(.data, keep = "positive")) + neg <- manynet::as_matrix(manynet::to_unsigned(.data, keep = "negative")) + nn <- manynet::net_nodes(.data) + pn <- pos-neg*2 + diag(pn) <- 0 + idmat <- diag(nn) + v1 <- matrix(1,nn,1) + out <- solve(idmat - ((pn%*%t(pn))/(4*(nn-1)^2))) %*% (idmat+( pn/(2*(nn-1)) )) %*% v1 + make_node_measure(out, .data) +} + +#' @rdname measure_central_degree +#' @section Leverage centrality: +#' Leverage centrality concerns the degree of a node compared with that of its +#' neighbours, \eqn{J}: +#' \deqn{C_L(i) = \frac{1}{d(i)} \sum_{j \in J(i)} \frac{d(i) - d(j)}{d(i) + d(j)}} +#' @references +#' ## On leverage centrality +#' Joyce, Karen E., Paul J. Laurienti, Jonathan H. Burdette, and Satoru Hayasaka. 2010. +#' "A New Measure of Centrality for Brain Networks". +#' _PLoS ONE_ 5(8): e12200. +#' \doi{10.1371/journal.pone.0012200} +#' @export +node_by_leverage <- function(.data){ + .data <- manynet::expect_nodes(.data) + out <- (node_by_deg(.data) - node_by_neighbours_degree(.data))/ + (node_by_deg(.data) + node_by_neighbours_degree(.data)) + make_node_measure(out, .data) +} + +# Degree-like centralities #### + +#' Measuring ties degree-like centrality +#' @name measure_centralities_degree +#' @description +#' `tie_by_degree()` measures the degree centrality of ties in a network +#' +#' All measures attempt to use as much information as they are offered, +#' including whether the networks are directed, weighted, or multimodal. +#' If this would produce unintended results, +#' first transform the salient properties using e.g. [to_undirected()] functions. +#' All centrality and centralization measures return normalized measures +#' by default, including for two-mode networks. +#' @template param_data +#' @family degree +#' @family centrality +#' @template tie_measure +NULL + +#' @rdname measure_centralities_degree +#' @examples +#' tie_by_degree(ison_adolescents) +#' @export +tie_by_degree <- function(.data, normalized = TRUE){ + .data <- manynet::expect_ties(.data) + edge_adj <- manynet::to_ties(.data) + out <- node_by_degree(edge_adj, normalized = normalized) + class(out) <- "numeric" + make_tie_measure(out, .data) +} + +# Degree centralisation #### + +#' Measuring networks degree-like centralisation +#' @name measure_centralisation_degree +#' @description +#' - `net_by_degree()` measures a network's degree centralization; +#' there are several related shortcut functions: +#' - `net_by_indegree()` returns the `direction = 'in'` results. +#' - `net_by_outdegree()` returns the `direction = 'out'` results. +#' +#' All measures attempt to use as much information as they are offered, +#' including whether the networks are directed, weighted, or multimodal. +#' If this would produce unintended results, +#' first transform the salient properties using e.g. [to_undirected()] functions. +#' All centrality and centralization measures return normalized measures +#' by default, including for two-mode networks. +#' @template param_data +#' @family degree +#' @family centrality +#' @template net_measure +NULL + +#' @rdname measure_centralisation_degree +#' @examples +#' net_by_degree(ison_southern_women, direction = "in") +#' @export +net_by_degree <- function(.data, normalized = TRUE, + direction = c("all", "out", "in")){ + + .data <- manynet::expect_nodes(.data) + direction <- match.arg(direction) + + if (manynet::is_twomode(.data)) { + mat <- manynet::as_matrix(.data) + mode <- c(rep(FALSE, nrow(mat)), rep(TRUE, ncol(mat))) + + out <- list() + if (direction == "all") { + if (!normalized) { + allcent <- c(rowSums(mat), colSums(mat)) + out$nodes1 <- sum(max(allcent[!mode]) - allcent)/((nrow(mat) + ncol(mat))*ncol(mat) - 2*(ncol(mat) + nrow(mat) - 1)) + out$nodes2 <- sum(max(allcent[mode]) - allcent)/((nrow(mat) + ncol(mat))*nrow(mat) - 2*(ncol(mat) + nrow(mat) - 1)) + } else if (normalized) { + allcent <- node_by_degree(.data, normalized = TRUE) + out$nodes1 <- sum(max(allcent[!mode]) - allcent)/((nrow(mat) + ncol(mat) - 1) - (ncol(mat) - 1) / nrow(mat) - (ncol(mat) + nrow(mat) - 1)/nrow(mat)) + out$nodes2 <- sum(max(allcent[mode]) - allcent)/((ncol(mat) + nrow(mat) - 1) - (nrow(mat) - 1) / ncol(mat) - (nrow(mat) + ncol(mat) - 1)/ncol(mat)) + } + } else if (direction == "in" | direction == "out") { + out$nodes1 <- sum(max(rowSums(mat)) - rowSums(mat))/((ncol(mat) - 1)*(nrow(mat) - 1)) + out$nodes2 <- sum(max(colSums(mat)) - colSums(mat))/((ncol(mat) - 1)*(nrow(mat) - 1)) + } + out <- c("Mode 1" = out$nodes1, "Mode 2" = out$nodes2) + } else { + out <- igraph::centr_degree(graph = .data, mode = direction, + normalized = normalized)$centralization + } + out <- make_network_measure(out, .data, call = deparse(sys.call())) + out +} + +#' @rdname measure_centralisation_degree +#' @export +net_by_outdegree <- function(.data, normalized = TRUE){ + .data <- manynet::expect_nodes(.data) + net_by_degree(.data, normalized = normalized, direction = "out") +} + +#' @rdname measure_centralisation_degree +#' @export +net_by_indegree <- function(.data, normalized = TRUE){ + .data <- manynet::expect_nodes(.data) + net_by_degree(.data, normalized = normalized, direction = "in") +} + diff --git a/R/measure_centrality_eigen.R b/R/measure_centrality_eigen.R new file mode 100644 index 0000000..a2c74d4 --- /dev/null +++ b/R/measure_centrality_eigen.R @@ -0,0 +1,330 @@ +# Eigenvector-like centralities #### + +#' Measuring nodes eigenvector-like centrality +#' @name measure_central_eigen +#' @description +#' These functions calculate common eigenvector-related centrality +#' measures, or walk-based eigenmeasures, for one- and two-mode networks: +#' +#' - `node_eigenvector()` measures the eigenvector centrality of nodes +#' in a network. +#' - `node_power()` measures the Bonacich, beta, or power centrality of +#' nodes in a network. +#' - `node_alpha()` measures the alpha or Katz centrality of nodes in a +#' network. +#' - `node_pagerank()` measures the pagerank centrality of nodes in a network. +#' - `node_hub()` measures how well nodes in a network serve as hubs pointing +#' to many authorities. +#' - `node_authority()` measures how well nodes in a network serve as +#' authorities from many hubs. +#' +#' All measures attempt to use as much information as they are offered, +#' including whether the networks are directed, weighted, or multimodal. +#' If this would produce unintended results, +#' first transform the salient properties using e.g. [to_undirected()] functions. +#' All centrality and centralization measures return normalized measures +#' by default, including for two-mode networks. +#' @template param_data +#' @family eigenvector +#' @family centrality +#' @template node_measure +NULL + +#' @rdname measure_central_eigen +#' @section Eigenvector centrality: +#' Eigenvector centrality operates as a measure of a node's influence in a network. +#' The idea is that being connected to well-connected others results in a higher score. +#' Each node's eigenvector centrality can be defined as: +#' \deqn{x_i = \frac{1}{\lambda} \sum_{j \in N} a_{i,j} x_j} +#' where \eqn{a_{i,j} = 1} if \eqn{i} is linked to \eqn{j} and 0 otherwise, +#' and \eqn{\lambda} is a constant representing the principal eigenvalue. +#' Rather than performing this iteration, +#' most routines solve the eigenvector equation \eqn{Ax = \lambda x}. +#' Note that since `{igraph}` v2.1.1, +#' the values will always be rescaled so that the maximum is 1. +#' @param scale Logical scalar, whether to rescale the vector so the maximum score is 1. +#' @details +#' We use `{igraph}` routines behind the scenes here for consistency and because they are often faster. +#' For example, `igraph::eigencentrality()` is approximately 25% faster than `sna::evcent()`. +#' @references +#' ## On eigenvector centrality +#' Bonacich, Phillip. 1991. +#' “Simultaneous Group and Individual Centralities.” +#' _Social Networks_ 13(2):155–68. +#' \doi{10.1016/0378-8733(91)90018-O} +#' @examples +#' node_by_eigenvector(ison_southern_women) +#' @export +node_by_eigenvector <- function(.data, normalized = TRUE, scale = TRUE){ + + .data <- manynet::expect_nodes(.data) + weights <- `if`(manynet::is_weighted(.data), + manynet::tie_weights(.data), NA) + graph <- manynet::as_igraph(.data) + + if(!normalized) manynet::snet_info("This function always returns a normalized value now.") + if(!scale) manynet::snet_info("This function always returns a scaled value now.") + + if(!manynet::is_connected(.data)) + manynet::snet_warn("Unconnected networks will only allow nodes from one component to have non-zero eigenvector scores.") + + # Do the calculations + if (!manynet::is_twomode(graph)){ + out <- igraph::eigen_centrality(graph = graph, + directed = manynet::is_directed(graph), + options = igraph::arpack_defaults())$vector + } else { + eigen1 <- manynet::to_mode1(graph) + eigen1 <- igraph::eigen_centrality(graph = eigen1, + directed = manynet::is_directed(eigen1), + options = igraph::arpack_defaults())$vector + eigen2 <- manynet::to_mode2(graph) + eigen2 <- igraph::eigen_centrality(graph = eigen2, + directed = manynet::is_directed(eigen2), + options = igraph::arpack_defaults())$vector + out <- c(eigen1, eigen2) + } + out <- make_node_measure(out, .data) + out +} + +#' @rdname measure_central_eigen +#' @param exponent Decay rate or attentuation factor for +#' the Bonacich power centrality score. +#' Can be positive or negative. +#' @section Power or beta (or Bonacich) centrality: +#' Power centrality includes an exponent that weights contributions to a node's +#' centrality based on how far away those other nodes are. +#' \deqn{c_b(i) = \sum A(i,j) (\alpha = \beta c(j))} +#' Where \eqn{\beta} is positive, this means being connected to central people +#' increases centrality. +#' Where \eqn{\beta} is negative, this means being connected to central people +#' decreases centrality +#' (and being connected to more peripheral actors increases centrality). +#' When \eqn{\beta = 0}, this is the outdegree. +#' \eqn{\alpha} is calculated to make sure the root mean square equals +#' the network size. +#' @references +#' ## On power centrality +#' Bonacich, Phillip. 1987. +#' “Power and Centrality: A Family of Measures.” +#' _The American Journal of Sociology_, 92(5): 1170–82. +#' \doi{10.1086/228631}. +#' @importFrom igraph power_centrality +#' @examples +#' node_by_power(ison_southern_women, exponent = 0.5) +#' @export +node_by_power <- function(.data, normalized = TRUE, scale = FALSE, exponent = 1){ + + .data <- manynet::expect_nodes(.data) + weights <- `if`(manynet::is_weighted(.data), + manynet::tie_weights(.data), NA) + graph <- manynet::as_igraph(.data) + + if(var(node_by_deg(graph))==0){ + manynet::snet_minor_info("All nodes have the same degree, so power centrality equals degree centrality.") + exponent <- 0 + } + + # Do the calculations + if (!manynet::is_twomode(graph)){ + out <- igraph::power_centrality(graph = graph, + exponent = exponent, + rescale = scale) + if (normalized) out <- out / sqrt(1/2) + } else { + eigen1 <- manynet::to_mode1(graph) + eigen1 <- igraph::power_centrality(graph = eigen1, + exponent = exponent, + rescale = scale) + eigen2 <- manynet::to_mode2(graph) + eigen2 <- igraph::power_centrality(graph = eigen2, + exponent = exponent, + rescale = scale) + out <- c(eigen1, eigen2) + if (normalized) out <- out / sqrt(1/2) + } + out <- make_node_measure(out, .data) + out +} + +#' @rdname measure_central_eigen +#' @param alpha A constant that trades off the importance of external influence against the importance of connection. +#' When \eqn{\alpha = 0}, only the external influence matters. +#' As \eqn{\alpha} gets larger, only the connectivity matters and we reduce to eigenvector centrality. +#' By default \eqn{\alpha = 0.85}. +#' @section Alpha centrality: +#' Alpha or Katz (or Katz-Bonacich) centrality operates better than +#' eigenvector centrality for directed networks because eigenvector centrality +#' will return 0s for all nodes not in the main strongly-connected component. +#' Each node's alpha centrality can be defined as: +#' \deqn{x_i = \frac{1}{\lambda} \sum_{j \in N} a_{i,j} x_j + e_i} +#' where \eqn{a_{i,j} = 1} if \eqn{i} is linked to \eqn{j} and 0 otherwise, +#' \eqn{\lambda} is a constant representing the principal eigenvalue, +#' and \eqn{e_i} is some external influence used to ensure that even nodes beyond the main +#' strongly connected component begin with some basic influence. +#' Note that many equations replace \eqn{\frac{1}{\lambda}} with \eqn{\alpha}, +#' hence the name. +#' +#' For example, if \eqn{\alpha = 0.5}, then each direct connection (or alter) would be worth \eqn{(0.5)^1 = 0.5}, +#' each secondary connection (or tertius) would be worth \eqn{(0.5)^2 = 0.25}, +#' each tertiary connection would be worth \eqn{(0.5)^3 = 0.125}, and so on. +#' +#' Rather than performing this iteration though, +#' most routines solve the equation \eqn{x = (I - \frac{1}{\lambda} A^T)^{-1} e}. +#' @importFrom igraph alpha_centrality +#' @references +#' ## On alpha centrality +#' Katz, Leo 1953. +#' "A new status index derived from sociometric analysis". +#' _Psychometrika_. 18(1): 39–43. +#' +#' Bonacich, P. and Lloyd, P. 2001. +#' “Eigenvector-like measures of centrality for asymmetric relations” +#' _Social Networks_. 23(3):191-201. +#' @export +node_by_alpha <- function(.data, alpha = 0.85){ + .data <- manynet::expect_nodes(.data) + make_node_measure(igraph::alpha_centrality(manynet::as_igraph(.data), + alpha = alpha), + .data) +} + +#' @rdname measure_central_eigen +#' @references +#' ## On pagerank centrality +#' Brin, Sergey and Page, Larry. 1998. +#' "The anatomy of a large-scale hypertextual web search engine". +#' _Proceedings of the 7th World-Wide Web Conference_. Brisbane, Australia. +#' @export +node_by_pagerank <- function(.data){ + .data <- manynet::expect_nodes(.data) + make_node_measure(igraph::page_rank(manynet::as_igraph(.data))$vector, + .data) +} + +#' @rdname measure_central_eigen +#' @references +#' ## On hub and authority centrality +#' Kleinberg, Jon. 1999. +#' "Authoritative sources in a hyperlinked environment". +#' _Journal of the ACM_ 46(5): 604–632. +#' \doi{10.1145/324133.324140} +#' @export +node_by_authority <- function(.data){ + .data <- manynet::expect_nodes(.data) + make_node_measure(igraph::hits_scores(manynet::as_igraph(.data))$authority, + .data) +} + +#' @rdname measure_central_eigen +#' @export +node_by_hub <- function(.data){ + .data <- manynet::expect_nodes(.data) + make_node_measure(igraph::hits_scores(manynet::as_igraph(.data))$hub, + .data) +} + +#' @rdname measure_central_eigen +#' @section Subgraph centrality: +#' Subgraph centrality measures the participation of a node in all subgraphs +#' in the network, giving higher weight to smaller subgraphs. +#' It is defined as: +#' \deqn{C_S(i) = \sum_{k=0}^{\infty} \frac{(A^k)_{ii}}{k!}} +#' where \eqn{(A^k)_{ii}} is the \eqn{i}th diagonal element of the \eqn{k}th power +#' of the adjacency matrix \eqn{A}, representing the number of closed walks +#' of length \eqn{k} starting and ending at node \eqn{i}. +#' Weighting by \eqn{\frac{1}{k!}} ensures that shorter walks contribute more +#' to the centrality score than longer walks. +#' +#' Subgraph centrality is a good choice of measure when the focus is on +#' local connectivity and clustering around a node, +#' as it captures the extent to which a node is embedded in tightly-knit +#' groups within the network. +#' Note though that because of the way spectral decomposition is used to +#' calculate this measure, this is not a good measure for very large graphs. +#' @references +#' ## On subgraph centrality +#' Estrada, Ernesto and Rodríguez-Velázquez, Juan A. 2005. +#' "Subgraph centrality in complex networks". +#' _Physical Review E_ 71(5): 056103. +#' \doi{10.1103/PhysRevE.71.056103} +#' @export +node_by_subgraph <- function(.data){ + .data <- manynet::expect_nodes(.data) + make_node_measure(igraph::subgraph_centrality(manynet::as_igraph(.data)), + .data) +} + +# Eigenvector-like centralities #### + +#' Measuring ties eigenvector-like centrality +#' @name measure_centralities_eigen +#' @description +#' `tie_by_eigenvector()` measures the eigenvector centrality of ties in a +#' network. +#' +#' All measures attempt to use as much information as they are offered, +#' including whether the networks are directed, weighted, or multimodal. +#' If this would produce unintended results, +#' first transform the salient properties using e.g. [to_undirected()] functions. +#' All centrality and centralization measures return normalized measures +#' by default, including for two-mode networks. +#' @template param_data +#' @family eigenvector +#' @family centrality +#' @template tie_measure +NULL + +#' @rdname measure_centralities_eigen +#' @examples +#' tie_by_eigenvector(ison_adolescents) +#' @export +tie_by_eigenvector <- function(.data, normalized = TRUE){ + .data <- manynet::expect_ties(.data) + edge_adj <- manynet::to_ties(.data) + out <- node_by_eigenvector(edge_adj, normalized = normalized) + class(out) <- "numeric" + make_tie_measure(out, .data) +} + +# Eigenvector centralisation #### + +#' Measuring networks eigenvector-like centralisation +#' @name measure_centralisation_eigen +#' @description +#' `net_by_eigenvector()` measures the eigenvector centralization for a +#' network. +#' +#' All measures attempt to use as much information as they are offered, +#' including whether the networks are directed, weighted, or multimodal. +#' If this would produce unintended results, +#' first transform the salient properties using e.g. [to_undirected()] functions. +#' All centrality and centralization measures return normalized measures +#' by default, including for two-mode networks. +#' @template param_data +#' @family eigenvector +#' @family centrality +#' @template net_measure +NULL + +#' @rdname measure_centralisation_eigen +#' @examples +#' net_by_eigenvector(ison_southern_women) +#' @export +net_by_eigenvector <- function(.data, normalized = TRUE){ + .data <- manynet::expect_nodes(.data) + if (manynet::is_twomode(.data)) { + out <- c(igraph::centr_eigen(manynet::as_igraph(manynet::to_mode1(.data)), + normalized = normalized)$centralization, + igraph::centr_eigen(manynet::as_igraph(manynet::to_mode2(.data)), + normalized = normalized)$centralization) + } else { + out <- igraph::centr_eigen(manynet::as_igraph(.data), + normalized = normalized)$centralization + } + out <- make_network_measure(out, .data, call = deparse(sys.call())) + out +} + + diff --git a/man/measure_central_between.Rd b/man/measure_central_between.Rd index 4178777..db2c7b7 100644 --- a/man/measure_central_between.Rd +++ b/man/measure_central_between.Rd @@ -1,14 +1,12 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/measure_centrality.R +% Please edit documentation in R/measure_centrality_betweenness.R \name{measure_central_between} \alias{measure_central_between} \alias{node_by_betweenness} \alias{node_by_induced} \alias{node_by_flow} \alias{node_by_stress} -\alias{tie_by_betweenness} -\alias{net_by_betweenness} -\title{Measures of betweenness-like centrality and centralisation} +\title{Measuring nodes betweenness-like centrality} \usage{ node_by_betweenness(.data, normalized = TRUE, cutoff = NULL) @@ -17,46 +15,31 @@ node_by_induced(.data, normalized = TRUE, cutoff = NULL) node_by_flow(.data, normalized = TRUE) node_by_stress(.data, normalized = TRUE) - -tie_by_betweenness(.data, normalized = TRUE) - -net_by_betweenness(.data, normalized = TRUE, direction = c("all", "out", "in")) } \arguments{ \item{.data}{A network object of class \code{mnet}, \code{igraph}, \code{tbl_graph}, \code{network}, or similar. For more information on the standard coercion possible, see \code{\link[manynet:manip_as]{manynet::as_tidygraph()}}.} -\item{normalized}{Logical scalar, whether the centrality scores are normalized. -Different denominators are used depending on whether the object is one-mode or two-mode, -the type of centrality, and other arguments.} - \item{cutoff}{The maximum path length to consider when calculating betweenness. If negative or NULL (the default), there's no limit to the path lengths considered.} - -\item{direction}{Character string, “out” bases the measure on outgoing ties, -“in” on incoming ties, and "all" on either/the sum of the two. -For two-mode networks, "all" uses as numerator the sum of differences -between the maximum centrality score for the mode -against all other centrality scores in the network, -whereas "in" uses as numerator the sum of differences -between the maximum centrality score for the mode -against only the centrality scores of the other nodes in that mode.} } \value{ -A numeric vector giving the betweenness centrality measure of each node. +A \code{node_measure} numeric vector the length of the nodes in the network, +providing the scores for each node. +If the network is labelled, +then the scores will be labelled with the nodes' names. } \description{ These functions calculate common betweenness-related centrality measures for one- and two-mode networks: \itemize{ -\item \code{node_betweenness()} measures the betweenness centralities of nodes in a network. -\item \code{node_induced()} measures the induced betweenness centralities of nodes in a network. -\item \code{node_flow()} measures the flow betweenness centralities of nodes in a network, +\item \code{node_by_betweenness()} measures the betweenness centralities of nodes in a network. +\item \code{node_by_induced()} measures the induced betweenness centralities of nodes in a network. +\item \code{node_by_flow()} measures the flow betweenness centralities of nodes in a network, which uses an electrical current model for information spreading in contrast to the shortest paths model used by normal betweenness centrality. -\item \code{node_stress()} measures the stress centrality of nodes in a network. -\item \code{tie_betweenness()} measures the number of shortest paths going through a tie. -\item \code{net_betweenness()} measures the betweenness centralization for a network. +\item \code{node_by_stress()} measures the stress centrality of nodes in a network. +\item \code{tie_by_betweenness()} measures the number of shortest paths going through a tie. } All measures attempt to use as much information as they are offered, @@ -101,9 +84,6 @@ nodes, and thus associated with bridging or spanning boundaries. \examples{ node_by_betweenness(ison_southern_women) node_by_induced(ison_adolescents) -(tb <- tie_by_betweenness(ison_adolescents)) -ison_adolescents \%>\% mutate_ties(weight = tb) -net_by_betweenness(ison_southern_women, direction = "in") } \references{ \subsection{On betweenness centrality}{ @@ -143,31 +123,86 @@ Shimbel, A. 1953. } } \seealso{ +Other betweenness: +\code{\link{measure_centralisation_between}}, +\code{\link{measure_centralities_between}} + Other centrality: \code{\link{measure_central_close}}, \code{\link{measure_central_degree}}, -\code{\link{measure_central_eigen}} +\code{\link{measure_central_eigen}}, +\code{\link{measure_centralisation_between}}, +\code{\link{measure_centralisation_close}}, +\code{\link{measure_centralisation_degree}}, +\code{\link{measure_centralisation_eigen}}, +\code{\link{measure_centralities_between}}, +\code{\link{measure_centralities_close}}, +\code{\link{measure_centralities_degree}}, +\code{\link{measure_centralities_eigen}} Other measures: -\code{\link{measure_assortativity}}, +\code{\link{measure_assort_net}}, +\code{\link{measure_assort_node}}, \code{\link{measure_breadth}}, +\code{\link{measure_broker_node}}, +\code{\link{measure_broker_tie}}, \code{\link{measure_brokerage}}, \code{\link{measure_central_close}}, \code{\link{measure_central_degree}}, \code{\link{measure_central_eigen}}, +\code{\link{measure_centralisation_between}}, +\code{\link{measure_centralisation_close}}, +\code{\link{measure_centralisation_degree}}, +\code{\link{measure_centralisation_eigen}}, +\code{\link{measure_centralities_between}}, +\code{\link{measure_centralities_close}}, +\code{\link{measure_centralities_degree}}, +\code{\link{measure_centralities_eigen}}, \code{\link{measure_closure}}, +\code{\link{measure_closure_node}}, \code{\link{measure_cohesion}}, +\code{\link{measure_core}}, \code{\link{measure_diffusion_infection}}, \code{\link{measure_diffusion_net}}, \code{\link{measure_diffusion_node}}, +\code{\link{measure_diverse_net}}, +\code{\link{measure_diverse_node}}, \code{\link{measure_features}}, \code{\link{measure_fragmentation}}, -\code{\link{measure_heterogeneity}}, \code{\link{measure_hierarchy}}, -\code{\link{measure_holes}}, -\code{\link{measure_periods}}, -\code{\link{member_diffusion}} +\code{\link{measure_periods}} + +Other nodal: +\code{\link{mark_core}}, +\code{\link{mark_degree}}, +\code{\link{mark_diff}}, +\code{\link{mark_nodes}}, +\code{\link{mark_select}}, +\code{\link{measure_assort_node}}, +\code{\link{measure_broker_node}}, +\code{\link{measure_brokerage}}, +\code{\link{measure_central_close}}, +\code{\link{measure_central_degree}}, +\code{\link{measure_central_eigen}}, +\code{\link{measure_closure_node}}, +\code{\link{measure_core}}, +\code{\link{measure_diffusion_node}}, +\code{\link{measure_diverse_node}}, +\code{\link{member_brokerage}}, +\code{\link{member_cliques}}, +\code{\link{member_community}}, +\code{\link{member_community_hier}}, +\code{\link{member_community_non}}, +\code{\link{member_components}}, +\code{\link{member_core}}, +\code{\link{member_diffusion}}, +\code{\link{member_equivalence}}, +\code{\link{motif_brokerage_node}}, +\code{\link{motif_exposure}}, +\code{\link{motif_node}}, +\code{\link{motif_path}} } \concept{betweenness} \concept{centrality} \concept{measures} +\concept{nodal} diff --git a/man/measure_central_close.Rd b/man/measure_central_close.Rd index 19d93fc..894f8d8 100644 --- a/man/measure_central_close.Rd +++ b/man/measure_central_close.Rd @@ -1,5 +1,5 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/measure_centrality.R +% Please edit documentation in R/measure_centrality_closeness.R \name{measure_central_close} \alias{measure_central_close} \alias{node_by_closeness} @@ -10,11 +10,7 @@ \alias{node_by_distance} \alias{node_by_vitality} \alias{node_by_randomwalk} -\alias{tie_by_closeness} -\alias{net_by_closeness} -\alias{net_by_reach} -\alias{net_by_harmonic} -\title{Measures of closeness-like centrality and centralisation} +\title{Measuring nodes closeness-like centrality} \usage{ node_by_closeness(.data, normalized = TRUE, direction = "out", cutoff = NULL) @@ -31,37 +27,22 @@ node_by_distance(.data, from, to, normalized = TRUE) node_by_vitality(.data, normalized = TRUE) node_by_randomwalk(.data, normalized = TRUE) - -tie_by_closeness(.data, normalized = TRUE) - -net_by_closeness(.data, normalized = TRUE, direction = c("all", "out", "in")) - -net_by_reach(.data, normalized = TRUE, cutoff = 2) - -net_by_harmonic(.data, normalized = TRUE, cutoff = 2) } \arguments{ \item{.data}{A network object of class \code{mnet}, \code{igraph}, \code{tbl_graph}, \code{network}, or similar. For more information on the standard coercion possible, see \code{\link[manynet:manip_as]{manynet::as_tidygraph()}}.} -\item{normalized}{Logical scalar, whether the centrality scores are normalized. -Different denominators are used depending on whether the object is one-mode or two-mode, -the type of centrality, and other arguments.} - -\item{direction}{Character string, “out” bases the measure on outgoing ties, -“in” on incoming ties, and "all" on either/the sum of the two. -For two-mode networks, "all" uses as numerator the sum of differences -between the maximum centrality score for the mode -against all other centrality scores in the network, -whereas "in" uses as numerator the sum of differences -between the maximum centrality score for the mode -against only the centrality scores of the other nodes in that mode.} - \item{cutoff}{Maximum path length to use during calculations.} \item{from, to}{Index or name of a node to calculate distances from or to.} } +\value{ +A \code{node_measure} numeric vector the length of the nodes in the network, +providing the scores for each node. +If the network is labelled, +then the scores will be labelled with the nodes' names. +} \description{ These functions calculate common closeness-related centrality measures that rely on path-length for one- and two-mode networks: @@ -82,11 +63,6 @@ given node. \item \code{node_by_vitality()} measures a network's closeness vitality centrality, or the change in closeness centrality between networks with and without a given node. -\item \code{tie_by_closeness()} measures the closeness of each tie to other ties -in the network. -\item \code{net_by_closeness()} measures a network's closeness centralization. -\item \code{net_by_reach()} measures a network's reach centralization. -\item \code{net_by_harmonic()} measures a network's harmonic centralization. } All measures attempt to use as much information as they are offered, @@ -192,9 +168,6 @@ where \eqn{H_{ji}} is the hitting time from node \eqn{j} to node \eqn{i}. \examples{ node_by_closeness(ison_southern_women) node_by_reach(ison_adolescents) -(ec <- tie_by_closeness(ison_adolescents)) -ison_adolescents \%>\% mutate_ties(weight = ec) -net_by_closeness(ison_southern_women, direction = "in") } \references{ \subsection{On closeness centrality}{ @@ -269,30 +242,86 @@ Noh, J.D. and R. Rieger. 2004. } } \seealso{ +Other closeness: +\code{\link{measure_centralisation_close}}, +\code{\link{measure_centralities_close}} + Other centrality: \code{\link{measure_central_between}}, \code{\link{measure_central_degree}}, -\code{\link{measure_central_eigen}} +\code{\link{measure_central_eigen}}, +\code{\link{measure_centralisation_between}}, +\code{\link{measure_centralisation_close}}, +\code{\link{measure_centralisation_degree}}, +\code{\link{measure_centralisation_eigen}}, +\code{\link{measure_centralities_between}}, +\code{\link{measure_centralities_close}}, +\code{\link{measure_centralities_degree}}, +\code{\link{measure_centralities_eigen}} Other measures: -\code{\link{measure_assortativity}}, +\code{\link{measure_assort_net}}, +\code{\link{measure_assort_node}}, \code{\link{measure_breadth}}, +\code{\link{measure_broker_node}}, +\code{\link{measure_broker_tie}}, \code{\link{measure_brokerage}}, \code{\link{measure_central_between}}, \code{\link{measure_central_degree}}, \code{\link{measure_central_eigen}}, +\code{\link{measure_centralisation_between}}, +\code{\link{measure_centralisation_close}}, +\code{\link{measure_centralisation_degree}}, +\code{\link{measure_centralisation_eigen}}, +\code{\link{measure_centralities_between}}, +\code{\link{measure_centralities_close}}, +\code{\link{measure_centralities_degree}}, +\code{\link{measure_centralities_eigen}}, \code{\link{measure_closure}}, +\code{\link{measure_closure_node}}, \code{\link{measure_cohesion}}, +\code{\link{measure_core}}, \code{\link{measure_diffusion_infection}}, \code{\link{measure_diffusion_net}}, \code{\link{measure_diffusion_node}}, +\code{\link{measure_diverse_net}}, +\code{\link{measure_diverse_node}}, \code{\link{measure_features}}, \code{\link{measure_fragmentation}}, -\code{\link{measure_heterogeneity}}, \code{\link{measure_hierarchy}}, -\code{\link{measure_holes}}, -\code{\link{measure_periods}}, -\code{\link{member_diffusion}} +\code{\link{measure_periods}} + +Other nodal: +\code{\link{mark_core}}, +\code{\link{mark_degree}}, +\code{\link{mark_diff}}, +\code{\link{mark_nodes}}, +\code{\link{mark_select}}, +\code{\link{measure_assort_node}}, +\code{\link{measure_broker_node}}, +\code{\link{measure_brokerage}}, +\code{\link{measure_central_between}}, +\code{\link{measure_central_degree}}, +\code{\link{measure_central_eigen}}, +\code{\link{measure_closure_node}}, +\code{\link{measure_core}}, +\code{\link{measure_diffusion_node}}, +\code{\link{measure_diverse_node}}, +\code{\link{member_brokerage}}, +\code{\link{member_cliques}}, +\code{\link{member_community}}, +\code{\link{member_community_hier}}, +\code{\link{member_community_non}}, +\code{\link{member_components}}, +\code{\link{member_core}}, +\code{\link{member_diffusion}}, +\code{\link{member_equivalence}}, +\code{\link{motif_brokerage_node}}, +\code{\link{motif_exposure}}, +\code{\link{motif_node}}, +\code{\link{motif_path}} } \concept{centrality} +\concept{closeness} \concept{measures} +\concept{nodal} diff --git a/man/measure_central_degree.Rd b/man/measure_central_degree.Rd index c458233..3e45570 100644 --- a/man/measure_central_degree.Rd +++ b/man/measure_central_degree.Rd @@ -1,5 +1,5 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/measure_centrality.R +% Please edit documentation in R/measure_centrality_degree.R \name{measure_central_degree} \alias{measure_central_degree} \alias{node_by_degree} @@ -9,11 +9,7 @@ \alias{node_by_multidegree} \alias{node_by_posneg} \alias{node_by_leverage} -\alias{tie_by_degree} -\alias{net_by_degree} -\alias{net_by_outdegree} -\alias{net_by_indegree} -\title{Measures of degree-like centrality and centralisation} +\title{Measuring nodes degree-like centrality} \usage{ node_by_degree( .data, @@ -33,14 +29,6 @@ node_by_multidegree(.data, tie1, tie2) node_by_posneg(.data) node_by_leverage(.data) - -tie_by_degree(.data, normalized = TRUE) - -net_by_degree(.data, normalized = TRUE, direction = c("all", "out", "in")) - -net_by_outdegree(.data, normalized = TRUE) - -net_by_indegree(.data, normalized = TRUE) } \arguments{ \item{.data}{A network object of class \code{mnet}, \code{igraph}, \code{tbl_graph}, \code{network}, or similar. @@ -78,6 +66,11 @@ against only the centrality scores of the other nodes in that mode.} \item{tie2}{Character string indicating the second uniplex network.} } \value{ +A \code{node_measure} numeric vector the length of the nodes in the network, +providing the scores for each node. +If the network is labelled, +then the scores will be labelled with the nodes' names. + A single centralization score if the object was one-mode, and two centralization scores if the object was two-mode. @@ -87,24 +80,17 @@ the function will return a \code{tidygraph} object where the nodes have been upd \description{ These functions calculate common degree-related centrality measures for one- and two-mode networks: \itemize{ -\item \code{node_degree()} measures the degree centrality of nodes in an unweighted network, +\item \code{node_by_degree()} measures the degree centrality of nodes in an unweighted network, or weighted degree/strength of nodes in a weighted network; there are several related shortcut functions: \itemize{ -\item \code{node_deg()} returns the unnormalised results. -\item \code{node_indegree()} returns the \code{direction = 'in'} results. -\item \code{node_outdegree()} returns the \code{direction = 'out'} results. -} -\item \code{node_multidegree()} measures the ratio between types of ties in a multiplex network. -\item \code{node_posneg()} measures the PN (positive-negative) centrality of a signed network. -\item \code{node_leverage()} measures the leverage centrality of nodes in a network. -\item \code{tie_degree()} measures the degree centrality of ties in a network -\item \code{net_degree()} measures a network's degree centralization; -there are several related shortcut functions: -\itemize{ -\item \code{net_indegree()} returns the \code{direction = 'out'} results. -\item \code{net_outdegree()} returns the \code{direction = 'out'} results. +\item \code{node_by_deg()} returns the unnormalised results. +\item \code{node_by_indegree()} returns the \code{direction = 'in'} results. +\item \code{node_by_outdegree()} returns the \code{direction = 'out'} results. } +\item \code{node_by_multidegree()} measures the ratio between types of ties in a multiplex network. +\item \code{node_by_posneg()} measures the PN (positive-negative) centrality of a signed network. +\item \code{node_by_leverage()} measures the leverage centrality of nodes in a network. } All measures attempt to use as much information as they are offered, @@ -137,8 +123,6 @@ neighbours, \eqn{J}: \examples{ node_by_degree(ison_southern_women) -tie_by_degree(ison_adolescents) -net_by_degree(ison_southern_women, direction = "in") } \references{ \subsection{On multimodal centrality}{ @@ -186,34 +170,87 @@ Joyce, Karen E., Paul J. Laurienti, Jonathan H. Burdette, and Satoru Hayasaka. 2 } } \seealso{ +Other degree: +\code{\link{mark_degree}}, +\code{\link{measure_centralisation_degree}}, +\code{\link{measure_centralities_degree}} + Other centrality: \code{\link{measure_central_between}}, \code{\link{measure_central_close}}, -\code{\link{measure_central_eigen}} +\code{\link{measure_central_eigen}}, +\code{\link{measure_centralisation_between}}, +\code{\link{measure_centralisation_close}}, +\code{\link{measure_centralisation_degree}}, +\code{\link{measure_centralisation_eigen}}, +\code{\link{measure_centralities_between}}, +\code{\link{measure_centralities_close}}, +\code{\link{measure_centralities_degree}}, +\code{\link{measure_centralities_eigen}} Other measures: -\code{\link{measure_assortativity}}, +\code{\link{measure_assort_net}}, +\code{\link{measure_assort_node}}, \code{\link{measure_breadth}}, +\code{\link{measure_broker_node}}, +\code{\link{measure_broker_tie}}, \code{\link{measure_brokerage}}, \code{\link{measure_central_between}}, \code{\link{measure_central_close}}, \code{\link{measure_central_eigen}}, +\code{\link{measure_centralisation_between}}, +\code{\link{measure_centralisation_close}}, +\code{\link{measure_centralisation_degree}}, +\code{\link{measure_centralisation_eigen}}, +\code{\link{measure_centralities_between}}, +\code{\link{measure_centralities_close}}, +\code{\link{measure_centralities_degree}}, +\code{\link{measure_centralities_eigen}}, \code{\link{measure_closure}}, +\code{\link{measure_closure_node}}, \code{\link{measure_cohesion}}, +\code{\link{measure_core}}, \code{\link{measure_diffusion_infection}}, \code{\link{measure_diffusion_net}}, \code{\link{measure_diffusion_node}}, +\code{\link{measure_diverse_net}}, +\code{\link{measure_diverse_node}}, \code{\link{measure_features}}, \code{\link{measure_fragmentation}}, -\code{\link{measure_heterogeneity}}, \code{\link{measure_hierarchy}}, -\code{\link{measure_holes}}, -\code{\link{measure_periods}}, -\code{\link{member_diffusion}} - -Other degree: -\code{\link{mark_degree}} +\code{\link{measure_periods}} + +Other nodal: +\code{\link{mark_core}}, +\code{\link{mark_degree}}, +\code{\link{mark_diff}}, +\code{\link{mark_nodes}}, +\code{\link{mark_select}}, +\code{\link{measure_assort_node}}, +\code{\link{measure_broker_node}}, +\code{\link{measure_brokerage}}, +\code{\link{measure_central_between}}, +\code{\link{measure_central_close}}, +\code{\link{measure_central_eigen}}, +\code{\link{measure_closure_node}}, +\code{\link{measure_core}}, +\code{\link{measure_diffusion_node}}, +\code{\link{measure_diverse_node}}, +\code{\link{member_brokerage}}, +\code{\link{member_cliques}}, +\code{\link{member_community}}, +\code{\link{member_community_hier}}, +\code{\link{member_community_non}}, +\code{\link{member_components}}, +\code{\link{member_core}}, +\code{\link{member_diffusion}}, +\code{\link{member_equivalence}}, +\code{\link{motif_brokerage_node}}, +\code{\link{motif_exposure}}, +\code{\link{motif_node}}, +\code{\link{motif_path}} } \concept{centrality} \concept{degree} \concept{measures} +\concept{nodal} diff --git a/man/measure_central_eigen.Rd b/man/measure_central_eigen.Rd index 3261673..1840667 100644 --- a/man/measure_central_eigen.Rd +++ b/man/measure_central_eigen.Rd @@ -1,5 +1,5 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/measure_centrality.R +% Please edit documentation in R/measure_centrality_eigen.R \name{measure_central_eigen} \alias{measure_central_eigen} \alias{node_by_eigenvector} @@ -9,9 +9,7 @@ \alias{node_by_authority} \alias{node_by_hub} \alias{node_by_subgraph} -\alias{tie_by_eigenvector} -\alias{net_by_eigenvector} -\title{Measures of eigenvector-like centrality and centralisation} +\title{Measuring nodes eigenvector-like centrality} \usage{ node_by_eigenvector(.data, normalized = TRUE, scale = TRUE) @@ -26,20 +24,12 @@ node_by_authority(.data) node_by_hub(.data) node_by_subgraph(.data) - -tie_by_eigenvector(.data, normalized = TRUE) - -net_by_eigenvector(.data, normalized = TRUE) } \arguments{ \item{.data}{A network object of class \code{mnet}, \code{igraph}, \code{tbl_graph}, \code{network}, or similar. For more information on the standard coercion possible, see \code{\link[manynet:manip_as]{manynet::as_tidygraph()}}.} -\item{normalized}{Logical scalar, whether the centrality scores are normalized. -Different denominators are used depending on whether the object is one-mode or two-mode, -the type of centrality, and other arguments.} - \item{scale}{Logical scalar, whether to rescale the vector so the maximum score is 1.} \item{exponent}{Decay rate or attentuation factor for @@ -52,9 +42,10 @@ As \eqn{\alpha} gets larger, only the connectivity matters and we reduce to eige By default \eqn{\alpha = 0.85}.} } \value{ -A numeric vector giving the eigenvector centrality measure of each node. - -A numeric vector giving each node's power centrality measure. +A \code{node_measure} numeric vector the length of the nodes in the network, +providing the scores for each node. +If the network is labelled, +then the scores will be labelled with the nodes' names. } \description{ These functions calculate common eigenvector-related centrality @@ -71,10 +62,6 @@ network. to many authorities. \item \code{node_authority()} measures how well nodes in a network serve as authorities from many hubs. -\item \code{tie_eigenvector()} measures the eigenvector centrality of ties in a -network. -\item \code{net_eigenvector()} measures the eigenvector centralization for a -network. } All measures attempt to use as much information as they are offered, @@ -162,8 +149,6 @@ calculate this measure, this is not a good measure for very large graphs. \examples{ node_by_eigenvector(ison_southern_women) node_by_power(ison_southern_women, exponent = 0.5) -tie_by_eigenvector(ison_adolescents) -net_by_eigenvector(ison_southern_women) } \references{ \subsection{On eigenvector centrality}{ @@ -217,30 +202,86 @@ Estrada, Ernesto and Rodríguez-Velázquez, Juan A. 2005. } } \seealso{ +Other eigenvector: +\code{\link{measure_centralisation_eigen}}, +\code{\link{measure_centralities_eigen}} + Other centrality: \code{\link{measure_central_between}}, \code{\link{measure_central_close}}, -\code{\link{measure_central_degree}} +\code{\link{measure_central_degree}}, +\code{\link{measure_centralisation_between}}, +\code{\link{measure_centralisation_close}}, +\code{\link{measure_centralisation_degree}}, +\code{\link{measure_centralisation_eigen}}, +\code{\link{measure_centralities_between}}, +\code{\link{measure_centralities_close}}, +\code{\link{measure_centralities_degree}}, +\code{\link{measure_centralities_eigen}} Other measures: -\code{\link{measure_assortativity}}, +\code{\link{measure_assort_net}}, +\code{\link{measure_assort_node}}, \code{\link{measure_breadth}}, +\code{\link{measure_broker_node}}, +\code{\link{measure_broker_tie}}, \code{\link{measure_brokerage}}, \code{\link{measure_central_between}}, \code{\link{measure_central_close}}, \code{\link{measure_central_degree}}, +\code{\link{measure_centralisation_between}}, +\code{\link{measure_centralisation_close}}, +\code{\link{measure_centralisation_degree}}, +\code{\link{measure_centralisation_eigen}}, +\code{\link{measure_centralities_between}}, +\code{\link{measure_centralities_close}}, +\code{\link{measure_centralities_degree}}, +\code{\link{measure_centralities_eigen}}, \code{\link{measure_closure}}, +\code{\link{measure_closure_node}}, \code{\link{measure_cohesion}}, +\code{\link{measure_core}}, \code{\link{measure_diffusion_infection}}, \code{\link{measure_diffusion_net}}, \code{\link{measure_diffusion_node}}, +\code{\link{measure_diverse_net}}, +\code{\link{measure_diverse_node}}, \code{\link{measure_features}}, \code{\link{measure_fragmentation}}, -\code{\link{measure_heterogeneity}}, \code{\link{measure_hierarchy}}, -\code{\link{measure_holes}}, -\code{\link{measure_periods}}, -\code{\link{member_diffusion}} +\code{\link{measure_periods}} + +Other nodal: +\code{\link{mark_core}}, +\code{\link{mark_degree}}, +\code{\link{mark_diff}}, +\code{\link{mark_nodes}}, +\code{\link{mark_select}}, +\code{\link{measure_assort_node}}, +\code{\link{measure_broker_node}}, +\code{\link{measure_brokerage}}, +\code{\link{measure_central_between}}, +\code{\link{measure_central_close}}, +\code{\link{measure_central_degree}}, +\code{\link{measure_closure_node}}, +\code{\link{measure_core}}, +\code{\link{measure_diffusion_node}}, +\code{\link{measure_diverse_node}}, +\code{\link{member_brokerage}}, +\code{\link{member_cliques}}, +\code{\link{member_community}}, +\code{\link{member_community_hier}}, +\code{\link{member_community_non}}, +\code{\link{member_components}}, +\code{\link{member_core}}, +\code{\link{member_diffusion}}, +\code{\link{member_equivalence}}, +\code{\link{motif_brokerage_node}}, +\code{\link{motif_exposure}}, +\code{\link{motif_node}}, +\code{\link{motif_path}} } \concept{centrality} +\concept{eigenvector} \concept{measures} +\concept{nodal} diff --git a/man/measure_centralisation_between.Rd b/man/measure_centralisation_between.Rd new file mode 100644 index 0000000..93ac427 --- /dev/null +++ b/man/measure_centralisation_between.Rd @@ -0,0 +1,86 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/measure_centrality_betweenness.R +\name{measure_centralisation_between} +\alias{measure_centralisation_between} +\alias{net_by_betweenness} +\title{Measuring networks betweenness-like centralisation} +\usage{ +net_by_betweenness(.data, normalized = TRUE, direction = c("all", "out", "in")) +} +\arguments{ +\item{.data}{A network object of class \code{mnet}, \code{igraph}, \code{tbl_graph}, \code{network}, or similar. +For more information on the standard coercion possible, +see \code{\link[manynet:manip_as]{manynet::as_tidygraph()}}.} + +\item{cutoff}{The maximum path length to consider when calculating betweenness. +If negative or NULL (the default), there's no limit to the path lengths considered.} +} +\value{ +A \code{network_measure} numeric score. +} +\description{ +\code{net_by_betweenness()} measures the betweenness centralization for a network. + +All measures attempt to use as much information as they are offered, +including whether the networks are directed, weighted, or multimodal. +If this would produce unintended results, +first transform the salient properties using e.g. \code{\link[manynet:manip_direction]{manynet::to_undirected()}} functions. +All centrality and centralization measures return normalized measures by default, +including for two-mode networks. +} +\examples{ +net_by_betweenness(ison_southern_women, direction = "in") +} +\seealso{ +Other betweenness: +\code{\link{measure_central_between}}, +\code{\link{measure_centralities_between}} + +Other centrality: +\code{\link{measure_central_between}}, +\code{\link{measure_central_close}}, +\code{\link{measure_central_degree}}, +\code{\link{measure_central_eigen}}, +\code{\link{measure_centralisation_close}}, +\code{\link{measure_centralisation_degree}}, +\code{\link{measure_centralisation_eigen}}, +\code{\link{measure_centralities_between}}, +\code{\link{measure_centralities_close}}, +\code{\link{measure_centralities_degree}}, +\code{\link{measure_centralities_eigen}} + +Other measures: +\code{\link{measure_assort_net}}, +\code{\link{measure_assort_node}}, +\code{\link{measure_breadth}}, +\code{\link{measure_broker_node}}, +\code{\link{measure_broker_tie}}, +\code{\link{measure_brokerage}}, +\code{\link{measure_central_between}}, +\code{\link{measure_central_close}}, +\code{\link{measure_central_degree}}, +\code{\link{measure_central_eigen}}, +\code{\link{measure_centralisation_close}}, +\code{\link{measure_centralisation_degree}}, +\code{\link{measure_centralisation_eigen}}, +\code{\link{measure_centralities_between}}, +\code{\link{measure_centralities_close}}, +\code{\link{measure_centralities_degree}}, +\code{\link{measure_centralities_eigen}}, +\code{\link{measure_closure}}, +\code{\link{measure_closure_node}}, +\code{\link{measure_cohesion}}, +\code{\link{measure_core}}, +\code{\link{measure_diffusion_infection}}, +\code{\link{measure_diffusion_net}}, +\code{\link{measure_diffusion_node}}, +\code{\link{measure_diverse_net}}, +\code{\link{measure_diverse_node}}, +\code{\link{measure_features}}, +\code{\link{measure_fragmentation}}, +\code{\link{measure_hierarchy}}, +\code{\link{measure_periods}} +} +\concept{betweenness} +\concept{centrality} +\concept{measures} diff --git a/man/measure_centralisation_close.Rd b/man/measure_centralisation_close.Rd new file mode 100644 index 0000000..7c400d7 --- /dev/null +++ b/man/measure_centralisation_close.Rd @@ -0,0 +1,96 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/measure_centrality_closeness.R +\name{measure_centralisation_close} +\alias{measure_centralisation_close} +\alias{net_by_closeness} +\alias{net_by_reach} +\alias{net_by_harmonic} +\title{Measuring networks closeness-like centralisation} +\usage{ +net_by_closeness(.data, normalized = TRUE, direction = c("all", "out", "in")) + +net_by_reach(.data, normalized = TRUE, cutoff = 2) + +net_by_harmonic(.data, normalized = TRUE, cutoff = 2) +} +\arguments{ +\item{.data}{A network object of class \code{mnet}, \code{igraph}, \code{tbl_graph}, \code{network}, or similar. +For more information on the standard coercion possible, +see \code{\link[manynet:manip_as]{manynet::as_tidygraph()}}.} + +\item{cutoff}{The maximum path length to consider when calculating betweenness. +If negative or NULL (the default), there's no limit to the path lengths considered.} +} +\value{ +A \code{network_measure} numeric score. +} +\description{ +\itemize{ +\item \code{net_by_closeness()} measures a network's closeness centralization. +\item \code{net_by_reach()} measures a network's reach centralization. +\item \code{net_by_harmonic()} measures a network's harmonic centralization. +} + +All measures attempt to use as much information as they are offered, +including whether the networks are directed, weighted, or multimodal. +If this would produce unintended results, +first transform the salient properties using e.g. \code{\link[manynet:manip_direction]{manynet::to_undirected()}} functions. +All centrality and centralization measures return normalized measures by default, +including for two-mode networks. +} +\examples{ +net_by_closeness(ison_southern_women, direction = "in") +} +\seealso{ +Other closeness: +\code{\link{measure_central_close}}, +\code{\link{measure_centralities_close}} + +Other centrality: +\code{\link{measure_central_between}}, +\code{\link{measure_central_close}}, +\code{\link{measure_central_degree}}, +\code{\link{measure_central_eigen}}, +\code{\link{measure_centralisation_between}}, +\code{\link{measure_centralisation_degree}}, +\code{\link{measure_centralisation_eigen}}, +\code{\link{measure_centralities_between}}, +\code{\link{measure_centralities_close}}, +\code{\link{measure_centralities_degree}}, +\code{\link{measure_centralities_eigen}} + +Other measures: +\code{\link{measure_assort_net}}, +\code{\link{measure_assort_node}}, +\code{\link{measure_breadth}}, +\code{\link{measure_broker_node}}, +\code{\link{measure_broker_tie}}, +\code{\link{measure_brokerage}}, +\code{\link{measure_central_between}}, +\code{\link{measure_central_close}}, +\code{\link{measure_central_degree}}, +\code{\link{measure_central_eigen}}, +\code{\link{measure_centralisation_between}}, +\code{\link{measure_centralisation_degree}}, +\code{\link{measure_centralisation_eigen}}, +\code{\link{measure_centralities_between}}, +\code{\link{measure_centralities_close}}, +\code{\link{measure_centralities_degree}}, +\code{\link{measure_centralities_eigen}}, +\code{\link{measure_closure}}, +\code{\link{measure_closure_node}}, +\code{\link{measure_cohesion}}, +\code{\link{measure_core}}, +\code{\link{measure_diffusion_infection}}, +\code{\link{measure_diffusion_net}}, +\code{\link{measure_diffusion_node}}, +\code{\link{measure_diverse_net}}, +\code{\link{measure_diverse_node}}, +\code{\link{measure_features}}, +\code{\link{measure_fragmentation}}, +\code{\link{measure_hierarchy}}, +\code{\link{measure_periods}} +} +\concept{centrality} +\concept{closeness} +\concept{measures} diff --git a/man/measure_centralisation_degree.Rd b/man/measure_centralisation_degree.Rd new file mode 100644 index 0000000..dc1e93f --- /dev/null +++ b/man/measure_centralisation_degree.Rd @@ -0,0 +1,97 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/measure_centrality_degree.R +\name{measure_centralisation_degree} +\alias{measure_centralisation_degree} +\alias{net_by_degree} +\alias{net_by_outdegree} +\alias{net_by_indegree} +\title{Measuring networks degree-like centralisation} +\usage{ +net_by_degree(.data, normalized = TRUE, direction = c("all", "out", "in")) + +net_by_outdegree(.data, normalized = TRUE) + +net_by_indegree(.data, normalized = TRUE) +} +\arguments{ +\item{.data}{A network object of class \code{mnet}, \code{igraph}, \code{tbl_graph}, \code{network}, or similar. +For more information on the standard coercion possible, +see \code{\link[manynet:manip_as]{manynet::as_tidygraph()}}.} +} +\value{ +A \code{network_measure} numeric score. +} +\description{ +\itemize{ +\item \code{net_by_degree()} measures a network's degree centralization; +there are several related shortcut functions: +\itemize{ +\item \code{net_by_indegree()} returns the \code{direction = 'in'} results. +\item \code{net_by_outdegree()} returns the \code{direction = 'out'} results. +} +} + +All measures attempt to use as much information as they are offered, +including whether the networks are directed, weighted, or multimodal. +If this would produce unintended results, +first transform the salient properties using e.g. \code{\link[manynet:manip_direction]{manynet::to_undirected()}} functions. +All centrality and centralization measures return normalized measures +by default, including for two-mode networks. +} +\examples{ +net_by_degree(ison_southern_women, direction = "in") +} +\seealso{ +Other degree: +\code{\link{mark_degree}}, +\code{\link{measure_central_degree}}, +\code{\link{measure_centralities_degree}} + +Other centrality: +\code{\link{measure_central_between}}, +\code{\link{measure_central_close}}, +\code{\link{measure_central_degree}}, +\code{\link{measure_central_eigen}}, +\code{\link{measure_centralisation_between}}, +\code{\link{measure_centralisation_close}}, +\code{\link{measure_centralisation_eigen}}, +\code{\link{measure_centralities_between}}, +\code{\link{measure_centralities_close}}, +\code{\link{measure_centralities_degree}}, +\code{\link{measure_centralities_eigen}} + +Other measures: +\code{\link{measure_assort_net}}, +\code{\link{measure_assort_node}}, +\code{\link{measure_breadth}}, +\code{\link{measure_broker_node}}, +\code{\link{measure_broker_tie}}, +\code{\link{measure_brokerage}}, +\code{\link{measure_central_between}}, +\code{\link{measure_central_close}}, +\code{\link{measure_central_degree}}, +\code{\link{measure_central_eigen}}, +\code{\link{measure_centralisation_between}}, +\code{\link{measure_centralisation_close}}, +\code{\link{measure_centralisation_eigen}}, +\code{\link{measure_centralities_between}}, +\code{\link{measure_centralities_close}}, +\code{\link{measure_centralities_degree}}, +\code{\link{measure_centralities_eigen}}, +\code{\link{measure_closure}}, +\code{\link{measure_closure_node}}, +\code{\link{measure_cohesion}}, +\code{\link{measure_core}}, +\code{\link{measure_diffusion_infection}}, +\code{\link{measure_diffusion_net}}, +\code{\link{measure_diffusion_node}}, +\code{\link{measure_diverse_net}}, +\code{\link{measure_diverse_node}}, +\code{\link{measure_features}}, +\code{\link{measure_fragmentation}}, +\code{\link{measure_hierarchy}}, +\code{\link{measure_periods}} +} +\concept{centrality} +\concept{degree} +\concept{measures} diff --git a/man/measure_centralisation_eigen.Rd b/man/measure_centralisation_eigen.Rd new file mode 100644 index 0000000..a66e5bd --- /dev/null +++ b/man/measure_centralisation_eigen.Rd @@ -0,0 +1,84 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/measure_centrality_eigen.R +\name{measure_centralisation_eigen} +\alias{measure_centralisation_eigen} +\alias{net_by_eigenvector} +\title{Measuring networks eigenvector-like centralisation} +\usage{ +net_by_eigenvector(.data, normalized = TRUE) +} +\arguments{ +\item{.data}{A network object of class \code{mnet}, \code{igraph}, \code{tbl_graph}, \code{network}, or similar. +For more information on the standard coercion possible, +see \code{\link[manynet:manip_as]{manynet::as_tidygraph()}}.} +} +\value{ +A \code{network_measure} numeric score. +} +\description{ +\code{net_by_eigenvector()} measures the eigenvector centralization for a +network. + +All measures attempt to use as much information as they are offered, +including whether the networks are directed, weighted, or multimodal. +If this would produce unintended results, +first transform the salient properties using e.g. \code{\link[manynet:manip_direction]{manynet::to_undirected()}} functions. +All centrality and centralization measures return normalized measures +by default, including for two-mode networks. +} +\examples{ +net_by_eigenvector(ison_southern_women) +} +\seealso{ +Other eigenvector: +\code{\link{measure_central_eigen}}, +\code{\link{measure_centralities_eigen}} + +Other centrality: +\code{\link{measure_central_between}}, +\code{\link{measure_central_close}}, +\code{\link{measure_central_degree}}, +\code{\link{measure_central_eigen}}, +\code{\link{measure_centralisation_between}}, +\code{\link{measure_centralisation_close}}, +\code{\link{measure_centralisation_degree}}, +\code{\link{measure_centralities_between}}, +\code{\link{measure_centralities_close}}, +\code{\link{measure_centralities_degree}}, +\code{\link{measure_centralities_eigen}} + +Other measures: +\code{\link{measure_assort_net}}, +\code{\link{measure_assort_node}}, +\code{\link{measure_breadth}}, +\code{\link{measure_broker_node}}, +\code{\link{measure_broker_tie}}, +\code{\link{measure_brokerage}}, +\code{\link{measure_central_between}}, +\code{\link{measure_central_close}}, +\code{\link{measure_central_degree}}, +\code{\link{measure_central_eigen}}, +\code{\link{measure_centralisation_between}}, +\code{\link{measure_centralisation_close}}, +\code{\link{measure_centralisation_degree}}, +\code{\link{measure_centralities_between}}, +\code{\link{measure_centralities_close}}, +\code{\link{measure_centralities_degree}}, +\code{\link{measure_centralities_eigen}}, +\code{\link{measure_closure}}, +\code{\link{measure_closure_node}}, +\code{\link{measure_cohesion}}, +\code{\link{measure_core}}, +\code{\link{measure_diffusion_infection}}, +\code{\link{measure_diffusion_net}}, +\code{\link{measure_diffusion_node}}, +\code{\link{measure_diverse_net}}, +\code{\link{measure_diverse_node}}, +\code{\link{measure_features}}, +\code{\link{measure_fragmentation}}, +\code{\link{measure_hierarchy}}, +\code{\link{measure_periods}} +} +\concept{centrality} +\concept{eigenvector} +\concept{measures} diff --git a/man/measure_centralities_between.Rd b/man/measure_centralities_between.Rd new file mode 100644 index 0000000..7370579 --- /dev/null +++ b/man/measure_centralities_between.Rd @@ -0,0 +1,101 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/measure_centrality_betweenness.R +\name{measure_centralities_between} +\alias{measure_centralities_between} +\alias{tie_by_betweenness} +\title{Measuring ties betweenness-like centrality} +\usage{ +tie_by_betweenness(.data, normalized = TRUE) +} +\arguments{ +\item{.data}{A network object of class \code{mnet}, \code{igraph}, \code{tbl_graph}, \code{network}, or similar. +For more information on the standard coercion possible, +see \code{\link[manynet:manip_as]{manynet::as_tidygraph()}}.} + +\item{cutoff}{The maximum path length to consider when calculating betweenness. +If negative or NULL (the default), there's no limit to the path lengths considered.} +} +\value{ +A \code{tie_measure} numeric vector the length of the ties in the network, +providing the scores for each tie. +If the network is labelled, +then the scores will be labelled with the ties' adjacent nodes' names. +} +\description{ +\code{tie_by_betweenness()} measures the number of shortest paths going through a tie. + +All measures attempt to use as much information as they are offered, +including whether the networks are directed, weighted, or multimodal. +If this would produce unintended results, +first transform the salient properties using e.g. \code{\link[manynet:manip_direction]{manynet::to_undirected()}} functions. +All centrality and centralization measures return normalized measures by default, +including for two-mode networks. +} +\examples{ +(tb <- tie_by_betweenness(ison_adolescents)) +ison_adolescents \%>\% mutate_ties(weight = tb) +} +\seealso{ +Other betweenness: +\code{\link{measure_central_between}}, +\code{\link{measure_centralisation_between}} + +Other centrality: +\code{\link{measure_central_between}}, +\code{\link{measure_central_close}}, +\code{\link{measure_central_degree}}, +\code{\link{measure_central_eigen}}, +\code{\link{measure_centralisation_between}}, +\code{\link{measure_centralisation_close}}, +\code{\link{measure_centralisation_degree}}, +\code{\link{measure_centralisation_eigen}}, +\code{\link{measure_centralities_close}}, +\code{\link{measure_centralities_degree}}, +\code{\link{measure_centralities_eigen}} + +Other measures: +\code{\link{measure_assort_net}}, +\code{\link{measure_assort_node}}, +\code{\link{measure_breadth}}, +\code{\link{measure_broker_node}}, +\code{\link{measure_broker_tie}}, +\code{\link{measure_brokerage}}, +\code{\link{measure_central_between}}, +\code{\link{measure_central_close}}, +\code{\link{measure_central_degree}}, +\code{\link{measure_central_eigen}}, +\code{\link{measure_centralisation_between}}, +\code{\link{measure_centralisation_close}}, +\code{\link{measure_centralisation_degree}}, +\code{\link{measure_centralisation_eigen}}, +\code{\link{measure_centralities_close}}, +\code{\link{measure_centralities_degree}}, +\code{\link{measure_centralities_eigen}}, +\code{\link{measure_closure}}, +\code{\link{measure_closure_node}}, +\code{\link{measure_cohesion}}, +\code{\link{measure_core}}, +\code{\link{measure_diffusion_infection}}, +\code{\link{measure_diffusion_net}}, +\code{\link{measure_diffusion_node}}, +\code{\link{measure_diverse_net}}, +\code{\link{measure_diverse_node}}, +\code{\link{measure_features}}, +\code{\link{measure_fragmentation}}, +\code{\link{measure_hierarchy}}, +\code{\link{measure_periods}} + +Other tie: +\code{\link{mark_dyads}}, +\code{\link{mark_tie_select}}, +\code{\link{mark_ties}}, +\code{\link{mark_triangles}}, +\code{\link{measure_broker_tie}}, +\code{\link{measure_centralities_close}}, +\code{\link{measure_centralities_degree}}, +\code{\link{measure_centralities_eigen}} +} +\concept{betweenness} +\concept{centrality} +\concept{measures} +\concept{tie} diff --git a/man/measure_centralities_close.Rd b/man/measure_centralities_close.Rd new file mode 100644 index 0000000..6b6b642 --- /dev/null +++ b/man/measure_centralities_close.Rd @@ -0,0 +1,102 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/measure_centrality_closeness.R +\name{measure_centralities_close} +\alias{measure_centralities_close} +\alias{tie_by_closeness} +\title{Measuring ties closeness-like centrality} +\usage{ +tie_by_closeness(.data, normalized = TRUE) +} +\arguments{ +\item{.data}{A network object of class \code{mnet}, \code{igraph}, \code{tbl_graph}, \code{network}, or similar. +For more information on the standard coercion possible, +see \code{\link[manynet:manip_as]{manynet::as_tidygraph()}}.} + +\item{cutoff}{The maximum path length to consider when calculating betweenness. +If negative or NULL (the default), there's no limit to the path lengths considered.} +} +\value{ +A \code{tie_measure} numeric vector the length of the ties in the network, +providing the scores for each tie. +If the network is labelled, +then the scores will be labelled with the ties' adjacent nodes' names. +} +\description{ +\code{tie_by_closeness()} measures the closeness of each tie to other ties +in the network. + +All measures attempt to use as much information as they are offered, +including whether the networks are directed, weighted, or multimodal. +If this would produce unintended results, +first transform the salient properties using e.g. \code{\link[manynet:manip_direction]{manynet::to_undirected()}} functions. +All centrality and centralization measures return normalized measures by default, +including for two-mode networks. +} +\examples{ +(ec <- tie_by_closeness(ison_adolescents)) +ison_adolescents \%>\% mutate_ties(weight = ec) +} +\seealso{ +Other closeness: +\code{\link{measure_central_close}}, +\code{\link{measure_centralisation_close}} + +Other centrality: +\code{\link{measure_central_between}}, +\code{\link{measure_central_close}}, +\code{\link{measure_central_degree}}, +\code{\link{measure_central_eigen}}, +\code{\link{measure_centralisation_between}}, +\code{\link{measure_centralisation_close}}, +\code{\link{measure_centralisation_degree}}, +\code{\link{measure_centralisation_eigen}}, +\code{\link{measure_centralities_between}}, +\code{\link{measure_centralities_degree}}, +\code{\link{measure_centralities_eigen}} + +Other measures: +\code{\link{measure_assort_net}}, +\code{\link{measure_assort_node}}, +\code{\link{measure_breadth}}, +\code{\link{measure_broker_node}}, +\code{\link{measure_broker_tie}}, +\code{\link{measure_brokerage}}, +\code{\link{measure_central_between}}, +\code{\link{measure_central_close}}, +\code{\link{measure_central_degree}}, +\code{\link{measure_central_eigen}}, +\code{\link{measure_centralisation_between}}, +\code{\link{measure_centralisation_close}}, +\code{\link{measure_centralisation_degree}}, +\code{\link{measure_centralisation_eigen}}, +\code{\link{measure_centralities_between}}, +\code{\link{measure_centralities_degree}}, +\code{\link{measure_centralities_eigen}}, +\code{\link{measure_closure}}, +\code{\link{measure_closure_node}}, +\code{\link{measure_cohesion}}, +\code{\link{measure_core}}, +\code{\link{measure_diffusion_infection}}, +\code{\link{measure_diffusion_net}}, +\code{\link{measure_diffusion_node}}, +\code{\link{measure_diverse_net}}, +\code{\link{measure_diverse_node}}, +\code{\link{measure_features}}, +\code{\link{measure_fragmentation}}, +\code{\link{measure_hierarchy}}, +\code{\link{measure_periods}} + +Other tie: +\code{\link{mark_dyads}}, +\code{\link{mark_tie_select}}, +\code{\link{mark_ties}}, +\code{\link{mark_triangles}}, +\code{\link{measure_broker_tie}}, +\code{\link{measure_centralities_between}}, +\code{\link{measure_centralities_degree}}, +\code{\link{measure_centralities_eigen}} +} +\concept{centrality} +\concept{closeness} +\concept{measures} +\concept{tie} diff --git a/man/measure_centralities_degree.Rd b/man/measure_centralities_degree.Rd new file mode 100644 index 0000000..a8d6cb5 --- /dev/null +++ b/man/measure_centralities_degree.Rd @@ -0,0 +1,98 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/measure_centrality_degree.R +\name{measure_centralities_degree} +\alias{measure_centralities_degree} +\alias{tie_by_degree} +\title{Measuring ties degree-like centrality} +\usage{ +tie_by_degree(.data, normalized = TRUE) +} +\arguments{ +\item{.data}{A network object of class \code{mnet}, \code{igraph}, \code{tbl_graph}, \code{network}, or similar. +For more information on the standard coercion possible, +see \code{\link[manynet:manip_as]{manynet::as_tidygraph()}}.} +} +\value{ +A \code{tie_measure} numeric vector the length of the ties in the network, +providing the scores for each tie. +If the network is labelled, +then the scores will be labelled with the ties' adjacent nodes' names. +} +\description{ +\code{tie_by_degree()} measures the degree centrality of ties in a network + +All measures attempt to use as much information as they are offered, +including whether the networks are directed, weighted, or multimodal. +If this would produce unintended results, +first transform the salient properties using e.g. \code{\link[manynet:manip_direction]{manynet::to_undirected()}} functions. +All centrality and centralization measures return normalized measures +by default, including for two-mode networks. +} +\examples{ +tie_by_degree(ison_adolescents) +} +\seealso{ +Other degree: +\code{\link{mark_degree}}, +\code{\link{measure_central_degree}}, +\code{\link{measure_centralisation_degree}} + +Other centrality: +\code{\link{measure_central_between}}, +\code{\link{measure_central_close}}, +\code{\link{measure_central_degree}}, +\code{\link{measure_central_eigen}}, +\code{\link{measure_centralisation_between}}, +\code{\link{measure_centralisation_close}}, +\code{\link{measure_centralisation_degree}}, +\code{\link{measure_centralisation_eigen}}, +\code{\link{measure_centralities_between}}, +\code{\link{measure_centralities_close}}, +\code{\link{measure_centralities_eigen}} + +Other measures: +\code{\link{measure_assort_net}}, +\code{\link{measure_assort_node}}, +\code{\link{measure_breadth}}, +\code{\link{measure_broker_node}}, +\code{\link{measure_broker_tie}}, +\code{\link{measure_brokerage}}, +\code{\link{measure_central_between}}, +\code{\link{measure_central_close}}, +\code{\link{measure_central_degree}}, +\code{\link{measure_central_eigen}}, +\code{\link{measure_centralisation_between}}, +\code{\link{measure_centralisation_close}}, +\code{\link{measure_centralisation_degree}}, +\code{\link{measure_centralisation_eigen}}, +\code{\link{measure_centralities_between}}, +\code{\link{measure_centralities_close}}, +\code{\link{measure_centralities_eigen}}, +\code{\link{measure_closure}}, +\code{\link{measure_closure_node}}, +\code{\link{measure_cohesion}}, +\code{\link{measure_core}}, +\code{\link{measure_diffusion_infection}}, +\code{\link{measure_diffusion_net}}, +\code{\link{measure_diffusion_node}}, +\code{\link{measure_diverse_net}}, +\code{\link{measure_diverse_node}}, +\code{\link{measure_features}}, +\code{\link{measure_fragmentation}}, +\code{\link{measure_hierarchy}}, +\code{\link{measure_periods}} + +Other tie: +\code{\link{mark_dyads}}, +\code{\link{mark_tie_select}}, +\code{\link{mark_ties}}, +\code{\link{mark_triangles}}, +\code{\link{measure_broker_tie}}, +\code{\link{measure_centralities_between}}, +\code{\link{measure_centralities_close}}, +\code{\link{measure_centralities_eigen}} +} +\concept{centrality} +\concept{degree} +\concept{measures} +\concept{tie} diff --git a/man/measure_centralities_eigen.Rd b/man/measure_centralities_eigen.Rd new file mode 100644 index 0000000..710609b --- /dev/null +++ b/man/measure_centralities_eigen.Rd @@ -0,0 +1,98 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/measure_centrality_eigen.R +\name{measure_centralities_eigen} +\alias{measure_centralities_eigen} +\alias{tie_by_eigenvector} +\title{Measuring ties eigenvector-like centrality} +\usage{ +tie_by_eigenvector(.data, normalized = TRUE) +} +\arguments{ +\item{.data}{A network object of class \code{mnet}, \code{igraph}, \code{tbl_graph}, \code{network}, or similar. +For more information on the standard coercion possible, +see \code{\link[manynet:manip_as]{manynet::as_tidygraph()}}.} +} +\value{ +A \code{tie_measure} numeric vector the length of the ties in the network, +providing the scores for each tie. +If the network is labelled, +then the scores will be labelled with the ties' adjacent nodes' names. +} +\description{ +\code{tie_by_eigenvector()} measures the eigenvector centrality of ties in a +network. + +All measures attempt to use as much information as they are offered, +including whether the networks are directed, weighted, or multimodal. +If this would produce unintended results, +first transform the salient properties using e.g. \code{\link[manynet:manip_direction]{manynet::to_undirected()}} functions. +All centrality and centralization measures return normalized measures +by default, including for two-mode networks. +} +\examples{ +tie_by_eigenvector(ison_adolescents) +} +\seealso{ +Other eigenvector: +\code{\link{measure_central_eigen}}, +\code{\link{measure_centralisation_eigen}} + +Other centrality: +\code{\link{measure_central_between}}, +\code{\link{measure_central_close}}, +\code{\link{measure_central_degree}}, +\code{\link{measure_central_eigen}}, +\code{\link{measure_centralisation_between}}, +\code{\link{measure_centralisation_close}}, +\code{\link{measure_centralisation_degree}}, +\code{\link{measure_centralisation_eigen}}, +\code{\link{measure_centralities_between}}, +\code{\link{measure_centralities_close}}, +\code{\link{measure_centralities_degree}} + +Other measures: +\code{\link{measure_assort_net}}, +\code{\link{measure_assort_node}}, +\code{\link{measure_breadth}}, +\code{\link{measure_broker_node}}, +\code{\link{measure_broker_tie}}, +\code{\link{measure_brokerage}}, +\code{\link{measure_central_between}}, +\code{\link{measure_central_close}}, +\code{\link{measure_central_degree}}, +\code{\link{measure_central_eigen}}, +\code{\link{measure_centralisation_between}}, +\code{\link{measure_centralisation_close}}, +\code{\link{measure_centralisation_degree}}, +\code{\link{measure_centralisation_eigen}}, +\code{\link{measure_centralities_between}}, +\code{\link{measure_centralities_close}}, +\code{\link{measure_centralities_degree}}, +\code{\link{measure_closure}}, +\code{\link{measure_closure_node}}, +\code{\link{measure_cohesion}}, +\code{\link{measure_core}}, +\code{\link{measure_diffusion_infection}}, +\code{\link{measure_diffusion_net}}, +\code{\link{measure_diffusion_node}}, +\code{\link{measure_diverse_net}}, +\code{\link{measure_diverse_node}}, +\code{\link{measure_features}}, +\code{\link{measure_fragmentation}}, +\code{\link{measure_hierarchy}}, +\code{\link{measure_periods}} + +Other tie: +\code{\link{mark_dyads}}, +\code{\link{mark_tie_select}}, +\code{\link{mark_ties}}, +\code{\link{mark_triangles}}, +\code{\link{measure_broker_tie}}, +\code{\link{measure_centralities_between}}, +\code{\link{measure_centralities_close}}, +\code{\link{measure_centralities_degree}} +} +\concept{centrality} +\concept{eigenvector} +\concept{measures} +\concept{tie} From 47b599e18f98b79c71cb8db9977248d99e4c6e47 Mon Sep 17 00:00:00 2001 From: James Hollway Date: Sat, 21 Mar 2026 10:58:31 +0100 Subject: [PATCH 08/35] Added net/node/tie roxygen templates --- man-roxygen/net_measure.R | 3 +++ man-roxygen/net_motif.R | 4 ++++ man-roxygen/node_mark.R | 1 + man-roxygen/node_measure.R | 7 +++++++ man-roxygen/node_member.R | 7 +++++++ man-roxygen/node_motif.R | 8 ++++++++ man-roxygen/tie_mark.R | 1 + man-roxygen/tie_measure.R | 7 +++++++ 8 files changed, 38 insertions(+) create mode 100644 man-roxygen/net_measure.R create mode 100644 man-roxygen/net_motif.R create mode 100644 man-roxygen/node_measure.R create mode 100644 man-roxygen/node_member.R create mode 100644 man-roxygen/node_motif.R create mode 100644 man-roxygen/tie_measure.R diff --git a/man-roxygen/net_measure.R b/man-roxygen/net_measure.R new file mode 100644 index 0000000..720aef7 --- /dev/null +++ b/man-roxygen/net_measure.R @@ -0,0 +1,3 @@ +#' @family measures +#' @returns +#' A `network_measure` numeric score. diff --git a/man-roxygen/net_motif.R b/man-roxygen/net_motif.R new file mode 100644 index 0000000..acf94b4 --- /dev/null +++ b/man-roxygen/net_motif.R @@ -0,0 +1,4 @@ +#' @family motifs +#' @returns +#' A `network_motif` tibble with one row and a column for each motif type, +#' giving the count of each motif in the network. diff --git a/man-roxygen/node_mark.R b/man-roxygen/node_mark.R index 74b4422..5741472 100644 --- a/man-roxygen/node_mark.R +++ b/man-roxygen/node_mark.R @@ -1,5 +1,6 @@ #' @template data #' @family marks +#' @family nodal #' @returns #' A `node_mark` logical vector the length of the nodes in the network, #' giving either TRUE or FALSE for each node depending on diff --git a/man-roxygen/node_measure.R b/man-roxygen/node_measure.R new file mode 100644 index 0000000..3f93514 --- /dev/null +++ b/man-roxygen/node_measure.R @@ -0,0 +1,7 @@ +#' @family measures +#' @family nodal +#' @returns +#' A `node_measure` numeric vector the length of the nodes in the network, +#' providing the scores for each node. +#' If the network is labelled, +#' then the scores will be labelled with the nodes' names. diff --git a/man-roxygen/node_member.R b/man-roxygen/node_member.R new file mode 100644 index 0000000..3671f81 --- /dev/null +++ b/man-roxygen/node_member.R @@ -0,0 +1,7 @@ +#' @family memberships +#' @family nodal +#' @returns +#' A `node_member` character vector the length of the nodes in the network, +#' of group memberships "A", "B", etc for each node. +#' If the network is labelled, +#' then the assignments will be labelled with the nodes' names. diff --git a/man-roxygen/node_motif.R b/man-roxygen/node_motif.R new file mode 100644 index 0000000..9a27941 --- /dev/null +++ b/man-roxygen/node_motif.R @@ -0,0 +1,8 @@ +#' @family motifs +#' @family nodal +#' @returns +#' A `node_motif` tibble with one row for each node in the network and +#' a column for each motif type, +#' giving the count of each motif in which each node participates. +#' If the network is labelled, +#' then the node names will be in a column named `names`. diff --git a/man-roxygen/tie_mark.R b/man-roxygen/tie_mark.R index 8c75b0a..e81c8b8 100644 --- a/man-roxygen/tie_mark.R +++ b/man-roxygen/tie_mark.R @@ -1,4 +1,5 @@ #' @family marks +#' @family tie #' @returns #' A `tie_mark` logical vector the length of the ties in the network, #' giving either TRUE or FALSE for each tie depending on diff --git a/man-roxygen/tie_measure.R b/man-roxygen/tie_measure.R new file mode 100644 index 0000000..b02204d --- /dev/null +++ b/man-roxygen/tie_measure.R @@ -0,0 +1,7 @@ +#' @family measures +#' @family tie +#' @returns +#' A `tie_measure` numeric vector the length of the ties in the network, +#' providing the scores for each tie. +#' If the network is labelled, +#' then the scores will be labelled with the ties' adjacent nodes' names. From 685288485488a832ab8061a9e6c572217627ea44 Mon Sep 17 00:00:00 2001 From: James Hollway Date: Sat, 21 Mar 2026 18:00:03 +0100 Subject: [PATCH 09/35] Added param templates --- man-roxygen/param_attr.R | 1 + man-roxygen/param_data.R | 3 +++ man-roxygen/param_dir.R | 3 +++ man-roxygen/param_memb.R | 5 +++++ man-roxygen/param_norm.R | 4 ++++ man-roxygen/param_select.R | 1 + 6 files changed, 17 insertions(+) create mode 100644 man-roxygen/param_attr.R create mode 100644 man-roxygen/param_data.R create mode 100644 man-roxygen/param_dir.R create mode 100644 man-roxygen/param_memb.R create mode 100644 man-roxygen/param_norm.R create mode 100644 man-roxygen/param_select.R diff --git a/man-roxygen/param_attr.R b/man-roxygen/param_attr.R new file mode 100644 index 0000000..2092cea --- /dev/null +++ b/man-roxygen/param_attr.R @@ -0,0 +1 @@ +#' @param attribute Name of a nodal attribute, mark, measure, or membership vector. diff --git a/man-roxygen/param_data.R b/man-roxygen/param_data.R new file mode 100644 index 0000000..86fcf38 --- /dev/null +++ b/man-roxygen/param_data.R @@ -0,0 +1,3 @@ +#' @param .data A network object of class `mnet`, `igraph`, `tbl_graph`, `network`, or similar. +#' For more information on the standard coercion possible, +#' see [manynet::as_tidygraph()]. diff --git a/man-roxygen/param_dir.R b/man-roxygen/param_dir.R new file mode 100644 index 0000000..a5be178 --- /dev/null +++ b/man-roxygen/param_dir.R @@ -0,0 +1,3 @@ +#' @param direction Character string, “out” bases the measure on outgoing ties, +#' “in” on incoming ties, and "all" on either/the sum of the two. +#' By default "all". diff --git a/man-roxygen/param_memb.R b/man-roxygen/param_memb.R new file mode 100644 index 0000000..991f2d7 --- /dev/null +++ b/man-roxygen/param_memb.R @@ -0,0 +1,5 @@ +#' @param membership A character vector of categorical membership. +#' This is a vector of the same length as the number of nodes in the network, +#' where each element is a character string indicating the membership of the corresponding node. +#' While this may often be a vector created using `node_in_*()` functions, +#' it can be any character vector that assigns nodes to groups or categories. diff --git a/man-roxygen/param_norm.R b/man-roxygen/param_norm.R new file mode 100644 index 0000000..606b359 --- /dev/null +++ b/man-roxygen/param_norm.R @@ -0,0 +1,4 @@ +#' @param normalized Logical scalar, whether scores are normalized. +#' Different denominators may be used depending on the measure, +#' whether the object is one-mode or two-mode, and other arguments. +#' By default TRUE. diff --git a/man-roxygen/param_select.R b/man-roxygen/param_select.R new file mode 100644 index 0000000..e4170dd --- /dev/null +++ b/man-roxygen/param_select.R @@ -0,0 +1 @@ +#' @param select Number of elements to select (as TRUE). From 8d174a82302e6a92ba50cea43716114710e087c2 Mon Sep 17 00:00:00 2001 From: James Hollway Date: Sat, 21 Mar 2026 18:00:53 +0100 Subject: [PATCH 10/35] Added param templating to centrality documentation --- ...eenness.R => measure_centrality_between.R} | 8 +++--- R/measure_centrality_closeness.R | 9 ++++--- R/measure_centrality_degree.R | 27 +++++++++---------- R/measure_centrality_eigen.R | 3 +++ man/measure_central_between.Rd | 9 +++++-- man/measure_central_close.Rd | 11 +++++++- man/measure_central_degree.Rd | 22 +++++---------- man/measure_central_eigen.Rd | 7 ++++- man/measure_centralisation_between.Rd | 12 ++++++--- man/measure_centralisation_close.Rd | 9 +++++++ man/measure_centralisation_degree.Rd | 16 +++++++++++ man/measure_centralisation_eigen.Rd | 5 ++++ man/measure_centralities_between.Rd | 10 ++++--- man/measure_centralities_close.Rd | 8 +++--- man/measure_centralities_degree.Rd | 7 ++++- man/measure_centralities_eigen.Rd | 7 ++++- 16 files changed, 116 insertions(+), 54 deletions(-) rename R/{measure_centrality_betweenness.R => measure_centrality_between.R} (97%) diff --git a/R/measure_centrality_betweenness.R b/R/measure_centrality_between.R similarity index 97% rename from R/measure_centrality_betweenness.R rename to R/measure_centrality_between.R index 36eca9d..1a5c482 100644 --- a/R/measure_centrality_betweenness.R +++ b/R/measure_centrality_between.R @@ -20,6 +20,7 @@ #' All centrality and centralization measures return normalized measures by default, #' including for two-mode networks. #' @template param_data +#' @template param_norm #' @family betweenness #' @family centrality #' @template node_measure @@ -168,11 +169,10 @@ node_by_stress <- function(.data, normalized = TRUE){ #' All centrality and centralization measures return normalized measures by default, #' including for two-mode networks. #' @template param_data +#' @template param_norm #' @family betweenness #' @family centrality #' @template tie_measure -#' @param cutoff The maximum path length to consider when calculating betweenness. -#' If negative or NULL (the default), there's no limit to the path lengths considered. NULL #' @rdname measure_centralities_between @@ -205,11 +205,11 @@ tie_by_betweenness <- function(.data, normalized = TRUE){ #' All centrality and centralization measures return normalized measures by default, #' including for two-mode networks. #' @template param_data +#' @template param_norm +#' @template param_dir #' @family betweenness #' @family centrality #' @template net_measure -#' @param cutoff The maximum path length to consider when calculating betweenness. -#' If negative or NULL (the default), there's no limit to the path lengths considered. NULL #' @rdname measure_centralisation_between diff --git a/R/measure_centrality_closeness.R b/R/measure_centrality_closeness.R index 6c0dc62..f118004 100644 --- a/R/measure_centrality_closeness.R +++ b/R/measure_centrality_closeness.R @@ -1,6 +1,7 @@ # Closeness-like centralities #### #' Measuring nodes closeness-like centrality +#' @name measure_central_close #' @description #' These functions calculate common closeness-related centrality measures #' that rely on path-length for one- and two-mode networks: @@ -28,8 +29,9 @@ #' first transform the salient properties using e.g. [to_undirected()] functions. #' All centrality and centralization measures return normalized measures by default, #' including for two-mode networks. -#' @name measure_central_close #' @template param_data +#' @template param_norm +#' @template param_dir #' @family closeness #' @family centrality #' @template node_measure @@ -350,11 +352,10 @@ node_by_randomwalk <- function(.data, normalized = TRUE){ #' All centrality and centralization measures return normalized measures by default, #' including for two-mode networks. #' @template param_data +#' @template param_norm #' @family closeness #' @family centrality #' @template tie_measure -#' @param cutoff The maximum path length to consider when calculating betweenness. -#' If negative or NULL (the default), there's no limit to the path lengths considered. NULL #' @rdname measure_centralities_close @@ -386,6 +387,8 @@ tie_by_closeness <- function(.data, normalized = TRUE){ #' All centrality and centralization measures return normalized measures by default, #' including for two-mode networks. #' @template param_data +#' @template param_norm +#' @template param_dir #' @family closeness #' @family centrality #' @template net_measure diff --git a/R/measure_centrality_degree.R b/R/measure_centrality_degree.R index 50639e3..a3bf827 100644 --- a/R/measure_centrality_degree.R +++ b/R/measure_centrality_degree.R @@ -22,12 +22,11 @@ #' All centrality and centralization measures return normalized measures by default, #' including for two-mode networks. #' @template param_data +#' @template param_norm +#' @template param_dir #' @family degree #' @family centrality #' @template node_measure -#' @param normalized Logical scalar, whether the centrality scores are normalized. -#' Different denominators are used depending on whether the object is one-mode or two-mode, -#' the type of centrality, and other arguments. #' @param alpha Numeric scalar, the positive tuning parameter introduced in #' Opsahl et al (2010) for trading off between degree and strength centrality measures. #' By default, `alpha = 0`, which ignores tie weights and the measure is solely based @@ -40,16 +39,6 @@ #' Of two nodes with the same sum of tie weights, the node with fewer ties will obtain #' the higher score. #' This argument is ignored except in the case of a weighted network. -#' @param direction Character string, “out” bases the measure on outgoing ties, -#' “in” on incoming ties, and "all" on either/the sum of the two. -#' For two-mode networks, "all" uses as numerator the sum of differences -#' between the maximum centrality score for the mode -#' against all other centrality scores in the network, -#' whereas "in" uses as numerator the sum of differences -#' between the maximum centrality score for the mode -#' against only the centrality scores of the other nodes in that mode. -#' @return A single centralization score if the object was one-mode, -#' and two centralization scores if the object was two-mode. #' @importFrom igraph graph_from_incidence_matrix is_bipartite degree V #' @references #' ## On multimodal centrality @@ -77,8 +66,6 @@ #' \doi{10.1016/j.socnet.2010.03.006} #' @examples #' node_by_degree(ison_southern_women) -#' @return Depending on how and what kind of an object is passed to the function, -#' the function will return a `tidygraph` object where the nodes have been updated NULL #' @rdname measure_central_degree @@ -224,6 +211,7 @@ node_by_leverage <- function(.data){ #' All centrality and centralization measures return normalized measures #' by default, including for two-mode networks. #' @template param_data +#' @template param_norm #' @family degree #' @family centrality #' @template tie_measure @@ -257,7 +245,16 @@ tie_by_degree <- function(.data, normalized = TRUE){ #' first transform the salient properties using e.g. [to_undirected()] functions. #' All centrality and centralization measures return normalized measures #' by default, including for two-mode networks. +#' +#' For two-mode networks, "all" uses as numerator the sum of differences +#' between the maximum centrality score for the mode +#' against all other centrality scores in the network, +#' whereas "in" uses as numerator the sum of differences +#' between the maximum centrality score for the mode +#' against only the centrality scores of the other nodes in that mode. #' @template param_data +#' @template param_norm +#' @template param_dir #' @family degree #' @family centrality #' @template net_measure diff --git a/R/measure_centrality_eigen.R b/R/measure_centrality_eigen.R index a2c74d4..bad7b6e 100644 --- a/R/measure_centrality_eigen.R +++ b/R/measure_centrality_eigen.R @@ -25,6 +25,7 @@ #' All centrality and centralization measures return normalized measures #' by default, including for two-mode networks. #' @template param_data +#' @template param_norm #' @family eigenvector #' @family centrality #' @template node_measure @@ -271,6 +272,7 @@ node_by_subgraph <- function(.data){ #' All centrality and centralization measures return normalized measures #' by default, including for two-mode networks. #' @template param_data +#' @template param_norm #' @family eigenvector #' @family centrality #' @template tie_measure @@ -303,6 +305,7 @@ tie_by_eigenvector <- function(.data, normalized = TRUE){ #' All centrality and centralization measures return normalized measures #' by default, including for two-mode networks. #' @template param_data +#' @template param_norm #' @family eigenvector #' @family centrality #' @template net_measure diff --git a/man/measure_central_between.Rd b/man/measure_central_between.Rd index db2c7b7..176569c 100644 --- a/man/measure_central_between.Rd +++ b/man/measure_central_between.Rd @@ -1,5 +1,5 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/measure_centrality_betweenness.R +% Please edit documentation in R/measure_centrality_between.R \name{measure_central_between} \alias{measure_central_between} \alias{node_by_betweenness} @@ -21,6 +21,11 @@ node_by_stress(.data, normalized = TRUE) For more information on the standard coercion possible, see \code{\link[manynet:manip_as]{manynet::as_tidygraph()}}.} +\item{normalized}{Logical scalar, whether scores are normalized. +Different denominators may be used depending on the measure, +whether the object is one-mode or two-mode, and other arguments. +By default TRUE.} + \item{cutoff}{The maximum path length to consider when calculating betweenness. If negative or NULL (the default), there's no limit to the path lengths considered.} } @@ -177,7 +182,7 @@ Other nodal: \code{\link{mark_degree}}, \code{\link{mark_diff}}, \code{\link{mark_nodes}}, -\code{\link{mark_select}}, +\code{\link{mark_select_node}}, \code{\link{measure_assort_node}}, \code{\link{measure_broker_node}}, \code{\link{measure_brokerage}}, diff --git a/man/measure_central_close.Rd b/man/measure_central_close.Rd index 894f8d8..97b172c 100644 --- a/man/measure_central_close.Rd +++ b/man/measure_central_close.Rd @@ -33,6 +33,15 @@ node_by_randomwalk(.data, normalized = TRUE) For more information on the standard coercion possible, see \code{\link[manynet:manip_as]{manynet::as_tidygraph()}}.} +\item{normalized}{Logical scalar, whether scores are normalized. +Different denominators may be used depending on the measure, +whether the object is one-mode or two-mode, and other arguments. +By default TRUE.} + +\item{direction}{Character string, “out” bases the measure on outgoing ties, +“in” on incoming ties, and "all" on either/the sum of the two. +By default "all".} + \item{cutoff}{Maximum path length to use during calculations.} \item{from, to}{Index or name of a node to calculate distances from or to.} @@ -296,7 +305,7 @@ Other nodal: \code{\link{mark_degree}}, \code{\link{mark_diff}}, \code{\link{mark_nodes}}, -\code{\link{mark_select}}, +\code{\link{mark_select_node}}, \code{\link{measure_assort_node}}, \code{\link{measure_broker_node}}, \code{\link{measure_brokerage}}, diff --git a/man/measure_central_degree.Rd b/man/measure_central_degree.Rd index 3e45570..aa7325b 100644 --- a/man/measure_central_degree.Rd +++ b/man/measure_central_degree.Rd @@ -35,9 +35,10 @@ node_by_leverage(.data) For more information on the standard coercion possible, see \code{\link[manynet:manip_as]{manynet::as_tidygraph()}}.} -\item{normalized}{Logical scalar, whether the centrality scores are normalized. -Different denominators are used depending on whether the object is one-mode or two-mode, -the type of centrality, and other arguments.} +\item{normalized}{Logical scalar, whether scores are normalized. +Different denominators may be used depending on the measure, +whether the object is one-mode or two-mode, and other arguments. +By default TRUE.} \item{alpha}{Numeric scalar, the positive tuning parameter introduced in Opsahl et al (2010) for trading off between degree and strength centrality measures. @@ -54,12 +55,7 @@ This argument is ignored except in the case of a weighted network.} \item{direction}{Character string, “out” bases the measure on outgoing ties, “in” on incoming ties, and "all" on either/the sum of the two. -For two-mode networks, "all" uses as numerator the sum of differences -between the maximum centrality score for the mode -against all other centrality scores in the network, -whereas "in" uses as numerator the sum of differences -between the maximum centrality score for the mode -against only the centrality scores of the other nodes in that mode.} +By default "all".} \item{tie1}{Character string indicating the first uniplex network.} @@ -70,12 +66,6 @@ A \code{node_measure} numeric vector the length of the nodes in the network, providing the scores for each node. If the network is labelled, then the scores will be labelled with the nodes' names. - -A single centralization score if the object was one-mode, -and two centralization scores if the object was two-mode. - -Depending on how and what kind of an object is passed to the function, -the function will return a \code{tidygraph} object where the nodes have been updated } \description{ These functions calculate common degree-related centrality measures for one- and two-mode networks: @@ -225,7 +215,7 @@ Other nodal: \code{\link{mark_degree}}, \code{\link{mark_diff}}, \code{\link{mark_nodes}}, -\code{\link{mark_select}}, +\code{\link{mark_select_node}}, \code{\link{measure_assort_node}}, \code{\link{measure_broker_node}}, \code{\link{measure_brokerage}}, diff --git a/man/measure_central_eigen.Rd b/man/measure_central_eigen.Rd index 1840667..15bb68c 100644 --- a/man/measure_central_eigen.Rd +++ b/man/measure_central_eigen.Rd @@ -30,6 +30,11 @@ node_by_subgraph(.data) For more information on the standard coercion possible, see \code{\link[manynet:manip_as]{manynet::as_tidygraph()}}.} +\item{normalized}{Logical scalar, whether scores are normalized. +Different denominators may be used depending on the measure, +whether the object is one-mode or two-mode, and other arguments. +By default TRUE.} + \item{scale}{Logical scalar, whether to rescale the vector so the maximum score is 1.} \item{exponent}{Decay rate or attentuation factor for @@ -256,7 +261,7 @@ Other nodal: \code{\link{mark_degree}}, \code{\link{mark_diff}}, \code{\link{mark_nodes}}, -\code{\link{mark_select}}, +\code{\link{mark_select_node}}, \code{\link{measure_assort_node}}, \code{\link{measure_broker_node}}, \code{\link{measure_brokerage}}, diff --git a/man/measure_centralisation_between.Rd b/man/measure_centralisation_between.Rd index 93ac427..8d46bea 100644 --- a/man/measure_centralisation_between.Rd +++ b/man/measure_centralisation_between.Rd @@ -1,5 +1,5 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/measure_centrality_betweenness.R +% Please edit documentation in R/measure_centrality_between.R \name{measure_centralisation_between} \alias{measure_centralisation_between} \alias{net_by_betweenness} @@ -12,8 +12,14 @@ net_by_betweenness(.data, normalized = TRUE, direction = c("all", "out", "in")) For more information on the standard coercion possible, see \code{\link[manynet:manip_as]{manynet::as_tidygraph()}}.} -\item{cutoff}{The maximum path length to consider when calculating betweenness. -If negative or NULL (the default), there's no limit to the path lengths considered.} +\item{normalized}{Logical scalar, whether scores are normalized. +Different denominators may be used depending on the measure, +whether the object is one-mode or two-mode, and other arguments. +By default TRUE.} + +\item{direction}{Character string, “out” bases the measure on outgoing ties, +“in” on incoming ties, and "all" on either/the sum of the two. +By default "all".} } \value{ A \code{network_measure} numeric score. diff --git a/man/measure_centralisation_close.Rd b/man/measure_centralisation_close.Rd index 7c400d7..1180a78 100644 --- a/man/measure_centralisation_close.Rd +++ b/man/measure_centralisation_close.Rd @@ -18,6 +18,15 @@ net_by_harmonic(.data, normalized = TRUE, cutoff = 2) For more information on the standard coercion possible, see \code{\link[manynet:manip_as]{manynet::as_tidygraph()}}.} +\item{normalized}{Logical scalar, whether scores are normalized. +Different denominators may be used depending on the measure, +whether the object is one-mode or two-mode, and other arguments. +By default TRUE.} + +\item{direction}{Character string, “out” bases the measure on outgoing ties, +“in” on incoming ties, and "all" on either/the sum of the two. +By default "all".} + \item{cutoff}{The maximum path length to consider when calculating betweenness. If negative or NULL (the default), there's no limit to the path lengths considered.} } diff --git a/man/measure_centralisation_degree.Rd b/man/measure_centralisation_degree.Rd index dc1e93f..f28b738 100644 --- a/man/measure_centralisation_degree.Rd +++ b/man/measure_centralisation_degree.Rd @@ -17,6 +17,15 @@ net_by_indegree(.data, normalized = TRUE) \item{.data}{A network object of class \code{mnet}, \code{igraph}, \code{tbl_graph}, \code{network}, or similar. For more information on the standard coercion possible, see \code{\link[manynet:manip_as]{manynet::as_tidygraph()}}.} + +\item{normalized}{Logical scalar, whether scores are normalized. +Different denominators may be used depending on the measure, +whether the object is one-mode or two-mode, and other arguments. +By default TRUE.} + +\item{direction}{Character string, “out” bases the measure on outgoing ties, +“in” on incoming ties, and "all" on either/the sum of the two. +By default "all".} } \value{ A \code{network_measure} numeric score. @@ -37,6 +46,13 @@ If this would produce unintended results, first transform the salient properties using e.g. \code{\link[manynet:manip_direction]{manynet::to_undirected()}} functions. All centrality and centralization measures return normalized measures by default, including for two-mode networks. + +For two-mode networks, "all" uses as numerator the sum of differences +between the maximum centrality score for the mode +against all other centrality scores in the network, +whereas "in" uses as numerator the sum of differences +between the maximum centrality score for the mode +against only the centrality scores of the other nodes in that mode. } \examples{ net_by_degree(ison_southern_women, direction = "in") diff --git a/man/measure_centralisation_eigen.Rd b/man/measure_centralisation_eigen.Rd index a66e5bd..af21767 100644 --- a/man/measure_centralisation_eigen.Rd +++ b/man/measure_centralisation_eigen.Rd @@ -11,6 +11,11 @@ net_by_eigenvector(.data, normalized = TRUE) \item{.data}{A network object of class \code{mnet}, \code{igraph}, \code{tbl_graph}, \code{network}, or similar. For more information on the standard coercion possible, see \code{\link[manynet:manip_as]{manynet::as_tidygraph()}}.} + +\item{normalized}{Logical scalar, whether scores are normalized. +Different denominators may be used depending on the measure, +whether the object is one-mode or two-mode, and other arguments. +By default TRUE.} } \value{ A \code{network_measure} numeric score. diff --git a/man/measure_centralities_between.Rd b/man/measure_centralities_between.Rd index 7370579..af6b74a 100644 --- a/man/measure_centralities_between.Rd +++ b/man/measure_centralities_between.Rd @@ -1,5 +1,5 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/measure_centrality_betweenness.R +% Please edit documentation in R/measure_centrality_between.R \name{measure_centralities_between} \alias{measure_centralities_between} \alias{tie_by_betweenness} @@ -12,8 +12,10 @@ tie_by_betweenness(.data, normalized = TRUE) For more information on the standard coercion possible, see \code{\link[manynet:manip_as]{manynet::as_tidygraph()}}.} -\item{cutoff}{The maximum path length to consider when calculating betweenness. -If negative or NULL (the default), there's no limit to the path lengths considered.} +\item{normalized}{Logical scalar, whether scores are normalized. +Different denominators may be used depending on the measure, +whether the object is one-mode or two-mode, and other arguments. +By default TRUE.} } \value{ A \code{tie_measure} numeric vector the length of the ties in the network, @@ -87,7 +89,7 @@ Other measures: Other tie: \code{\link{mark_dyads}}, -\code{\link{mark_tie_select}}, +\code{\link{mark_select_tie}}, \code{\link{mark_ties}}, \code{\link{mark_triangles}}, \code{\link{measure_broker_tie}}, diff --git a/man/measure_centralities_close.Rd b/man/measure_centralities_close.Rd index 6b6b642..a009a5b 100644 --- a/man/measure_centralities_close.Rd +++ b/man/measure_centralities_close.Rd @@ -12,8 +12,10 @@ tie_by_closeness(.data, normalized = TRUE) For more information on the standard coercion possible, see \code{\link[manynet:manip_as]{manynet::as_tidygraph()}}.} -\item{cutoff}{The maximum path length to consider when calculating betweenness. -If negative or NULL (the default), there's no limit to the path lengths considered.} +\item{normalized}{Logical scalar, whether scores are normalized. +Different denominators may be used depending on the measure, +whether the object is one-mode or two-mode, and other arguments. +By default TRUE.} } \value{ A \code{tie_measure} numeric vector the length of the ties in the network, @@ -88,7 +90,7 @@ Other measures: Other tie: \code{\link{mark_dyads}}, -\code{\link{mark_tie_select}}, +\code{\link{mark_select_tie}}, \code{\link{mark_ties}}, \code{\link{mark_triangles}}, \code{\link{measure_broker_tie}}, diff --git a/man/measure_centralities_degree.Rd b/man/measure_centralities_degree.Rd index a8d6cb5..2f4fb07 100644 --- a/man/measure_centralities_degree.Rd +++ b/man/measure_centralities_degree.Rd @@ -11,6 +11,11 @@ tie_by_degree(.data, normalized = TRUE) \item{.data}{A network object of class \code{mnet}, \code{igraph}, \code{tbl_graph}, \code{network}, or similar. For more information on the standard coercion possible, see \code{\link[manynet:manip_as]{manynet::as_tidygraph()}}.} + +\item{normalized}{Logical scalar, whether scores are normalized. +Different denominators may be used depending on the measure, +whether the object is one-mode or two-mode, and other arguments. +By default TRUE.} } \value{ A \code{tie_measure} numeric vector the length of the ties in the network, @@ -84,7 +89,7 @@ Other measures: Other tie: \code{\link{mark_dyads}}, -\code{\link{mark_tie_select}}, +\code{\link{mark_select_tie}}, \code{\link{mark_ties}}, \code{\link{mark_triangles}}, \code{\link{measure_broker_tie}}, diff --git a/man/measure_centralities_eigen.Rd b/man/measure_centralities_eigen.Rd index 710609b..5f237f1 100644 --- a/man/measure_centralities_eigen.Rd +++ b/man/measure_centralities_eigen.Rd @@ -11,6 +11,11 @@ tie_by_eigenvector(.data, normalized = TRUE) \item{.data}{A network object of class \code{mnet}, \code{igraph}, \code{tbl_graph}, \code{network}, or similar. For more information on the standard coercion possible, see \code{\link[manynet:manip_as]{manynet::as_tidygraph()}}.} + +\item{normalized}{Logical scalar, whether scores are normalized. +Different denominators may be used depending on the measure, +whether the object is one-mode or two-mode, and other arguments. +By default TRUE.} } \value{ A \code{tie_measure} numeric vector the length of the ties in the network, @@ -84,7 +89,7 @@ Other measures: Other tie: \code{\link{mark_dyads}}, -\code{\link{mark_tie_select}}, +\code{\link{mark_select_tie}}, \code{\link{mark_ties}}, \code{\link{mark_triangles}}, \code{\link{measure_broker_tie}}, From 8ec3b070717b290b18a04fb98791d824d5352a38 Mon Sep 17 00:00:00 2001 From: James Hollway Date: Sat, 21 Mar 2026 18:02:18 +0100 Subject: [PATCH 11/35] Fixed brokerage documentation, added param_memb where required --- R/measure_holes.R | 59 +++++++----- R/motif_brokerage.R | 72 ++++++++------ man/measure_broker_node.Rd | 184 ++++++++++++++++++++++++++++++++++++ man/measure_broker_tie.Rd | 78 +++++++++++++++ man/measure_brokerage.Rd | 74 +++++++++++++-- man/motif_brokerage.Rd | 66 ------------- man/motif_brokerage_net.Rd | 55 +++++++++++ man/motif_brokerage_node.Rd | 103 ++++++++++++++++++++ 8 files changed, 563 insertions(+), 128 deletions(-) create mode 100644 man/measure_broker_node.Rd create mode 100644 man/measure_broker_tie.Rd delete mode 100644 man/motif_brokerage.Rd create mode 100644 man/motif_brokerage_net.Rd create mode 100644 man/motif_brokerage_node.Rd diff --git a/R/measure_holes.R b/R/measure_holes.R index 1ca28ac..dde079c 100644 --- a/R/measure_holes.R +++ b/R/measure_holes.R @@ -1,23 +1,22 @@ -#' Measures of structural holes -#' +# Nodal holes #### + +#' Measuring nodes brokerage +#' @name measure_broker_node #' @description #' These function provide different measures of the degree to which nodes #' fill structural holes, as outlined in Burt (1992): #' -#' - `node_bridges()` measures the sum of bridges to which each node +#' - `node_by_bridges()` measures the sum of bridges to which each node #' is adjacent. -#' - `node_redundancy()` measures the redundancy of each nodes' contacts. -#' - `node_effsize()` measures nodes' effective size. -#' - `node_efficiency()` measures nodes' efficiency. -#' - `node_constraint()` measures nodes' constraint scores for one-mode networks +#' - `node_by_redundancy()` measures the redundancy of each nodes' contacts. +#' - `node_by_effsize()` measures nodes' effective size. +#' - `node_by_efficiency()` measures nodes' efficiency. +#' - `node_by_constraint()` measures nodes' constraint scores for one-mode networks #' according to Burt (1992) and for two-mode networks according to Hollway et al (2020). -#' - `node_hierarchy()` measures nodes' exposure to hierarchy, +#' - `node_by_hierarchy()` measures nodes' exposure to hierarchy, #' where only one or two contacts are the source of closure. -#' - `node_neighbours_degree()` measures nodes' average nearest neighbors degree, +#' - `node_by_neighbours_degree()` measures nodes' average nearest neighbors degree, #' or \eqn{knn}, a measure of the type of local environment a node finds itself in -#' - `tie_cohesion()` measures the ratio between common neighbors to ties' -#' adjacent nodes and the total number of adjacent nodes, -#' where high values indicate ties' embeddedness in dense local environments #' #' Burt's theory holds that while those nodes embedded in dense clusters #' of close connections are likely exposed to the same or similar ideas and information, @@ -31,17 +30,17 @@ #' where \eqn{t} is the sum of ties and \eqn{n} the sum of nodes in each node's neighbourhood, #' and effective size is calculated as \eqn{n - \frac{2t}{n}}. #' Node efficiency is the node's effective size divided by its degree. -#' @name measure_holes -#' @family measures #' @references #' ## On structural holes #' Burt, Ronald S. 1992. #' _Structural Holes: The Social Structure of Competition_. #' Cambridge, MA: Harvard University Press. -#' @inheritParams mark_nodes +#' @template param_data +#' @family brokerage +#' @template node_measure NULL -#' @rdname measure_holes +#' @rdname measure_broker_node #' @examples #' node_by_bridges(ison_adolescents) #' node_by_bridges(ison_southern_women) @@ -56,7 +55,7 @@ node_by_bridges <- function(.data){ make_node_measure(out, .data) } -#' @rdname measure_holes +#' @rdname measure_broker_node #' @references #' Borgatti, Steven. 1997. #' “\href{http://www.analytictech.com/connections/v20(1)/holes.htm}{Structural Holes: Unpacking Burt’s Redundancy Measures}” @@ -104,7 +103,7 @@ node_by_redundancy <- function(.data){ }, FUN.VALUE = numeric(1)) } -#' @rdname measure_holes +#' @rdname measure_broker_node #' @examples #' node_by_effsize(ison_adolescents) #' node_by_effsize(ison_southern_women) @@ -130,7 +129,7 @@ node_by_effsize <- function(.data){ } -#' @rdname measure_holes +#' @rdname measure_broker_node #' @examples #' node_by_efficiency(ison_adolescents) #' node_by_efficiency(ison_southern_women) @@ -141,7 +140,7 @@ node_by_efficiency <- function(.data){ make_node_measure(as.numeric(out), .data) } -#' @rdname measure_holes +#' @rdname measure_broker_node #' @references #' Hollway, James, Jean-Frédéric Morin, and Joost Pauwelyn. 2020. #' "Structural conditions for novelty: The introduction of new environmental clauses to the trade regime complex." @@ -193,7 +192,7 @@ node_by_constraint <- function(.data) { make_node_measure(res, .data) } -#' @rdname measure_holes +#' @rdname measure_broker_node #' @examples #' node_by_hierarchy(ison_adolescents) #' node_by_hierarchy(ison_southern_women) @@ -214,7 +213,7 @@ node_by_hierarchy <- function(.data){ make_node_measure(out, .data) } -#' @rdname measure_holes +#' @rdname measure_broker_node #' @importFrom igraph knn #' @references #' ## On neighbours average degree @@ -229,7 +228,21 @@ node_by_neighbours_degree <- function(.data){ make_node_measure(out, .data) } -#' @rdname measure_holes +# Tie holes #### + +#' Measuring ties brokerage +#' @name measure_broker_tie +#' @description +#' `tie_by_cohesion()` measures the ratio between common neighbors to ties' +#' adjacent nodes and the total number of adjacent nodes, +#' where high values indicate ties' embeddedness in dense local environments. +#' +#' @template param_data +#' @family brokerage +#' @template tie_measure +NULL + +#' @rdname measure_broker_tie #' @export tie_by_cohesion <- function(.data){ .data <- manynet::expect_ties(.data) diff --git a/R/motif_brokerage.R b/R/motif_brokerage.R index cc97f35..7588b9a 100644 --- a/R/motif_brokerage.R +++ b/R/motif_brokerage.R @@ -1,29 +1,21 @@ # Motifs #### -#' Motifs of brokerage -#' +#' Motifs of nodes brokerage #' @description -#' These functions include ways to take a census of the brokerage positions of nodes -#' in a network: -#' -#' - `node_x_brokerage()` returns the Gould-Fernandez brokerage +#' `node_x_brokerage()` returns the Gould-Fernandez brokerage #' roles played by nodes in a network. -#' - `net_x_brokerage()` returns the Gould-Fernandez brokerage -#' roles in a network. -#' - `node_brokering_activity()` measures nodes' brokerage activity. -#' - `node_brokering_exclusivity()` measures nodes' brokerage exclusivity. #' -#' @name motif_brokerage -#' @family motifs +#' @name motif_brokerage_node +#' @template param_data +#' @template param_memb #' @family brokerage -#' @inheritParams motif_node -#' @param membership A vector of partition membership as integers. +#' @template node_motif #' @param standardized Whether the score should be standardized #' into a _z_-score indicating how many standard deviations above #' or below the average the score lies. NULL -#' @rdname motif_brokerage +#' @rdname motif_brokerage_node #' @references #' ## On brokerage motifs #' Gould, Roger V., and Roberto M. Fernandez. 1989. @@ -36,7 +28,7 @@ NULL #' _Social Networks_ 41:36–47. #' \doi{10.1016/j.socnet.2014.11.005} #' @examples -#' # node_x_brokerage(ison_networkers, "Discipline") +#' node_x_brokerage(ison_networkers, "Discipline") #' @export node_x_brokerage <- function(.data, membership, standardized = FALSE){ thisRequires("sna") @@ -58,9 +50,24 @@ node_x_brokerage <- function(.data, membership, standardized = FALSE){ make_node_motif(out, .data) } -#' @rdname motif_brokerage +#' Motifs of network brokerage +#' @description +#' `net_x_brokerage()` returns the Gould-Fernandez brokerage +#' roles in a network. +#' +#' @name motif_brokerage_net +#' @template param_data +#' @template param_memb +#' @family brokerage +#' @template net_motif +#' @param standardized Whether the score should be standardized +#' into a _z_-score indicating how many standard deviations above +#' or below the average the score lies. +NULL + +#' @rdname motif_brokerage_net #' @examples -#' # net_x_brokerage(ison_networkers, "Discipline") +#' net_x_brokerage(ison_networkers, "Discipline") #' @export net_x_brokerage <- function(.data, membership, standardized = FALSE){ thisRequires("sna") @@ -84,18 +91,18 @@ net_x_brokerage <- function(.data, membership, standardized = FALSE){ # Measures #### #' Measures of brokerage -#' #' @description #' These functions include ways to measure nodes' brokerage activity and #' exclusivity in a network: #' -#' - `node_brokering_activity()` measures nodes' brokerage activity. -#' - `node_brokering_exclusivity()` measures nodes' brokerage exclusivity. +#' - `node_by_brokering_activity()` measures nodes' brokerage activity. +#' - `node_by_brokering_exclusivity()` measures nodes' brokerage exclusivity. #' #' @name measure_brokerage -#' @family measures +#' @template param_data +#' @template param_memb +#' @template node_measure #' @family brokerage -#' @inheritParams motif_brokerage NULL #' @rdname measure_brokerage @@ -165,19 +172,24 @@ node_by_brokering_exclusivity <- function(.data, membership){ # Memberships #### -#' Memberships of brokerage +#' Memberships in brokerage positions #' #' @description -#' These functions include ways to take a census of the brokerage positions of nodes -#' in a network: -#' -#' - `node_in_brokerage()` returns nodes membership as a powerhouse, +#' `node_in_brokerage()` returns nodes membership as a powerhouse, #' connector, linchpin, or sideliner according to Hamilton et al. (2020). #' #' @name member_brokerage -#' @family memberships +#' @template param_data +#' @template param_memb #' @family brokerage -#' @inheritParams motif_brokerage +#' @references +#' ## On brokerage activity and exclusivity +#' Hamilton, Matthew, Jacob Hileman, and Orjan Bodin. 2020. +#' "Evaluating heterogeneous brokerage: New conceptual and methodological approaches +#' and their application to multi-level environmental governance networks" +#' _Social Networks_ 61: 1-10. +#' \doi{10.1016/j.socnet.2019.08.002} +#' @template node_member NULL #' @rdname member_brokerage diff --git a/man/measure_broker_node.Rd b/man/measure_broker_node.Rd new file mode 100644 index 0000000..cbf2670 --- /dev/null +++ b/man/measure_broker_node.Rd @@ -0,0 +1,184 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/measure_holes.R +\name{measure_broker_node} +\alias{measure_broker_node} +\alias{node_by_bridges} +\alias{node_by_redundancy} +\alias{node_by_effsize} +\alias{node_by_efficiency} +\alias{node_by_constraint} +\alias{node_by_hierarchy} +\alias{node_by_neighbours_degree} +\title{Measuring nodes brokerage} +\usage{ +node_by_bridges(.data) + +node_by_redundancy(.data) + +node_by_effsize(.data) + +node_by_efficiency(.data) + +node_by_constraint(.data) + +node_by_hierarchy(.data) + +node_by_neighbours_degree(.data) +} +\arguments{ +\item{.data}{A network object of class \code{mnet}, \code{igraph}, \code{tbl_graph}, \code{network}, or similar. +For more information on the standard coercion possible, +see \code{\link[manynet:manip_as]{manynet::as_tidygraph()}}.} +} +\value{ +A \code{node_measure} numeric vector the length of the nodes in the network, +providing the scores for each node. +If the network is labelled, +then the scores will be labelled with the nodes' names. +} +\description{ +These function provide different measures of the degree to which nodes +fill structural holes, as outlined in Burt (1992): +\itemize{ +\item \code{node_by_bridges()} measures the sum of bridges to which each node +is adjacent. +\item \code{node_by_redundancy()} measures the redundancy of each nodes' contacts. +\item \code{node_by_effsize()} measures nodes' effective size. +\item \code{node_by_efficiency()} measures nodes' efficiency. +\item \code{node_by_constraint()} measures nodes' constraint scores for one-mode networks +according to Burt (1992) and for two-mode networks according to Hollway et al (2020). +\item \code{node_by_hierarchy()} measures nodes' exposure to hierarchy, +where only one or two contacts are the source of closure. +\item \code{node_by_neighbours_degree()} measures nodes' average nearest neighbors degree, +or \eqn{knn}, a measure of the type of local environment a node finds itself in +} + +Burt's theory holds that while those nodes embedded in dense clusters +of close connections are likely exposed to the same or similar ideas and information, +those who fill structural holes between two otherwise disconnected groups +can gain some comparative advantage from that position. +} +\details{ +A number of different ways of measuring these structural holes are available. +Note that we use Borgatti's reformulation for unweighted networks in +\code{node_redundancy()} and \code{node_effsize()}. +Redundancy is thus \eqn{\frac{2t}{n}}, +where \eqn{t} is the sum of ties and \eqn{n} the sum of nodes in each node's neighbourhood, +and effective size is calculated as \eqn{n - \frac{2t}{n}}. +Node efficiency is the node's effective size divided by its degree. +} +\examples{ +node_by_bridges(ison_adolescents) +node_by_bridges(ison_southern_women) +node_by_redundancy(ison_adolescents) +node_by_redundancy(ison_southern_women) +node_by_effsize(ison_adolescents) +node_by_effsize(ison_southern_women) +node_by_efficiency(ison_adolescents) +node_by_efficiency(ison_southern_women) +node_by_constraint(ison_southern_women) +node_by_hierarchy(ison_adolescents) +node_by_hierarchy(ison_southern_women) +} +\references{ +\subsection{On structural holes}{ + +Burt, Ronald S. 1992. +\emph{Structural Holes: The Social Structure of Competition}. +Cambridge, MA: Harvard University Press. +} + +Borgatti, Steven. 1997. +“\href{http://www.analytictech.com/connections/v20(1)/holes.htm}{Structural Holes: Unpacking Burt’s Redundancy Measures}” +\emph{Connections} 20(1):35-38. + +Burchard, Jake, and Benjamin Cornwell. 2018. +“Structural Holes and Bridging in Two-Mode Networks.” +\emph{Social Networks} 55:11–20. +\doi{10.1016/j.socnet.2018.04.001} + +Hollway, James, Jean-Frédéric Morin, and Joost Pauwelyn. 2020. +"Structural conditions for novelty: The introduction of new environmental clauses to the trade regime complex." +\emph{International Environmental Agreements: Politics, Law and Economics} 20 (1): 61–83. +\doi{10.1007/s10784-019-09464-5} + +\subsection{On neighbours average degree}{ + +Barrat, Alain, Marc Barthelemy, Romualdo Pastor-Satorras, and Alessandro Vespignani. 2004. +"The architecture of complex weighted networks", +\emph{Proc. Natl. Acad. Sci.} 101: 3747. +} +} +\seealso{ +Other brokerage: +\code{\link{measure_broker_tie}}, +\code{\link{measure_brokerage}}, +\code{\link{member_brokerage}}, +\code{\link{motif_brokerage_net}}, +\code{\link{motif_brokerage_node}} + +Other measures: +\code{\link{measure_assort_net}}, +\code{\link{measure_assort_node}}, +\code{\link{measure_breadth}}, +\code{\link{measure_broker_tie}}, +\code{\link{measure_brokerage}}, +\code{\link{measure_central_between}}, +\code{\link{measure_central_close}}, +\code{\link{measure_central_degree}}, +\code{\link{measure_central_eigen}}, +\code{\link{measure_centralisation_between}}, +\code{\link{measure_centralisation_close}}, +\code{\link{measure_centralisation_degree}}, +\code{\link{measure_centralisation_eigen}}, +\code{\link{measure_centralities_between}}, +\code{\link{measure_centralities_close}}, +\code{\link{measure_centralities_degree}}, +\code{\link{measure_centralities_eigen}}, +\code{\link{measure_closure}}, +\code{\link{measure_closure_node}}, +\code{\link{measure_cohesion}}, +\code{\link{measure_core}}, +\code{\link{measure_diffusion_infection}}, +\code{\link{measure_diffusion_net}}, +\code{\link{measure_diffusion_node}}, +\code{\link{measure_diverse_net}}, +\code{\link{measure_diverse_node}}, +\code{\link{measure_features}}, +\code{\link{measure_fragmentation}}, +\code{\link{measure_hierarchy}}, +\code{\link{measure_periods}} + +Other nodal: +\code{\link{mark_core}}, +\code{\link{mark_degree}}, +\code{\link{mark_diff}}, +\code{\link{mark_nodes}}, +\code{\link{mark_select_node}}, +\code{\link{measure_assort_node}}, +\code{\link{measure_brokerage}}, +\code{\link{measure_central_between}}, +\code{\link{measure_central_close}}, +\code{\link{measure_central_degree}}, +\code{\link{measure_central_eigen}}, +\code{\link{measure_closure_node}}, +\code{\link{measure_core}}, +\code{\link{measure_diffusion_node}}, +\code{\link{measure_diverse_node}}, +\code{\link{member_brokerage}}, +\code{\link{member_cliques}}, +\code{\link{member_community}}, +\code{\link{member_community_hier}}, +\code{\link{member_community_non}}, +\code{\link{member_components}}, +\code{\link{member_core}}, +\code{\link{member_diffusion}}, +\code{\link{member_equivalence}}, +\code{\link{motif_brokerage_node}}, +\code{\link{motif_exposure}}, +\code{\link{motif_node}}, +\code{\link{motif_path}} +} +\concept{brokerage} +\concept{measures} +\concept{nodal} diff --git a/man/measure_broker_tie.Rd b/man/measure_broker_tie.Rd new file mode 100644 index 0000000..37eee09 --- /dev/null +++ b/man/measure_broker_tie.Rd @@ -0,0 +1,78 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/measure_holes.R +\name{measure_broker_tie} +\alias{measure_broker_tie} +\alias{tie_by_cohesion} +\title{Measuring ties brokerage} +\usage{ +tie_by_cohesion(.data) +} +\arguments{ +\item{.data}{A network object of class \code{mnet}, \code{igraph}, \code{tbl_graph}, \code{network}, or similar. +For more information on the standard coercion possible, +see \code{\link[manynet:manip_as]{manynet::as_tidygraph()}}.} +} +\value{ +A \code{tie_measure} numeric vector the length of the ties in the network, +providing the scores for each tie. +If the network is labelled, +then the scores will be labelled with the ties' adjacent nodes' names. +} +\description{ +\code{tie_by_cohesion()} measures the ratio between common neighbors to ties' +adjacent nodes and the total number of adjacent nodes, +where high values indicate ties' embeddedness in dense local environments. +} +\seealso{ +Other brokerage: +\code{\link{measure_broker_node}}, +\code{\link{measure_brokerage}}, +\code{\link{member_brokerage}}, +\code{\link{motif_brokerage_net}}, +\code{\link{motif_brokerage_node}} + +Other measures: +\code{\link{measure_assort_net}}, +\code{\link{measure_assort_node}}, +\code{\link{measure_breadth}}, +\code{\link{measure_broker_node}}, +\code{\link{measure_brokerage}}, +\code{\link{measure_central_between}}, +\code{\link{measure_central_close}}, +\code{\link{measure_central_degree}}, +\code{\link{measure_central_eigen}}, +\code{\link{measure_centralisation_between}}, +\code{\link{measure_centralisation_close}}, +\code{\link{measure_centralisation_degree}}, +\code{\link{measure_centralisation_eigen}}, +\code{\link{measure_centralities_between}}, +\code{\link{measure_centralities_close}}, +\code{\link{measure_centralities_degree}}, +\code{\link{measure_centralities_eigen}}, +\code{\link{measure_closure}}, +\code{\link{measure_closure_node}}, +\code{\link{measure_cohesion}}, +\code{\link{measure_core}}, +\code{\link{measure_diffusion_infection}}, +\code{\link{measure_diffusion_net}}, +\code{\link{measure_diffusion_node}}, +\code{\link{measure_diverse_net}}, +\code{\link{measure_diverse_node}}, +\code{\link{measure_features}}, +\code{\link{measure_fragmentation}}, +\code{\link{measure_hierarchy}}, +\code{\link{measure_periods}} + +Other tie: +\code{\link{mark_dyads}}, +\code{\link{mark_select_tie}}, +\code{\link{mark_ties}}, +\code{\link{mark_triangles}}, +\code{\link{measure_centralities_between}}, +\code{\link{measure_centralities_close}}, +\code{\link{measure_centralities_degree}}, +\code{\link{measure_centralities_eigen}} +} +\concept{brokerage} +\concept{measures} +\concept{tie} diff --git a/man/measure_brokerage.Rd b/man/measure_brokerage.Rd index a3f71b5..5af7e02 100644 --- a/man/measure_brokerage.Rd +++ b/man/measure_brokerage.Rd @@ -15,14 +15,24 @@ node_by_brokering_exclusivity(.data, membership) For more information on the standard coercion possible, see \code{\link[manynet:manip_as]{manynet::as_tidygraph()}}.} -\item{membership}{A vector of partition membership as integers.} +\item{membership}{A character vector of categorical membership. +This is a vector of the same length as the number of nodes in the network, +where each element is a character string indicating the membership of the corresponding node. +While this may often be a vector created using \verb{node_in_*()} functions, +it can be any character vector that assigns nodes to groups or categories.} +} +\value{ +A \code{node_measure} numeric vector the length of the nodes in the network, +providing the scores for each node. +If the network is labelled, +then the scores will be labelled with the nodes' names. } \description{ These functions include ways to measure nodes' brokerage activity and exclusivity in a network: \itemize{ -\item \code{node_brokering_activity()} measures nodes' brokerage activity. -\item \code{node_brokering_exclusivity()} measures nodes' brokerage exclusivity. +\item \code{node_by_brokering_activity()} measures nodes' brokerage activity. +\item \code{node_by_brokering_exclusivity()} measures nodes' brokerage exclusivity. } } \examples{ @@ -40,28 +50,74 @@ and their application to multi-level environmental governance networks" } \seealso{ Other measures: -\code{\link{measure_assortativity}}, +\code{\link{measure_assort_net}}, +\code{\link{measure_assort_node}}, \code{\link{measure_breadth}}, +\code{\link{measure_broker_node}}, +\code{\link{measure_broker_tie}}, \code{\link{measure_central_between}}, \code{\link{measure_central_close}}, \code{\link{measure_central_degree}}, \code{\link{measure_central_eigen}}, +\code{\link{measure_centralisation_between}}, +\code{\link{measure_centralisation_close}}, +\code{\link{measure_centralisation_degree}}, +\code{\link{measure_centralisation_eigen}}, +\code{\link{measure_centralities_between}}, +\code{\link{measure_centralities_close}}, +\code{\link{measure_centralities_degree}}, +\code{\link{measure_centralities_eigen}}, \code{\link{measure_closure}}, +\code{\link{measure_closure_node}}, \code{\link{measure_cohesion}}, +\code{\link{measure_core}}, \code{\link{measure_diffusion_infection}}, \code{\link{measure_diffusion_net}}, \code{\link{measure_diffusion_node}}, +\code{\link{measure_diverse_net}}, +\code{\link{measure_diverse_node}}, \code{\link{measure_features}}, \code{\link{measure_fragmentation}}, -\code{\link{measure_heterogeneity}}, \code{\link{measure_hierarchy}}, -\code{\link{measure_holes}}, -\code{\link{measure_periods}}, -\code{\link{member_diffusion}} +\code{\link{measure_periods}} + +Other nodal: +\code{\link{mark_core}}, +\code{\link{mark_degree}}, +\code{\link{mark_diff}}, +\code{\link{mark_nodes}}, +\code{\link{mark_select_node}}, +\code{\link{measure_assort_node}}, +\code{\link{measure_broker_node}}, +\code{\link{measure_central_between}}, +\code{\link{measure_central_close}}, +\code{\link{measure_central_degree}}, +\code{\link{measure_central_eigen}}, +\code{\link{measure_closure_node}}, +\code{\link{measure_core}}, +\code{\link{measure_diffusion_node}}, +\code{\link{measure_diverse_node}}, +\code{\link{member_brokerage}}, +\code{\link{member_cliques}}, +\code{\link{member_community}}, +\code{\link{member_community_hier}}, +\code{\link{member_community_non}}, +\code{\link{member_components}}, +\code{\link{member_core}}, +\code{\link{member_diffusion}}, +\code{\link{member_equivalence}}, +\code{\link{motif_brokerage_node}}, +\code{\link{motif_exposure}}, +\code{\link{motif_node}}, +\code{\link{motif_path}} Other brokerage: +\code{\link{measure_broker_node}}, +\code{\link{measure_broker_tie}}, \code{\link{member_brokerage}}, -\code{\link{motif_brokerage}} +\code{\link{motif_brokerage_net}}, +\code{\link{motif_brokerage_node}} } \concept{brokerage} \concept{measures} +\concept{nodal} diff --git a/man/motif_brokerage.Rd b/man/motif_brokerage.Rd deleted file mode 100644 index bcf5502..0000000 --- a/man/motif_brokerage.Rd +++ /dev/null @@ -1,66 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/motif_brokerage.R -\name{motif_brokerage} -\alias{motif_brokerage} -\alias{node_x_brokerage} -\alias{net_x_brokerage} -\title{Motifs of brokerage} -\usage{ -node_x_brokerage(.data, membership, standardized = FALSE) - -net_x_brokerage(.data, membership, standardized = FALSE) -} -\arguments{ -\item{.data}{A network object of class \code{mnet}, \code{igraph}, \code{tbl_graph}, \code{network}, or similar. -For more information on the standard coercion possible, -see \code{\link[manynet:manip_as]{manynet::as_tidygraph()}}.} - -\item{membership}{A vector of partition membership as integers.} - -\item{standardized}{Whether the score should be standardized -into a \emph{z}-score indicating how many standard deviations above -or below the average the score lies.} -} -\description{ -These functions include ways to take a census of the brokerage positions of nodes -in a network: -\itemize{ -\item \code{node_x_brokerage()} returns the Gould-Fernandez brokerage -roles played by nodes in a network. -\item \code{net_x_brokerage()} returns the Gould-Fernandez brokerage -roles in a network. -\item \code{node_brokering_activity()} measures nodes' brokerage activity. -\item \code{node_brokering_exclusivity()} measures nodes' brokerage exclusivity. -} -} -\examples{ -# node_x_brokerage(ison_networkers, "Discipline") -# net_x_brokerage(ison_networkers, "Discipline") -} -\references{ -\subsection{On brokerage motifs}{ - -Gould, Roger V., and Roberto M. Fernandez. 1989. -“Structures of Mediation: A Formal Approach to Brokerage in Transaction Networks.” -\emph{Sociological Methodology}, 19: 89-126. -\doi{10.2307/270949} - -Jasny, Lorien, and Mark Lubell. 2015. -“Two-Mode Brokerage in Policy Networks.” -\emph{Social Networks} 41:36–47. -\doi{10.1016/j.socnet.2014.11.005} -} -} -\seealso{ -Other motifs: -\code{\link{motif_diffusion}}, -\code{\link{motif_hierarchy}}, -\code{\link{motif_net}}, -\code{\link{motif_node}} - -Other brokerage: -\code{\link{measure_brokerage}}, -\code{\link{member_brokerage}} -} -\concept{brokerage} -\concept{motifs} diff --git a/man/motif_brokerage_net.Rd b/man/motif_brokerage_net.Rd new file mode 100644 index 0000000..886bc0c --- /dev/null +++ b/man/motif_brokerage_net.Rd @@ -0,0 +1,55 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/motif_brokerage.R +\name{motif_brokerage_net} +\alias{motif_brokerage_net} +\alias{net_x_brokerage} +\title{Motifs of network brokerage} +\usage{ +net_x_brokerage(.data, membership, standardized = FALSE) +} +\arguments{ +\item{.data}{A network object of class \code{mnet}, \code{igraph}, \code{tbl_graph}, \code{network}, or similar. +For more information on the standard coercion possible, +see \code{\link[manynet:manip_as]{manynet::as_tidygraph()}}.} + +\item{membership}{A character vector of categorical membership. +This is a vector of the same length as the number of nodes in the network, +where each element is a character string indicating the membership of the corresponding node. +While this may often be a vector created using \verb{node_in_*()} functions, +it can be any character vector that assigns nodes to groups or categories.} + +\item{standardized}{Whether the score should be standardized +into a \emph{z}-score indicating how many standard deviations above +or below the average the score lies.} +} +\value{ +A \code{network_motif} tibble with one row and a column for each motif type, +giving the count of each motif in the network. +} +\description{ +\code{net_x_brokerage()} returns the Gould-Fernandez brokerage +roles in a network. +} +\examples{ +net_x_brokerage(ison_networkers, "Discipline") +} +\seealso{ +Other brokerage: +\code{\link{measure_broker_node}}, +\code{\link{measure_broker_tie}}, +\code{\link{measure_brokerage}}, +\code{\link{member_brokerage}}, +\code{\link{motif_brokerage_node}} + +Other motifs: +\code{\link{motif_brokerage_node}}, +\code{\link{motif_exposure}}, +\code{\link{motif_hazard}}, +\code{\link{motif_hierarchy}}, +\code{\link{motif_net}}, +\code{\link{motif_node}}, +\code{\link{motif_path}}, +\code{\link{motif_periods}} +} +\concept{brokerage} +\concept{motifs} diff --git a/man/motif_brokerage_node.Rd b/man/motif_brokerage_node.Rd new file mode 100644 index 0000000..1de038d --- /dev/null +++ b/man/motif_brokerage_node.Rd @@ -0,0 +1,103 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/motif_brokerage.R +\name{motif_brokerage_node} +\alias{motif_brokerage_node} +\alias{node_x_brokerage} +\title{Motifs of nodes brokerage} +\usage{ +node_x_brokerage(.data, membership, standardized = FALSE) +} +\arguments{ +\item{.data}{A network object of class \code{mnet}, \code{igraph}, \code{tbl_graph}, \code{network}, or similar. +For more information on the standard coercion possible, +see \code{\link[manynet:manip_as]{manynet::as_tidygraph()}}.} + +\item{membership}{A character vector of categorical membership. +This is a vector of the same length as the number of nodes in the network, +where each element is a character string indicating the membership of the corresponding node. +While this may often be a vector created using \verb{node_in_*()} functions, +it can be any character vector that assigns nodes to groups or categories.} + +\item{standardized}{Whether the score should be standardized +into a \emph{z}-score indicating how many standard deviations above +or below the average the score lies.} +} +\value{ +A \code{node_motif} tibble with one row for each node in the network and +a column for each motif type, +giving the count of each motif in which each node participates. +If the network is labelled, +then the node names will be in a column named \code{names}. +} +\description{ +\code{node_x_brokerage()} returns the Gould-Fernandez brokerage +roles played by nodes in a network. +} +\examples{ +node_x_brokerage(ison_networkers, "Discipline") +} +\references{ +\subsection{On brokerage motifs}{ + +Gould, Roger V., and Roberto M. Fernandez. 1989. +“Structures of Mediation: A Formal Approach to Brokerage in Transaction Networks.” +\emph{Sociological Methodology}, 19: 89-126. +\doi{10.2307/270949} + +Jasny, Lorien, and Mark Lubell. 2015. +“Two-Mode Brokerage in Policy Networks.” +\emph{Social Networks} 41:36–47. +\doi{10.1016/j.socnet.2014.11.005} +} +} +\seealso{ +Other brokerage: +\code{\link{measure_broker_node}}, +\code{\link{measure_broker_tie}}, +\code{\link{measure_brokerage}}, +\code{\link{member_brokerage}}, +\code{\link{motif_brokerage_net}} + +Other motifs: +\code{\link{motif_brokerage_net}}, +\code{\link{motif_exposure}}, +\code{\link{motif_hazard}}, +\code{\link{motif_hierarchy}}, +\code{\link{motif_net}}, +\code{\link{motif_node}}, +\code{\link{motif_path}}, +\code{\link{motif_periods}} + +Other nodal: +\code{\link{mark_core}}, +\code{\link{mark_degree}}, +\code{\link{mark_diff}}, +\code{\link{mark_nodes}}, +\code{\link{mark_select_node}}, +\code{\link{measure_assort_node}}, +\code{\link{measure_broker_node}}, +\code{\link{measure_brokerage}}, +\code{\link{measure_central_between}}, +\code{\link{measure_central_close}}, +\code{\link{measure_central_degree}}, +\code{\link{measure_central_eigen}}, +\code{\link{measure_closure_node}}, +\code{\link{measure_core}}, +\code{\link{measure_diffusion_node}}, +\code{\link{measure_diverse_node}}, +\code{\link{member_brokerage}}, +\code{\link{member_cliques}}, +\code{\link{member_community}}, +\code{\link{member_community_hier}}, +\code{\link{member_community_non}}, +\code{\link{member_components}}, +\code{\link{member_core}}, +\code{\link{member_diffusion}}, +\code{\link{member_equivalence}}, +\code{\link{motif_exposure}}, +\code{\link{motif_node}}, +\code{\link{motif_path}} +} +\concept{brokerage} +\concept{motifs} +\concept{nodal} From af5fac2e9f4672d12ea6a5d19dd4dcdf5f105497 Mon Sep 17 00:00:00 2001 From: James Hollway Date: Sat, 21 Mar 2026 18:03:30 +0100 Subject: [PATCH 12/35] Improved documentation for diversity and assortativity --- R/measure_heterogeneity.R | 364 +++++++++++------- man/measure_assort_net.Rd | 178 +++++++++ man/measure_assort_node.Rd | 149 +++++++ man/measure_assortativity.Rd | 126 ------ ...eterogeneity.Rd => measure_diverse_net.Rd} | 73 ++-- man/measure_diverse_node.Rd | 124 ++++++ man/member_brokerage.Rd | 70 +++- 7 files changed, 763 insertions(+), 321 deletions(-) create mode 100644 man/measure_assort_net.Rd create mode 100644 man/measure_assort_node.Rd delete mode 100644 man/measure_assortativity.Rd rename man/{measure_heterogeneity.Rd => measure_diverse_net.Rd} (76%) create mode 100644 man/measure_diverse_node.Rd diff --git a/R/measure_heterogeneity.R b/R/measure_heterogeneity.R index 3f3280c..ff3010b 100644 --- a/R/measure_heterogeneity.R +++ b/R/measure_heterogeneity.R @@ -1,42 +1,29 @@ -# Diversity #### +# Network diversity #### #' Measures of network diversity -#' +#' @name measure_diverse_net #' @description #' These functions offer ways to measure the heterogeneity of an attribute #' across a network, within groups of a network, or the distribution of ties #' across this attribute: #' -#' - `net_richness()` measures the number of unique categories +#' - `net_by_richness()` measures the number of unique categories #' in a network attribute. -#' - `node_richness()` measures the number of unique categories -#' of an attribute to which each node is connected. -#' - `net_diversity()` measures the heterogeneity of ties across a network. -#' - `node_diversity()` measures the heterogeneity of each node's -#' local neighbourhood. -#' - `net_heterophily()` measures how embedded nodes in the network -#' are within groups of nodes with the same attribute. -#' - `node_heterophily()` measures each node's embeddedness within groups -#' of nodes with the same attribute. -#' - `net_assortativity()` measures the degree assortativity in a network. -#' - `net_spatial()` measures the spatial association/autocorrelation -#' (global Moran's I) in a network. +#' - `net_by_diversity()` measures the heterogeneity of ties across a network. #' -#' @inheritParams mark_nodes -#' @param attribute Name of a nodal attribute or membership vector -#' to use as categories for the diversity measure. -#' @param method Which method to use for `net_diversity()`. -#' Either "blau" (Blau's index) or "teachman" (Teachman's index) for -#' categorical attributes, or "variation" (coefficient of variation) -#' or "gini" (Gini coefficient) for numeric attributes. -#' Default is "blau". -#' If an incompatible method is chosen for the attribute type, -#' a suitable alternative will be used instead with a message. -#' @name measure_heterogeneity -#' @family measures +#' @template param_data +#' @template param_attr +#' @family diversity +#' @template net_measure +#' @param diversity Which method to use for `*_diversity()`. +#' Either "blau" (Blau's index) or "teachman" (Teachman's index) for categorical attributes, +#' or "variation" (coefficient of variation) or "gini" (Gini coefficient) for numeric attributes. +#' Default is "blau". +#' If an incompatible method is chosen for the attribute type, +#' a suitable alternative will be used instead with a message. NULL -#' @rdname measure_heterogeneity +#' @rdname measure_diverse_net #' @section Richness: #' Richness is a simple count of the number of different categories #' present for a given attribute. @@ -55,19 +42,7 @@ net_by_richness <- function(.data, attribute){ .data, call = deparse(sys.call())) } -#' @rdname measure_heterogeneity -#' @examples -#' node_by_richness(ison_networkers, "Discipline") -#' @export -node_by_richness <- function(.data, attribute){ - .data <- manynet::expect_nodes(.data) - out <- vapply(manynet::to_egos(.data, min_dist = 1), - function(x) length(unique(manynet::node_attribute(x, attribute))), - FUN.VALUE = numeric(1)) - make_node_measure(out, .data) -} - -#' @rdname measure_heterogeneity +#' @rdname measure_diverse_net #' @section Diversity: #' Blau's index (1977) uses a formula known also in other disciplines #' by other names @@ -143,7 +118,7 @@ node_by_richness <- function(.data, attribute){ #' net_by_diversity(marvel_friends, "Appearances") #' @export net_by_diversity <- function(.data, attribute, - method = c("blau","teachman","variation","gini")){ + diversity = c("blau","teachman","variation","gini")){ .data <- manynet::expect_nodes(.data) blau <- function(features) { 1 - sum((table(features)/length(features))^2) } teachman <- function(features) { @@ -159,21 +134,21 @@ net_by_diversity <- function(.data, attribute, return((2 * G) / (n * sum(x)) - (n + 1) / n) } attr <- manynet::node_attribute(.data, attribute) - method <- match.arg(method) - if(is.numeric(attr) && method %in% c("blau","teachman")){ - manynet::snet_info("{.val {method}} index is not appropriate for numeric attributes.") + diversity <- match.arg(diversity) + if(is.numeric(attr) && diversity %in% c("blau","teachman")){ + manynet::snet_info("{.val {diversity}} index is not appropriate for numeric attributes.") manynet::snet_info("Using {.val variation} coefficient instead", "({.val gini} coefficient also available).") - method <- "variation" + diversity <- "variation" } - if(is.character(attr) && method %in% c("variation","gini")){ - manynet::snet_info("{.val {method}} coefficient is not appropriate for categorical attributes.") + if(is.character(attr) && diversity %in% c("variation","gini")){ + manynet::snet_info("{.val {diversity}} coefficient is not appropriate for categorical attributes.") manynet::snet_info("Using {.val blau} index instead", "({.val teachman} index also available).") - method <- "blau" + diversity <- "blau" } - out <- switch(method, + out <- switch(diversity, blau = blau(attr), teachman = teachman(attr), variation = cv(attr), @@ -181,62 +156,136 @@ net_by_diversity <- function(.data, attribute, make_network_measure(out, .data, call = deparse(sys.call())) } -#' @rdname measure_heterogeneity +# Nodal diversity #### + +#' Measures of nodes diversity +#' @name measure_diverse_node +#' @description +#' These functions offer ways to measure the heterogeneity of an attribute +#' across a network, within groups of a network, or the distribution of ties +#' across this attribute: +#' +#' - `node_by_richness()` measures the number of unique categories +#' of an attribute to which each node is connected. +#' - `node_by_diversity()` measures the heterogeneity of each node's +#' local neighbourhood. +#' +#' @template param_data +#' @template param_attr +#' @family diversity +#' @template node_measure +#' @inheritParams measure_diverse_net +NULL + +#' @rdname measure_diverse_node +#' @examples +#' node_by_richness(ison_networkers, "Discipline") +#' @export +node_by_richness <- function(.data, attribute){ + .data <- manynet::expect_nodes(.data) + out <- vapply(manynet::to_egos(.data, min_dist = 1), + function(x) length(unique(manynet::node_attribute(x, attribute))), + FUN.VALUE = numeric(1)) + make_node_measure(out, .data) +} + +#' @rdname measure_diverse_node #' @examples +#' marvel_friends <- to_unsigned(to_uniplex(fict_marvel, "relationship"), "positive") #' node_by_diversity(marvel_friends, "Gender") #' node_by_diversity(marvel_friends, "Attractive") #' @export node_by_diversity <- function(.data, attribute, - method = c("blau","teachman","variation","gini")){ + diversity = c("blau","teachman","variation","gini")){ .data <- manynet::expect_nodes(.data) attr <- manynet::node_attribute(.data, attribute) - method <- match.arg(method) - if(is.numeric(attr) && method %in% c("blau","teachman")){ + diversity <- match.arg(diversity) + if(is.numeric(attr) && diversity %in% c("blau","teachman")){ manynet::snet_info("{.val {method}} index is not appropriate for numeric attributes.") manynet::snet_info("Using {.val variation} coefficient instead", - "({.val gini} coefficient also available).") - method <- "variation" + "({.val gini} coefficient also available).") + diversity <- "variation" } - if(is.character(attr) && method %in% c("variation","gini")){ - manynet::snet_info("{.val {method}} coefficient is not appropriate for categorical attributes.") + if(is.character(attr) && diversity %in% c("variation","gini")){ + manynet::snet_info("{.val {diversity}} coefficient is not appropriate for categorical attributes.") manynet::snet_info("Using {.val blau} index instead", - "({.val teachman} index also available).") - method <- "blau" + "({.val teachman} index also available).") + diversity <- "blau" } out <- vapply(igraph::ego(manynet::as_igraph(.data)), function(x) net_by_diversity( igraph::induced_subgraph(manynet::as_igraph(.data), x), - attribute, method = method), + attribute, diversity = diversity), FUN.VALUE = numeric(1)) make_node_measure(out, .data) } -# Assortativity #### +# Network assortativity #### #' Measures of network assortativity -#' +#' @name measure_assort_net #' @description #' These functions offer ways to measure the distribution or assortativity #' of ties in a network: #' -#' - `net_heterophily()` measures how embedded nodes in the network +#' - `net_by_heterophily()` measures how embedded nodes in the network #' are within groups of nodes with the same attribute. -#' - `node_heterophily()` measures each node's embeddedness within groups -#' of nodes with the same attribute. -#' - `net_assortativity()` measures the degree assortativity in a network. -#' - `net_spatial()` measures the spatial association/autocorrelation +#' - `net_by_homophily()` measures how embedded nodes in the network +#' are within groups of nodes with the same attribute, but with more options for method. +#' - `net_by_assortativity()` measures the degree assortativity in a network. +#' - `net_by_spatial()` measures the spatial association/autocorrelation #' (global Moran's I) in a network. #' -#' @inheritParams mark_nodes -#' @inheritParams measure_heterogeneity -#' @param attribute Name of a nodal attribute or membership vector -#' to use as categories for the diversity measure. -#' @name measure_assortativity -#' @family measures +#' Note that for two-mode networks, +#' homophily is calculated on the mode with the attribute of interest, +#' and the other mode is ignored. +#' If the attribute is present on both modes, +#' homophily is calculated on the first mode by default, +#' but a message is given and the user can choose to calculate homophily on the +#' other mode instead by subsetting the attribute vector and +#' converting the network to a one-mode network. +#' @template param_data +#' @template param_attr +#' @param assortativity Which method to use for `*_homophily()`. +#' Either "ie" (negative E-I index), "ei" (E-I index), +#' "yule" (Yule's Q), or "geary" (Geary's C). +#' Default is "ie". +#' The E-I index is the number of ties between (or _external_) nodes +#' grouped in some mutually exclusive categories +#' minus the number of ties within (or _internal_) these groups +#' divided by the total number of ties. +#' This value can range from 1 to -1, +#' where 1 indicates ties only between categories/groups and -1 ties only within categories/groups. +#' +#' Yule's Q is a measure of association for two binary variables, calculated as: +#' \deqn{Q = \frac{ad - bc}{ad + bc}} +#' where \eqn{a} is the number of ties between nodes in the same category, +#' \eqn{b} is the number of ties between nodes in different categories, +#' \eqn{c} is the number of non-ties between nodes in the same category, +#' and \eqn{d} is the number of non-ties between nodes in different categories. +#' This value can range from -1 to 1, where 1 indicates perfect association +#' (all ties are between nodes in the same category), -1 indicates perfect disassociation +#' (all ties are between nodes in different categories), and 0 indicates no association. +#' +#' Geary's C is a measure of spatial autocorrelation, calculated as: +#' \deqn{C = \frac{(n - 1) \sum +#' \limits_{i=1}^n \sum\limits_{j=1}^n w_{ij} (x_i - x_j)^2}{2W \sum\limits_{i=1}^n (x_i - \bar{x})^2}} +#' where \eqn{n} is the number of nodes, \eqn{ +#' w_{ij}} is the weight of the tie between nodes \eqn{i} and \eqn{j}, +#' \eqn{x_i} is the attribute value of node \eqn{i}, +#' \eqn{\bar{x}} is the mean attribute value across all nodes, and \eqn{W} is the sum of all tie weights. +#' This value can range from 0 to 2, where values less than 1 +#' indicate positive autocorrelation (similar values are more likely to be connected), +#' values greater than 1 indicate negative autocorrelation (dissimilar values are more likely +#' to be connected), and a value of 1 indicates no autocorrelation. +#' If an incompatible method is chosen for the attribute type, +#' a suitable alternative will be used instead with a message. +#' @family diversity +#' @template net_measure NULL -#' @rdname measure_assortativity -#' @section Homophily: +#' @rdname measure_assort_net +#' @section Heterophily: #' Given a partition of a network into a number of mutually exclusive groups then #' The E-I index is the number of ties between (or _external_) nodes #' grouped in some mutually exclusive categories @@ -276,38 +325,12 @@ net_by_heterophily <- function(.data, attribute){ make_network_measure(ei, .data, call = deparse(sys.call())) } -#' @rdname measure_assortativity -#' @examples -#' node_by_heterophily(marvel_friends, "Gender") -#' node_by_heterophily(marvel_friends, "Attractive") -#' @export -node_by_heterophily <- function(.data, attribute){ - .data <- manynet::expect_nodes(.data) - m <- manynet::as_matrix(.data) - if (length(attribute) == 1 && is.character(attribute)) { - attribute <- manynet::node_attribute(.data, attribute) - } - if (is.character(attribute) | is.numeric(attribute)) { - attribute <- as.factor(attribute) - } - if(anyNA(attribute)){ - m[is.na(attribute),] <- NA - m[,is.na(attribute)] <- NA - } - same <- outer(attribute, attribute, "==") - nInternal <- rowSums(m * same, na.rm = TRUE) - nInternal[is.na(attribute)] <- NA - nExternal <- rowSums(m, na.rm = TRUE) - nInternal - ei <- (nExternal - nInternal) / rowSums(m, na.rm = TRUE) - make_node_measure(ei, .data) -} - -#' @rdname measure_assortativity +#' @rdname measure_assort_net #' @examples #' net_by_homophily(marvel_friends, "Gender") #' @export net_by_homophily <- function(.data, attribute, - method = c("ie","ei","yule","geary")){ + assortativity = c("ie","ei","yule","geary")){ .data <- manynet::expect_nodes(.data) # mode <- attr_mode(.data, attribute) # if(is_twomode(.data) && !is.null(mode)){ @@ -327,20 +350,20 @@ net_by_homophily <- function(.data, attribute, if (length(attribute) == 1 && is.character(attribute)) { attribute <- manynet::node_attribute(.data, attribute) } - method <- match.arg(method) - if(is.numeric(attribute) && method %in% c("ie","ei","yule")){ - manynet::snet_info("{.val {method}} index is not appropriate for numeric attributes.") + assortativity <- match.arg(assortativity) + if(is.numeric(attribute) && assortativity %in% c("ie","ei","yule")){ + manynet::snet_info("{.val {assortativity}} index is not appropriate for numeric attributes.") manynet::snet_info("Using {.val geary}'s C instead.") - method <- "geary" + assortativity <- "geary" } - if(!is.numeric(attribute) && method == "geary"){ - manynet::snet_info("{.val {method}} index is not appropriate for categorical attributes.") + if(!is.numeric(attribute) && assortativity == "geary"){ + manynet::snet_info("{.val {assortativity}} index is not appropriate for categorical attributes.") manynet::snet_info("Using {.val ie} index instead.") - method <- "ie" + assortativity <- "ie" } m <- manynet::as_matrix(manynet::to_unweighted(.data)) - + ei <- function(m, attribute){ same <- outer(attribute, attribute, "==") nInternal <- sum(m * same, na.rm = TRUE) @@ -379,9 +402,9 @@ net_by_homophily <- function(.data, attribute, if (den == 0) return(NA_real_) num / den - } + } - res <- switch(match.arg(method), + res <- switch(match.arg(assortativity), ie = -ei(m, attribute), ei = ei(m, attribute), yule = yule(m, attribute), @@ -389,7 +412,7 @@ net_by_homophily <- function(.data, attribute, make_network_measure(res, .data, call = deparse(sys.call())) } - + attr_mode <- function(.data, attribute){ if(manynet::is_twomode(.data)){ @@ -400,34 +423,7 @@ attr_mode <- function(.data, attribute){ } else NULL } -#' @rdname measure_assortativity -#' @export -node_by_homophily <- function(.data, attribute, - method = c("ie","ei","yule","geary")){ - .data <- manynet::expect_nodes(.data) - # if (length(attribute) == 1 && is.character(attribute)) { - # attribute <- manynet::node_attribute(.data, attribute) - # } - method <- match.arg(method) - if(is.numeric(attribute) && method %in% c("ie","ei","yule")){ - manynet::snet_info("{.val {method}} index is not appropriate for numeric attributes.") - manynet::snet_info("Using {.val geary}'s C instead.") - method <- "geary" - } - if(!is.numeric(attribute) && method == "geary"){ - manynet::snet_info("{.val {method}} index is not appropriate for categorical attributes.") - manynet::snet_info("Using {.val ie} index instead.") - method <- "ie" - } - out <- vapply(igraph::ego(manynet::as_igraph(.data)), - function(x) net_by_homophily( - igraph::induced_subgraph(manynet::as_igraph(.data), x), - attribute, method = method), - FUN.VALUE = numeric(1)) - make_node_measure(out, .data) -} - -#' @rdname measure_assortativity +#' @rdname measure_assort_net #' @importFrom igraph assortativity_degree #' @references #' ## On assortativity @@ -441,11 +437,11 @@ node_by_homophily <- function(.data, attribute, net_by_assortativity <- function(.data){ .data <- manynet::expect_nodes(.data) make_network_measure(igraph::assortativity_degree(manynet::as_igraph(.data), - directed = manynet::is_directed(.data)), - .data, call = deparse(sys.call())) + directed = manynet::is_directed(.data)), + .data, call = deparse(sys.call())) } -#' @rdname measure_assortativity +#' @rdname measure_assort_net #' @references #' ## On spatial autocorrelation #' Moran, Patrick Alfred Pierce. 1950. @@ -465,7 +461,81 @@ net_by_spatial <- function(.data, attribute){ W <- sum(w, na.rm = TRUE) I <- (N/W) * (sum(w * matrix(x - x_bar, N, N) * matrix(x - x_bar, N, N, byrow = TRUE)) / - sum((x - x_bar)^2)) + sum((x - x_bar)^2)) make_network_measure(I, .data, call = deparse(sys.call())) } + +# Network assortativity #### + +#' Measures of nodes assortativity +#' @name measure_assort_node +#' @description +#' These functions offer ways to measure nodes' assortativity in a network: +#' +#' - `node_by_heterophily()` measures each node's embeddedness within groups +#' of nodes with the same attribute. +#' - `node_by_homophily()` measures each node's embeddedness within groups +#' of nodes with the same attribute, using a variety of methods. +#' +#' @template param_data +#' @template param_attr +#' @family diversity +#' @template node_measure +#' @inheritParams measure_assort_net +NULL + +#' @rdname measure_assort_node +#' @examples +#' marvel_friends <- to_unsigned(to_uniplex(fict_marvel, "relationship"), "positive") +#' node_by_heterophily(marvel_friends, "Gender") +#' node_by_heterophily(marvel_friends, "Attractive") +#' @export +node_by_heterophily <- function(.data, attribute){ + .data <- manynet::expect_nodes(.data) + m <- manynet::as_matrix(.data) + if (length(attribute) == 1 && is.character(attribute)) { + attribute <- manynet::node_attribute(.data, attribute) + } + if (is.character(attribute) | is.numeric(attribute)) { + attribute <- as.factor(attribute) + } + if(anyNA(attribute)){ + m[is.na(attribute),] <- NA + m[,is.na(attribute)] <- NA + } + same <- outer(attribute, attribute, "==") + nInternal <- rowSums(m * same, na.rm = TRUE) + nInternal[is.na(attribute)] <- NA + nExternal <- rowSums(m, na.rm = TRUE) - nInternal + ei <- (nExternal - nInternal) / rowSums(m, na.rm = TRUE) + make_node_measure(ei, .data) +} + +#' @rdname measure_assort_node +#' @export +node_by_homophily <- function(.data, attribute, + assortativity = c("ie","ei","yule","geary")){ + .data <- manynet::expect_nodes(.data) + # if (length(attribute) == 1 && is.character(attribute)) { + # attribute <- manynet::node_attribute(.data, attribute) + # } + assortativity <- match.arg(assortativity) + if(is.numeric(attribute) && assortativity %in% c("ie","ei","yule")){ + manynet::snet_info("{.val {assortativity}} index is not appropriate for numeric attributes.") + manynet::snet_info("Using {.val geary}'s C instead.") + assortativity <- "geary" + } + if(!is.numeric(attribute) && assortativity == "geary"){ + manynet::snet_info("{.val {assortativity}} index is not appropriate for categorical attributes.") + manynet::snet_info("Using {.val ie} index instead.") + assortativity <- "ie" + } + out <- vapply(igraph::ego(manynet::as_igraph(.data)), + function(x) net_by_homophily( + igraph::induced_subgraph(manynet::as_igraph(.data), x), + attribute, assortativity = assortativity), + FUN.VALUE = numeric(1)) + make_node_measure(out, .data) +} + diff --git a/man/measure_assort_net.Rd b/man/measure_assort_net.Rd new file mode 100644 index 0000000..cd9b728 --- /dev/null +++ b/man/measure_assort_net.Rd @@ -0,0 +1,178 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/measure_heterogeneity.R +\name{measure_assort_net} +\alias{measure_assort_net} +\alias{net_by_heterophily} +\alias{net_by_homophily} +\alias{net_by_assortativity} +\alias{net_by_spatial} +\title{Measures of network assortativity} +\usage{ +net_by_heterophily(.data, attribute) + +net_by_homophily( + .data, + attribute, + assortativity = c("ie", "ei", "yule", "geary") +) + +net_by_assortativity(.data) + +net_by_spatial(.data, attribute) +} +\arguments{ +\item{.data}{A network object of class \code{mnet}, \code{igraph}, \code{tbl_graph}, \code{network}, or similar. +For more information on the standard coercion possible, +see \code{\link[manynet:manip_as]{manynet::as_tidygraph()}}.} + +\item{attribute}{Name of a nodal attribute, mark, measure, or membership vector.} + +\item{assortativity}{Which method to use for \verb{*_homophily()}. +Either "ie" (negative E-I index), "ei" (E-I index), +"yule" (Yule's Q), or "geary" (Geary's C). +Default is "ie". +The E-I index is the number of ties between (or \emph{external}) nodes +grouped in some mutually exclusive categories +minus the number of ties within (or \emph{internal}) these groups +divided by the total number of ties. +This value can range from 1 to -1, +where 1 indicates ties only between categories/groups and -1 ties only within categories/groups. + +Yule's Q is a measure of association for two binary variables, calculated as: +\deqn{Q = \frac{ad - bc}{ad + bc}} +where \eqn{a} is the number of ties between nodes in the same category, +\eqn{b} is the number of ties between nodes in different categories, +\eqn{c} is the number of non-ties between nodes in the same category, +and \eqn{d} is the number of non-ties between nodes in different categories. +This value can range from -1 to 1, where 1 indicates perfect association +(all ties are between nodes in the same category), -1 indicates perfect disassociation +(all ties are between nodes in different categories), and 0 indicates no association. + +Geary's C is a measure of spatial autocorrelation, calculated as: +\deqn{C = \frac{(n - 1) \sum + \limits_{i=1}^n \sum\limits_{j=1}^n w_{ij} (x_i - x_j)^2}{2W \sum\limits_{i=1}^n (x_i - \bar{x})^2}} +where \eqn{n} is the number of nodes, \eqn{ + w_{ij}} is the weight of the tie between nodes \eqn{i} and \eqn{j}, +\eqn{x_i} is the attribute value of node \eqn{i}, +\eqn{\bar{x}} is the mean attribute value across all nodes, and \eqn{W} is the sum of all tie weights. +This value can range from 0 to 2, where values less than 1 +indicate positive autocorrelation (similar values are more likely to be connected), +values greater than 1 indicate negative autocorrelation (dissimilar values are more likely +to be connected), and a value of 1 indicates no autocorrelation. +If an incompatible method is chosen for the attribute type, +a suitable alternative will be used instead with a message.} +} +\value{ +A \code{network_measure} numeric score. +} +\description{ +These functions offer ways to measure the distribution or assortativity +of ties in a network: +\itemize{ +\item \code{net_by_heterophily()} measures how embedded nodes in the network +are within groups of nodes with the same attribute. +\item \code{net_by_homophily()} measures how embedded nodes in the network +are within groups of nodes with the same attribute, but with more options for method. +\item \code{net_by_assortativity()} measures the degree assortativity in a network. +\item \code{net_by_spatial()} measures the spatial association/autocorrelation +(global Moran's I) in a network. +} + +Note that for two-mode networks, +homophily is calculated on the mode with the attribute of interest, +and the other mode is ignored. +If the attribute is present on both modes, +homophily is calculated on the first mode by default, +but a message is given and the user can choose to calculate homophily on the +other mode instead by subsetting the attribute vector and +converting the network to a one-mode network. +} +\section{Heterophily}{ + +Given a partition of a network into a number of mutually exclusive groups then +The E-I index is the number of ties between (or \emph{external}) nodes +grouped in some mutually exclusive categories +minus the number of ties within (or \emph{internal}) these groups +divided by the total number of ties. +This value can range from 1 to -1, +where 1 indicates ties only between categories/groups and -1 ties only within categories/groups. +} + +\examples{ +marvel_friends <- to_unsigned(to_uniplex(fict_marvel, "relationship"), "positive") +net_by_heterophily(marvel_friends, "Gender") +net_by_heterophily(marvel_friends, "Attractive") +net_by_homophily(marvel_friends, "Gender") +net_by_assortativity(ison_networkers) +net_by_spatial(ison_lawfirm, "age") +} +\references{ +\subsection{On heterophily}{ + +Krackhardt, David, and Robert N. Stern. 1988. +Informal networks and organizational crises: an experimental simulation. +\emph{Social Psychology Quarterly} 51(2): 123-140. +\doi{10.2307/2786835} + +McPherson, Miller, Lynn Smith-Lovin, and James M. Cook. 2001. +"Birds of a Feather: Homophily in Social Networks". +\emph{Annual Review of Sociology}, 27(1): 415-444. +\doi{10.1146/annurev.soc.27.1.415} +} + +\subsection{On assortativity}{ + +Newman, Mark E.J. 2002. +"Assortative mixing in networks". +\emph{Physical Review Letters}, 89(20): 208701. +\doi{10.1103/physrevlett.89.208701} +} + +\subsection{On spatial autocorrelation}{ + +Moran, Patrick Alfred Pierce. 1950. +"Notes on continuous stochastic phenomena". +\emph{Biometrika} 37(1): 17-23. +\doi{10.2307/2332142} +} +} +\seealso{ +Other diversity: +\code{\link{measure_assort_node}}, +\code{\link{measure_diverse_net}}, +\code{\link{measure_diverse_node}} + +Other measures: +\code{\link{measure_assort_node}}, +\code{\link{measure_breadth}}, +\code{\link{measure_broker_node}}, +\code{\link{measure_broker_tie}}, +\code{\link{measure_brokerage}}, +\code{\link{measure_central_between}}, +\code{\link{measure_central_close}}, +\code{\link{measure_central_degree}}, +\code{\link{measure_central_eigen}}, +\code{\link{measure_centralisation_between}}, +\code{\link{measure_centralisation_close}}, +\code{\link{measure_centralisation_degree}}, +\code{\link{measure_centralisation_eigen}}, +\code{\link{measure_centralities_between}}, +\code{\link{measure_centralities_close}}, +\code{\link{measure_centralities_degree}}, +\code{\link{measure_centralities_eigen}}, +\code{\link{measure_closure}}, +\code{\link{measure_closure_node}}, +\code{\link{measure_cohesion}}, +\code{\link{measure_core}}, +\code{\link{measure_diffusion_infection}}, +\code{\link{measure_diffusion_net}}, +\code{\link{measure_diffusion_node}}, +\code{\link{measure_diverse_net}}, +\code{\link{measure_diverse_node}}, +\code{\link{measure_features}}, +\code{\link{measure_fragmentation}}, +\code{\link{measure_hierarchy}}, +\code{\link{measure_periods}} +} +\concept{diversity} +\concept{measures} diff --git a/man/measure_assort_node.Rd b/man/measure_assort_node.Rd new file mode 100644 index 0000000..049d677 --- /dev/null +++ b/man/measure_assort_node.Rd @@ -0,0 +1,149 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/measure_heterogeneity.R +\name{measure_assort_node} +\alias{measure_assort_node} +\alias{node_by_heterophily} +\alias{node_by_homophily} +\title{Measures of nodes assortativity} +\usage{ +node_by_heterophily(.data, attribute) + +node_by_homophily( + .data, + attribute, + assortativity = c("ie", "ei", "yule", "geary") +) +} +\arguments{ +\item{.data}{A network object of class \code{mnet}, \code{igraph}, \code{tbl_graph}, \code{network}, or similar. +For more information on the standard coercion possible, +see \code{\link[manynet:manip_as]{manynet::as_tidygraph()}}.} + +\item{attribute}{Name of a nodal attribute, mark, measure, or membership vector.} + +\item{assortativity}{Which method to use for \verb{*_homophily()}. +Either "ie" (negative E-I index), "ei" (E-I index), +"yule" (Yule's Q), or "geary" (Geary's C). +Default is "ie". +The E-I index is the number of ties between (or \emph{external}) nodes +grouped in some mutually exclusive categories +minus the number of ties within (or \emph{internal}) these groups +divided by the total number of ties. +This value can range from 1 to -1, +where 1 indicates ties only between categories/groups and -1 ties only within categories/groups. + +Yule's Q is a measure of association for two binary variables, calculated as: +\deqn{Q = \frac{ad - bc}{ad + bc}} +where \eqn{a} is the number of ties between nodes in the same category, +\eqn{b} is the number of ties between nodes in different categories, +\eqn{c} is the number of non-ties between nodes in the same category, +and \eqn{d} is the number of non-ties between nodes in different categories. +This value can range from -1 to 1, where 1 indicates perfect association +(all ties are between nodes in the same category), -1 indicates perfect disassociation +(all ties are between nodes in different categories), and 0 indicates no association. + +Geary's C is a measure of spatial autocorrelation, calculated as: +\deqn{C = \frac{(n - 1) \sum + \limits_{i=1}^n \sum\limits_{j=1}^n w_{ij} (x_i - x_j)^2}{2W \sum\limits_{i=1}^n (x_i - \bar{x})^2}} +where \eqn{n} is the number of nodes, \eqn{ + w_{ij}} is the weight of the tie between nodes \eqn{i} and \eqn{j}, +\eqn{x_i} is the attribute value of node \eqn{i}, +\eqn{\bar{x}} is the mean attribute value across all nodes, and \eqn{W} is the sum of all tie weights. +This value can range from 0 to 2, where values less than 1 +indicate positive autocorrelation (similar values are more likely to be connected), +values greater than 1 indicate negative autocorrelation (dissimilar values are more likely +to be connected), and a value of 1 indicates no autocorrelation. +If an incompatible method is chosen for the attribute type, +a suitable alternative will be used instead with a message.} +} +\value{ +A \code{node_measure} numeric vector the length of the nodes in the network, +providing the scores for each node. +If the network is labelled, +then the scores will be labelled with the nodes' names. +} +\description{ +These functions offer ways to measure nodes' assortativity in a network: +\itemize{ +\item \code{node_by_heterophily()} measures each node's embeddedness within groups +of nodes with the same attribute. +\item \code{node_by_homophily()} measures each node's embeddedness within groups +of nodes with the same attribute, using a variety of methods. +} +} +\examples{ +marvel_friends <- to_unsigned(to_uniplex(fict_marvel, "relationship"), "positive") +node_by_heterophily(marvel_friends, "Gender") +node_by_heterophily(marvel_friends, "Attractive") +} +\seealso{ +Other diversity: +\code{\link{measure_assort_net}}, +\code{\link{measure_diverse_net}}, +\code{\link{measure_diverse_node}} + +Other measures: +\code{\link{measure_assort_net}}, +\code{\link{measure_breadth}}, +\code{\link{measure_broker_node}}, +\code{\link{measure_broker_tie}}, +\code{\link{measure_brokerage}}, +\code{\link{measure_central_between}}, +\code{\link{measure_central_close}}, +\code{\link{measure_central_degree}}, +\code{\link{measure_central_eigen}}, +\code{\link{measure_centralisation_between}}, +\code{\link{measure_centralisation_close}}, +\code{\link{measure_centralisation_degree}}, +\code{\link{measure_centralisation_eigen}}, +\code{\link{measure_centralities_between}}, +\code{\link{measure_centralities_close}}, +\code{\link{measure_centralities_degree}}, +\code{\link{measure_centralities_eigen}}, +\code{\link{measure_closure}}, +\code{\link{measure_closure_node}}, +\code{\link{measure_cohesion}}, +\code{\link{measure_core}}, +\code{\link{measure_diffusion_infection}}, +\code{\link{measure_diffusion_net}}, +\code{\link{measure_diffusion_node}}, +\code{\link{measure_diverse_net}}, +\code{\link{measure_diverse_node}}, +\code{\link{measure_features}}, +\code{\link{measure_fragmentation}}, +\code{\link{measure_hierarchy}}, +\code{\link{measure_periods}} + +Other nodal: +\code{\link{mark_core}}, +\code{\link{mark_degree}}, +\code{\link{mark_diff}}, +\code{\link{mark_nodes}}, +\code{\link{mark_select_node}}, +\code{\link{measure_broker_node}}, +\code{\link{measure_brokerage}}, +\code{\link{measure_central_between}}, +\code{\link{measure_central_close}}, +\code{\link{measure_central_degree}}, +\code{\link{measure_central_eigen}}, +\code{\link{measure_closure_node}}, +\code{\link{measure_core}}, +\code{\link{measure_diffusion_node}}, +\code{\link{measure_diverse_node}}, +\code{\link{member_brokerage}}, +\code{\link{member_cliques}}, +\code{\link{member_community}}, +\code{\link{member_community_hier}}, +\code{\link{member_community_non}}, +\code{\link{member_components}}, +\code{\link{member_core}}, +\code{\link{member_diffusion}}, +\code{\link{member_equivalence}}, +\code{\link{motif_brokerage_node}}, +\code{\link{motif_exposure}}, +\code{\link{motif_node}}, +\code{\link{motif_path}} +} +\concept{diversity} +\concept{measures} +\concept{nodal} diff --git a/man/measure_assortativity.Rd b/man/measure_assortativity.Rd deleted file mode 100644 index 5b96a06..0000000 --- a/man/measure_assortativity.Rd +++ /dev/null @@ -1,126 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/measure_heterogeneity.R -\name{measure_assortativity} -\alias{measure_assortativity} -\alias{net_by_heterophily} -\alias{node_by_heterophily} -\alias{net_by_homophily} -\alias{node_by_homophily} -\alias{net_by_assortativity} -\alias{net_by_spatial} -\title{Measures of network assortativity} -\usage{ -net_by_heterophily(.data, attribute) - -node_by_heterophily(.data, attribute) - -net_by_homophily(.data, attribute, method = c("ie", "ei", "yule", "geary")) - -node_by_homophily(.data, attribute, method = c("ie", "ei", "yule", "geary")) - -net_by_assortativity(.data) - -net_by_spatial(.data, attribute) -} -\arguments{ -\item{.data}{A network object of class \code{mnet}, \code{igraph}, \code{tbl_graph}, \code{network}, or similar. -For more information on the standard coercion possible, -see \code{\link[manynet:manip_as]{manynet::as_tidygraph()}}.} - -\item{attribute}{Name of a nodal attribute or membership vector -to use as categories for the diversity measure.} - -\item{method}{Which method to use for \code{net_diversity()}. -Either "blau" (Blau's index) or "teachman" (Teachman's index) for -categorical attributes, or "variation" (coefficient of variation) -or "gini" (Gini coefficient) for numeric attributes. -Default is "blau". -If an incompatible method is chosen for the attribute type, -a suitable alternative will be used instead with a message.} -} -\description{ -These functions offer ways to measure the distribution or assortativity -of ties in a network: -\itemize{ -\item \code{net_heterophily()} measures how embedded nodes in the network -are within groups of nodes with the same attribute. -\item \code{node_heterophily()} measures each node's embeddedness within groups -of nodes with the same attribute. -\item \code{net_assortativity()} measures the degree assortativity in a network. -\item \code{net_spatial()} measures the spatial association/autocorrelation -(global Moran's I) in a network. -} -} -\section{Homophily}{ - -Given a partition of a network into a number of mutually exclusive groups then -The E-I index is the number of ties between (or \emph{external}) nodes -grouped in some mutually exclusive categories -minus the number of ties within (or \emph{internal}) these groups -divided by the total number of ties. -This value can range from 1 to -1, -where 1 indicates ties only between categories/groups and -1 ties only within categories/groups. -} - -\examples{ -marvel_friends <- to_unsigned(to_uniplex(fict_marvel, "relationship"), "positive") -net_by_heterophily(marvel_friends, "Gender") -net_by_heterophily(marvel_friends, "Attractive") -node_by_heterophily(marvel_friends, "Gender") -node_by_heterophily(marvel_friends, "Attractive") -net_by_homophily(marvel_friends, "Gender") -net_by_assortativity(ison_networkers) -net_by_spatial(ison_lawfirm, "age") -} -\references{ -\subsection{On heterophily}{ - -Krackhardt, David, and Robert N. Stern. 1988. -Informal networks and organizational crises: an experimental simulation. -\emph{Social Psychology Quarterly} 51(2): 123-140. -\doi{10.2307/2786835} - -McPherson, Miller, Lynn Smith-Lovin, and James M. Cook. 2001. -"Birds of a Feather: Homophily in Social Networks". -\emph{Annual Review of Sociology}, 27(1): 415-444. -\doi{10.1146/annurev.soc.27.1.415} -} - -\subsection{On assortativity}{ - -Newman, Mark E.J. 2002. -"Assortative mixing in networks". -\emph{Physical Review Letters}, 89(20): 208701. -\doi{10.1103/physrevlett.89.208701} -} - -\subsection{On spatial autocorrelation}{ - -Moran, Patrick Alfred Pierce. 1950. -"Notes on continuous stochastic phenomena". -\emph{Biometrika} 37(1): 17-23. -\doi{10.2307/2332142} -} -} -\seealso{ -Other measures: -\code{\link{measure_breadth}}, -\code{\link{measure_brokerage}}, -\code{\link{measure_central_between}}, -\code{\link{measure_central_close}}, -\code{\link{measure_central_degree}}, -\code{\link{measure_central_eigen}}, -\code{\link{measure_closure}}, -\code{\link{measure_cohesion}}, -\code{\link{measure_diffusion_infection}}, -\code{\link{measure_diffusion_net}}, -\code{\link{measure_diffusion_node}}, -\code{\link{measure_features}}, -\code{\link{measure_fragmentation}}, -\code{\link{measure_heterogeneity}}, -\code{\link{measure_hierarchy}}, -\code{\link{measure_holes}}, -\code{\link{measure_periods}}, -\code{\link{member_diffusion}} -} -\concept{measures} diff --git a/man/measure_heterogeneity.Rd b/man/measure_diverse_net.Rd similarity index 76% rename from man/measure_heterogeneity.Rd rename to man/measure_diverse_net.Rd index ac38934..15c5f07 100644 --- a/man/measure_heterogeneity.Rd +++ b/man/measure_diverse_net.Rd @@ -1,27 +1,17 @@ % Generated by roxygen2: do not edit by hand % Please edit documentation in R/measure_heterogeneity.R -\name{measure_heterogeneity} -\alias{measure_heterogeneity} +\name{measure_diverse_net} +\alias{measure_diverse_net} \alias{net_by_richness} -\alias{node_by_richness} \alias{net_by_diversity} -\alias{node_by_diversity} \title{Measures of network diversity} \usage{ net_by_richness(.data, attribute) -node_by_richness(.data, attribute) - net_by_diversity( .data, attribute, - method = c("blau", "teachman", "variation", "gini") -) - -node_by_diversity( - .data, - attribute, - method = c("blau", "teachman", "variation", "gini") + diversity = c("blau", "teachman", "variation", "gini") ) } \arguments{ @@ -29,36 +19,26 @@ node_by_diversity( For more information on the standard coercion possible, see \code{\link[manynet:manip_as]{manynet::as_tidygraph()}}.} -\item{attribute}{Name of a nodal attribute or membership vector -to use as categories for the diversity measure.} +\item{attribute}{Name of a nodal attribute, mark, measure, or membership vector.} -\item{method}{Which method to use for \code{net_diversity()}. -Either "blau" (Blau's index) or "teachman" (Teachman's index) for -categorical attributes, or "variation" (coefficient of variation) -or "gini" (Gini coefficient) for numeric attributes. +\item{diversity}{Which method to use for \verb{*_diversity()}. +Either "blau" (Blau's index) or "teachman" (Teachman's index) for categorical attributes, +or "variation" (coefficient of variation) or "gini" (Gini coefficient) for numeric attributes. Default is "blau". If an incompatible method is chosen for the attribute type, a suitable alternative will be used instead with a message.} } +\value{ +A \code{network_measure} numeric score. +} \description{ These functions offer ways to measure the heterogeneity of an attribute across a network, within groups of a network, or the distribution of ties across this attribute: \itemize{ -\item \code{net_richness()} measures the number of unique categories +\item \code{net_by_richness()} measures the number of unique categories in a network attribute. -\item \code{node_richness()} measures the number of unique categories -of an attribute to which each node is connected. -\item \code{net_diversity()} measures the heterogeneity of ties across a network. -\item \code{node_diversity()} measures the heterogeneity of each node's -local neighbourhood. -\item \code{net_heterophily()} measures how embedded nodes in the network -are within groups of nodes with the same attribute. -\item \code{node_heterophily()} measures each node's embeddedness within groups -of nodes with the same attribute. -\item \code{net_assortativity()} measures the degree assortativity in a network. -\item \code{net_spatial()} measures the spatial association/autocorrelation -(global Moran's I) in a network. +\item \code{net_by_diversity()} measures the heterogeneity of ties across a network. } } \section{Richness}{ @@ -126,12 +106,9 @@ divided by the total area under the line of equality. \examples{ net_by_richness(ison_networkers) -node_by_richness(ison_networkers, "Discipline") marvel_friends <- to_unsigned(to_uniplex(fict_marvel, "relationship"), "positive") net_by_diversity(marvel_friends, "Gender") net_by_diversity(marvel_friends, "Appearances") -node_by_diversity(marvel_friends, "Gender") -node_by_diversity(marvel_friends, "Attractive") } \references{ \subsection{On richness}{ @@ -160,24 +137,42 @@ Princeton: Princeton University Press. } } \seealso{ +Other diversity: +\code{\link{measure_assort_net}}, +\code{\link{measure_assort_node}}, +\code{\link{measure_diverse_node}} + Other measures: -\code{\link{measure_assortativity}}, +\code{\link{measure_assort_net}}, +\code{\link{measure_assort_node}}, \code{\link{measure_breadth}}, +\code{\link{measure_broker_node}}, +\code{\link{measure_broker_tie}}, \code{\link{measure_brokerage}}, \code{\link{measure_central_between}}, \code{\link{measure_central_close}}, \code{\link{measure_central_degree}}, \code{\link{measure_central_eigen}}, +\code{\link{measure_centralisation_between}}, +\code{\link{measure_centralisation_close}}, +\code{\link{measure_centralisation_degree}}, +\code{\link{measure_centralisation_eigen}}, +\code{\link{measure_centralities_between}}, +\code{\link{measure_centralities_close}}, +\code{\link{measure_centralities_degree}}, +\code{\link{measure_centralities_eigen}}, \code{\link{measure_closure}}, +\code{\link{measure_closure_node}}, \code{\link{measure_cohesion}}, +\code{\link{measure_core}}, \code{\link{measure_diffusion_infection}}, \code{\link{measure_diffusion_net}}, \code{\link{measure_diffusion_node}}, +\code{\link{measure_diverse_node}}, \code{\link{measure_features}}, \code{\link{measure_fragmentation}}, \code{\link{measure_hierarchy}}, -\code{\link{measure_holes}}, -\code{\link{measure_periods}}, -\code{\link{member_diffusion}} +\code{\link{measure_periods}} } +\concept{diversity} \concept{measures} diff --git a/man/measure_diverse_node.Rd b/man/measure_diverse_node.Rd new file mode 100644 index 0000000..8965f04 --- /dev/null +++ b/man/measure_diverse_node.Rd @@ -0,0 +1,124 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/measure_heterogeneity.R +\name{measure_diverse_node} +\alias{measure_diverse_node} +\alias{node_by_richness} +\alias{node_by_diversity} +\title{Measures of nodes diversity} +\usage{ +node_by_richness(.data, attribute) + +node_by_diversity( + .data, + attribute, + diversity = c("blau", "teachman", "variation", "gini") +) +} +\arguments{ +\item{.data}{A network object of class \code{mnet}, \code{igraph}, \code{tbl_graph}, \code{network}, or similar. +For more information on the standard coercion possible, +see \code{\link[manynet:manip_as]{manynet::as_tidygraph()}}.} + +\item{attribute}{Name of a nodal attribute, mark, measure, or membership vector.} + +\item{diversity}{Which method to use for \verb{*_diversity()}. +Either "blau" (Blau's index) or "teachman" (Teachman's index) for categorical attributes, +or "variation" (coefficient of variation) or "gini" (Gini coefficient) for numeric attributes. +Default is "blau". +If an incompatible method is chosen for the attribute type, +a suitable alternative will be used instead with a message.} +} +\value{ +A \code{node_measure} numeric vector the length of the nodes in the network, +providing the scores for each node. +If the network is labelled, +then the scores will be labelled with the nodes' names. +} +\description{ +These functions offer ways to measure the heterogeneity of an attribute +across a network, within groups of a network, or the distribution of ties +across this attribute: +\itemize{ +\item \code{node_by_richness()} measures the number of unique categories +of an attribute to which each node is connected. +\item \code{node_by_diversity()} measures the heterogeneity of each node's +local neighbourhood. +} +} +\examples{ +node_by_richness(ison_networkers, "Discipline") +marvel_friends <- to_unsigned(to_uniplex(fict_marvel, "relationship"), "positive") +node_by_diversity(marvel_friends, "Gender") +node_by_diversity(marvel_friends, "Attractive") +} +\seealso{ +Other diversity: +\code{\link{measure_assort_net}}, +\code{\link{measure_assort_node}}, +\code{\link{measure_diverse_net}} + +Other measures: +\code{\link{measure_assort_net}}, +\code{\link{measure_assort_node}}, +\code{\link{measure_breadth}}, +\code{\link{measure_broker_node}}, +\code{\link{measure_broker_tie}}, +\code{\link{measure_brokerage}}, +\code{\link{measure_central_between}}, +\code{\link{measure_central_close}}, +\code{\link{measure_central_degree}}, +\code{\link{measure_central_eigen}}, +\code{\link{measure_centralisation_between}}, +\code{\link{measure_centralisation_close}}, +\code{\link{measure_centralisation_degree}}, +\code{\link{measure_centralisation_eigen}}, +\code{\link{measure_centralities_between}}, +\code{\link{measure_centralities_close}}, +\code{\link{measure_centralities_degree}}, +\code{\link{measure_centralities_eigen}}, +\code{\link{measure_closure}}, +\code{\link{measure_closure_node}}, +\code{\link{measure_cohesion}}, +\code{\link{measure_core}}, +\code{\link{measure_diffusion_infection}}, +\code{\link{measure_diffusion_net}}, +\code{\link{measure_diffusion_node}}, +\code{\link{measure_diverse_net}}, +\code{\link{measure_features}}, +\code{\link{measure_fragmentation}}, +\code{\link{measure_hierarchy}}, +\code{\link{measure_periods}} + +Other nodal: +\code{\link{mark_core}}, +\code{\link{mark_degree}}, +\code{\link{mark_diff}}, +\code{\link{mark_nodes}}, +\code{\link{mark_select_node}}, +\code{\link{measure_assort_node}}, +\code{\link{measure_broker_node}}, +\code{\link{measure_brokerage}}, +\code{\link{measure_central_between}}, +\code{\link{measure_central_close}}, +\code{\link{measure_central_degree}}, +\code{\link{measure_central_eigen}}, +\code{\link{measure_closure_node}}, +\code{\link{measure_core}}, +\code{\link{measure_diffusion_node}}, +\code{\link{member_brokerage}}, +\code{\link{member_cliques}}, +\code{\link{member_community}}, +\code{\link{member_community_hier}}, +\code{\link{member_community_non}}, +\code{\link{member_components}}, +\code{\link{member_core}}, +\code{\link{member_diffusion}}, +\code{\link{member_equivalence}}, +\code{\link{motif_brokerage_node}}, +\code{\link{motif_exposure}}, +\code{\link{motif_node}}, +\code{\link{motif_path}} +} +\concept{diversity} +\concept{measures} +\concept{nodal} diff --git a/man/member_brokerage.Rd b/man/member_brokerage.Rd index 5dceab8..1670625 100644 --- a/man/member_brokerage.Rd +++ b/man/member_brokerage.Rd @@ -3,7 +3,7 @@ \name{member_brokerage} \alias{member_brokerage} \alias{node_in_brokering} -\title{Memberships of brokerage} +\title{Memberships in brokerage positions} \usage{ node_in_brokering(.data, membership) } @@ -12,28 +12,80 @@ node_in_brokering(.data, membership) For more information on the standard coercion possible, see \code{\link[manynet:manip_as]{manynet::as_tidygraph()}}.} -\item{membership}{A vector of partition membership as integers.} +\item{membership}{A character vector of categorical membership. +This is a vector of the same length as the number of nodes in the network, +where each element is a character string indicating the membership of the corresponding node. +While this may often be a vector created using \verb{node_in_*()} functions, +it can be any character vector that assigns nodes to groups or categories.} +} +\value{ +A \code{node_member} character vector the length of the nodes in the network, +of group memberships "A", "B", etc for each node. +If the network is labelled, +then the assignments will be labelled with the nodes' names. } \description{ -These functions include ways to take a census of the brokerage positions of nodes -in a network: -\itemize{ -\item \code{node_in_brokerage()} returns nodes membership as a powerhouse, +\code{node_in_brokerage()} returns nodes membership as a powerhouse, connector, linchpin, or sideliner according to Hamilton et al. (2020). } +\references{ +\subsection{On brokerage activity and exclusivity}{ + +Hamilton, Matthew, Jacob Hileman, and Orjan Bodin. 2020. +"Evaluating heterogeneous brokerage: New conceptual and methodological approaches +and their application to multi-level environmental governance networks" +\emph{Social Networks} 61: 1-10. +\doi{10.1016/j.socnet.2019.08.002} +} } \seealso{ +Other brokerage: +\code{\link{measure_broker_node}}, +\code{\link{measure_broker_tie}}, +\code{\link{measure_brokerage}}, +\code{\link{motif_brokerage_net}}, +\code{\link{motif_brokerage_node}} + Other memberships: -\code{\link{mark_core}}, \code{\link{member_cliques}}, +\code{\link{member_community}}, \code{\link{member_community_hier}}, \code{\link{member_community_non}}, \code{\link{member_components}}, +\code{\link{member_core}}, +\code{\link{member_diffusion}}, \code{\link{member_equivalence}} -Other brokerage: +Other nodal: +\code{\link{mark_core}}, +\code{\link{mark_degree}}, +\code{\link{mark_diff}}, +\code{\link{mark_nodes}}, +\code{\link{mark_select_node}}, +\code{\link{measure_assort_node}}, +\code{\link{measure_broker_node}}, \code{\link{measure_brokerage}}, -\code{\link{motif_brokerage}} +\code{\link{measure_central_between}}, +\code{\link{measure_central_close}}, +\code{\link{measure_central_degree}}, +\code{\link{measure_central_eigen}}, +\code{\link{measure_closure_node}}, +\code{\link{measure_core}}, +\code{\link{measure_diffusion_node}}, +\code{\link{measure_diverse_node}}, +\code{\link{member_cliques}}, +\code{\link{member_community}}, +\code{\link{member_community_hier}}, +\code{\link{member_community_non}}, +\code{\link{member_components}}, +\code{\link{member_core}}, +\code{\link{member_diffusion}}, +\code{\link{member_equivalence}}, +\code{\link{motif_brokerage_node}}, +\code{\link{motif_exposure}}, +\code{\link{motif_node}}, +\code{\link{motif_path}} } \concept{brokerage} \concept{memberships} +\concept{nodal} From c423ff23ae888e8f23a8cc331690182ce02c0549 Mon Sep 17 00:00:00 2001 From: James Hollway Date: Sat, 21 Mar 2026 18:12:32 +0100 Subject: [PATCH 13/35] Using motif argument instead of census for consistency --- R/member_equivalence.R | 55 ++++--- R/{model_cluster.R => method_cluster.R} | 45 ++++-- R/method_k.R | 16 +- R/motif_census.R | 167 ++++++++++++-------- man-roxygen/param_motf.R | 1 + man/member_equivalence.Rd | 65 ++++++-- man/{model_cluster.Rd => method_cluster.Rd} | 46 ++++-- man/method_kselect.Rd | 9 +- man/motif_net.Rd | 32 +++- man/motif_node.Rd | 90 +++++++---- man/motif_path.Rd | 98 ++++++++++++ 11 files changed, 443 insertions(+), 181 deletions(-) rename R/{model_cluster.R => method_cluster.R} (76%) create mode 100644 man-roxygen/param_motf.R rename man/{model_cluster.Rd => method_cluster.Rd} (62%) create mode 100644 man/motif_path.Rd diff --git a/R/member_equivalence.R b/R/member_equivalence.R index d357218..0b58cb4 100644 --- a/R/member_equivalence.R +++ b/R/member_equivalence.R @@ -1,27 +1,26 @@ -#' Equivalence clustering algorithms -#' +#' Memberships in equivalent classes #' @description -#' These functions combine an appropriate `node_by_*()` function +#' These functions combine an appropriate `node_x_*()` function #' together with methods for calculating the hierarchical clusters #' provided by a certain distance calculation. #' #' - `node_in_equivalence()` assigns nodes membership based on their equivalence -#' with respective to some census/class. -#' The following functions call this function, together with an appropriate census. -#' - `node_in_structural()` assigns nodes membership based on their -#' having equivalent ties to the same other nodes. -#' - `node_in_regular()` assigns nodes membership based on their -#' having equivalent patterns of ties. -#' - `node_in_automorphic()` assigns nodes membership based on their -#' having equivalent distances to other nodes. +#' with respective to some motif/class. +#' The following functions call this function, together with an appropriate motif. +#' - `node_in_structural()` assigns nodes membership based on their +#' having equivalent ties to the same other nodes. +#' - `node_in_regular()` assigns nodes membership based on their +#' having equivalent patterns of ties. +#' - `node_in_automorphic()` assigns nodes membership based on their +#' having equivalent distances to other nodes. #' #' A `plot()` method exists for investigating the dendrogram #' of the hierarchical cluster and showing the returned cluster #' assignment. #' @name member_equivalence -#' @family memberships -#' @inheritParams mark_nodes -#' @param census A matrix returned by a `node_by_*()` function. +#' @template param_data +#' @template param_motf +#' @template node_member #' @param k Typically a character string indicating which method #' should be used to select the number of clusters to return. #' By default `"silhouette"`, other options include `"elbow"` and `"strict"`. @@ -40,7 +39,7 @@ #' By default `"euclidean"`, but other options include #' `"maximum"`, `"manhattan"`, `"canberra"`, `"binary"`, and `"minkowski"`. #' Fewer, identifiable letters, e.g. `"e"` for Euclidean, is sufficient. -#' @param range Integer indicating the maximum number of (k) clusters +#' @param Kmax Integer indicating the maximum number of (k) clusters #' to evaluate. #' Ignored when `k = "strict"` or a discrete number is given for `k`. #' @importFrom stats as.dist hclust cutree coef cor median @@ -49,25 +48,25 @@ NULL #' @rdname member_equivalence #' @export -node_in_equivalence <- function(.data, census, +node_in_equivalence <- function(.data, motif, k = c("silhouette", "elbow", "strict"), cluster = c("hierarchical", "concor", "cosine"), distance = c("euclidean", "maximum", "manhattan", "canberra", "binary", "minkowski"), - range = 8L){ + Kmax = 8L){ .data <- manynet::expect_nodes(.data) hc <- switch(match.arg(cluster), - hierarchical = cluster_hierarchical(census, + hierarchical = cluster_hierarchical(motif, match.arg(distance)), - concor = cluster_concor(.data, census), - cosine = cluster_cosine(census, + concor = cluster_concor(.data, motif), + cosine = cluster_cosine(motif, match.arg(distance))) if(!is.numeric(k)) k <- switch(match.arg(k), strict = k_strict(hc, .data), - elbow = k_elbow(hc, .data, census, range), - silhouette = k_silhouette(hc, .data, range)) + elbow = k_elbow(hc, .data, motif, Kmax), + silhouette = k_silhouette(hc, .data, Kmax)) if(length(k)==0) k <- 1 # in the case of all nodes being in the same cluster out <- make_node_member(stats::cutree(hc, k), .data) @@ -85,14 +84,14 @@ node_in_structural <- function(.data, cluster = c("hierarchical", "concor","cosine"), distance = c("euclidean", "maximum", "manhattan", "canberra", "binary", "minkowski"), - range = 8L){ + Kmax = 8L){ .data <- manynet::expect_nodes(.data) mat <- node_x_tie(.data) if(any(colSums(t(mat))==0)){ mat <- cbind(mat, (colSums(t(mat))==0)) } node_in_equivalence(.data, mat, - k = k, cluster = cluster, distance = distance, range = range) + k = k, cluster = cluster, distance = distance, Kmax = Kmax) } #' @rdname member_equivalence @@ -105,7 +104,7 @@ node_in_regular <- function(.data, cluster = c("hierarchical", "concor","cosine"), distance = c("euclidean", "maximum", "manhattan", "canberra", "binary", "minkowski"), - range = 8L){ + Kmax = 8L){ .data <- manynet::expect_nodes(.data) if(manynet::is_twomode(.data)){ manynet::snet_info("Since this is a two-mode network,", @@ -120,7 +119,7 @@ node_in_regular <- function(.data, } if(any(colSums(mat) == 0)) mat <- mat[,-which(colSums(mat) == 0)] node_in_equivalence(.data, mat, - k = k, cluster = cluster, distance = distance, range = range) + k = k, cluster = cluster, distance = distance, Kmax = Kmax) } #' @rdname member_equivalence @@ -135,9 +134,9 @@ node_in_automorphic <- function(.data, cluster = c("hierarchical", "concor","cosine"), distance = c("euclidean", "maximum", "manhattan", "canberra", "binary", "minkowski"), - range = 8L){ + Kmax = 8L){ .data <- manynet::expect_nodes(.data) mat <- node_x_path(.data) node_in_equivalence(.data, mat, - k = k, cluster = cluster, distance = distance, range = range) + k = k, cluster = cluster, distance = distance, Kmax = Kmax) } diff --git a/R/model_cluster.R b/R/method_cluster.R similarity index 76% rename from R/model_cluster.R rename to R/method_cluster.R index af7cdca..a34ffa0 100644 --- a/R/model_cluster.R +++ b/R/method_cluster.R @@ -1,7 +1,7 @@ #' Methods for equivalence clustering #' #' @description -#' These functions are used to cluster some census object: +#' These functions are used to cluster some motif census object: #' #' - `cluster_hierarchical()` returns a hierarchical clustering object #' created by `stats::hclust()`. @@ -14,14 +14,26 @@ #' These functions are not intended to be called directly, #' but are called within `node_in_equivalence()` and related functions. #' They are exported and listed here to provide more detailed documentation. -#' @name model_cluster +#' @name method_cluster #' @inheritParams member_equivalence +#' @returns +#' A hierarchical clustering object created by `stats::hclust()`, +#' with an additional `distances` attribute containing the distance matrix +#' used for clustering. NULL -#' @rdname model_cluster +#' @rdname method_cluster +#' @section Hierarchical clustering: +#' This method uses `stats::hclust()` to create a hierarchical clustering object +#' from a distance matrix created from the correlations between nodes' profiles +#' in the given motif census. +#' First a matrix of Pearson correlation coefficients between each pair of +#' nodes' profiles in the given motif census is created. +#' Then a distance matrix is created by subtracting these correlations from `1`, +#' and this is given to `stats::hclust()` to enable dendrogram construction etc. #' @export -cluster_hierarchical <- function(census, distance){ - correlations <- manynet::to_correlation(t(census)) +cluster_hierarchical <- function(motif, distance){ + correlations <- manynet::to_correlation(t(motif)) dissimilarity <- 1 - correlations distances <- stats::dist(dissimilarity, method = distance) hc <- stats::hclust(distances) @@ -29,10 +41,17 @@ cluster_hierarchical <- function(census, distance){ hc } -#' @rdname model_cluster +#' @rdname method_cluster +#' @section Cosine similarity: +#' This method is similar to the hierarchical clustering method, +#' but uses cosine similarity rather than correlation as the clustering basis. +#' First a matrix of cosine similarities between each pair of nodes' profiles +#' in the given census is created. +#' Then a distance matrix is created by subtracting these similarities from `1`, +#' and this is given to `stats::hclust` to enable dendrogram construction etc. #' @export -cluster_cosine <- function(census, distance){ - cosines <- manynet::to_cosine(census) +cluster_cosine <- function(motif, distance){ + cosines <- manynet::to_cosine(motif) dissimilarity <- 1 - cosines distances <- stats::dist(dissimilarity, method = distance) hc <- stats::hclust(distances) @@ -44,10 +63,10 @@ cluster_cosine <- function(census, distance){ # cluster_concor(ison_southern_women) # https://github.com/bwlewis/hclust_in_R/blob/master/hc.R -#' @rdname model_cluster +#' @rdname method_cluster #' @section CONCOR: -#' First a matrix of Pearson correlation coefficients between each pair of nodes -#' profiles in the given census is created. +#' First a matrix of Pearson correlation coefficients between each pair of +#' nodes' profiles in the given motif census is created. #' Then, again, we find the correlations of this square, symmetric matrix, #' and continue to do this iteratively until each entry is either `1` or `-1`. #' These values are used to split the data into two partitions, @@ -68,7 +87,7 @@ cluster_cosine <- function(census, distance){ #' _Journal of Mathematical Psychology_, 12: 328-83. #' \doi{10.1016/0022-2496(75)90028-0}. #' @export -cluster_concor <- function(.data, census){ +cluster_concor <- function(.data, motif){ .data <- manynet::expect_nodes(.data) split_cor <- function(m0, cutoff = 1) { if (ncol(m0) < 2 | all(manynet::to_correlation(m0)==1)) list(m0) @@ -87,7 +106,7 @@ cluster_concor <- function(.data, census){ } } } - p_list <- list(t(census)) + p_list <- list(t(motif)) if(is.null(colnames(p_list[[1]]))) colnames(p_list[[1]]) <- paste0("V",1:ncol(p_list[[1]])) p_group <- list() diff --git a/R/method_k.R b/R/method_k.R index a71e70e..740c6c3 100644 --- a/R/method_k.R +++ b/R/method_k.R @@ -185,9 +185,11 @@ k_silhouette <- function(hc, .data, Kmax){ k } -#' @rdname method_kselect +#' @rdname method_kselect +#' @param sims Integer of how many simulations should be generated as a +#' reference distribution. #' @export -k_gap <- function(hc, motif, Kmax, B = 100) { +k_gap <- function(hc, motif, Kmax, sims = 100) { if(missing(Kmax)) Kmax <- length(hc$order) else Kmax <- min(Kmax, length(hc$order)) @@ -211,7 +213,7 @@ k_gap <- function(hc, motif, Kmax, B = 100) { # storage logW <- numeric(Kmax) - logW_ref <- matrix(0, nrow = B, ncol = Kmax) + logW_ref <- matrix(0, nrow = sims, ncol = Kmax) # --- real data W_k --- for (k in 1:Kmax) { @@ -220,9 +222,9 @@ k_gap <- function(hc, motif, Kmax, B = 100) { } # --- reference datasets --- - for (b in 1:B) { - ref <- matrix(runif(n * p, mins, maxs), nrow = n) - d_ref <- dist(ref) + for (b in 1:sims) { + ref <- matrix(stats::runif(n * p, mins, maxs), nrow = n) + d_ref <- stats::dist(ref) hc_ref <- hclust(d_ref, method = hc$method) for (k in 1:Kmax) { @@ -233,7 +235,7 @@ k_gap <- function(hc, motif, Kmax, B = 100) { # --- gap statistic --- gap <- colMeans(logW_ref) - logW - se <- sqrt(1 + 1/B) * apply(logW_ref, 2, sd) + se <- sqrt(1 + 1/B) * apply(logW_ref, 2, stats::sd) # --- Tibshirani 1-SE rule --- k <- which(gap[-Kmax] >= gap[-1] - se[-1])[1] diff --git a/R/motif_census.R b/R/motif_census.R index b712dc1..9568880 100644 --- a/R/motif_census.R +++ b/R/motif_census.R @@ -1,28 +1,23 @@ -# Node censuses #### +# Node path #### -#' Motifs at the nodal level -#' +#' Motifs of nodes pathing +#' @name motif_path #' @description #' These functions include ways to take a census of the positions of nodes #' in a network: #' -#' - `node_by_tie()` returns a census of the ties in a network. +#' - `node_x_tie()` returns a census of the ties in a network. #' For directed networks, out-ties and in-ties are bound together. #' For multiplex networks, the various types of ties are bound together. -#' - `node_by_triad()` returns a census of the triad configurations -#' nodes are embedded in. -#' - `node_by_tetrad()` returns a census of nodes' positions -#' in motifs of four nodes. -#' - `node_by_path()` returns the shortest path lengths +#' - `node_x_path()` returns the shortest path lengths #' of each node to every other node in the network. #' -#' @name motif_node -#' @family motifs -#' @inheritParams mark_nodes +#' @template param_data +#' @template node_motif #' @importFrom igraph vcount make_ego_graph delete_vertices triad_census NULL -#' @rdname motif_node +#' @rdname motif_path #' @examples #' task_eg <- to_named(to_uniplex(ison_algebra, "tasks")) #' (tie_cen <- node_x_tie(task_eg)) @@ -45,10 +40,10 @@ node_x_tie <- function(.data){ rbind(rc, t(rc)) })) - } else { - rc <- manynet::as_matrix(object) - mat <- rbind(rc, t(rc)) - } + } else { + rc <- manynet::as_matrix(object) + mat <- rbind(rc, t(rc)) + } } else { if (manynet::is_multiplex(.data)) { mat <- do.call(rbind, lapply(unique(manynet::tie_attribute(object, "type")), @@ -70,7 +65,7 @@ node_x_tie <- function(.data){ if(manynet::is_multiplex(.data)){ rownames(mat) <- apply(expand.grid(c(paste0("from", manynet::node_names(object)), paste0("to", manynet::node_names(object))), - unique(manynet::tie_attribute(object, "type"))), + unique(manynet::tie_attribute(object, "type"))), 1, paste, collapse = "_") } else if (manynet::is_longitudinal(object)){ rownames(mat) <- apply(expand.grid(c(paste0("from", manynet::node_names(object)), @@ -84,6 +79,57 @@ node_x_tie <- function(.data){ make_node_motif(t(mat), object) } +#' @rdname motif_path +#' @importFrom igraph distances +#' @references +#' ## On paths +#' Dijkstra, Edsger W. 1959. +#' "A note on two problems in connexion with graphs". +#' _Numerische Mathematik_ 1, 269-71. +#' \doi{10.1007/BF01386390}. +#' +#' Opsahl, Tore, Filip Agneessens, and John Skvoretz. 2010. +#' "Node centrality in weighted networks: Generalizing degree and shortest paths". +#' _Social Networks_ 32(3): 245-51. +#' \doi{10.1016/j.socnet.2010.03.006}. +#' @examples +#' node_x_path(ison_adolescents) +#' node_x_path(ison_southern_women) +#' @export +node_x_path <- function(.data){ + .data <- manynet::expect_nodes(.data) + if(manynet::is_weighted(.data)){ + tore <- manynet::as_matrix(.data)/mean(manynet::as_matrix(.data)) + out <- 1/tore + } else out <- igraph::distances(manynet::as_igraph(.data)) + diag(out) <- 0 + make_node_motif(out, .data) +} + +# Node cohesion #### + +#' Motifs of nodes cohesion +#' @name motif_node +#' @description +#' These functions include ways to take a census of the positions of nodes +#' in a network: +#' +#' - `node_x_tie()` returns a census of the ties in a network. +#' For directed networks, out-ties and in-ties are bound together. +#' For multiplex networks, the various types of ties are bound together. +#' - `node_x_triad()` returns a census of the triad configurations +#' nodes are embedded in. +#' - `node_x_tetrad()` returns a census of nodes' positions +#' in motifs of four nodes. +#' - `node_x_path()` returns the shortest path lengths +#' of each node to every other node in the network. +#' +#' @template param_data +#' @family cohesion +#' @template node_motif +#' @importFrom igraph vcount make_ego_graph delete_vertices triad_census +NULL + #' @rdname motif_node #' @references #' ## On the dyad census @@ -116,6 +162,7 @@ node_x_dyad <- function(.data) { #' Davis, James A., and Samuel Leinhardt. 1967. #' “\href{https://files.eric.ed.gov/fulltext/ED024086.pdf}{The Structure of Positive Interpersonal Relations in Small Groups}.” 55. #' @examples +#' task_eg <- to_named(to_uniplex(ison_algebra, "tasks")) #' (triad_cen <- node_x_triad(task_eg)) #' @export node_x_triad <- function(.data){ @@ -255,52 +302,25 @@ node_x_tetrad <- function(.data){ # make_node_motif(out, .data) # } -#' @rdname motif_node -#' @importFrom igraph distances -#' @references -#' ## On paths -#' Dijkstra, Edsger W. 1959. -#' "A note on two problems in connexion with graphs". -#' _Numerische Mathematik_ 1, 269-71. -#' \doi{10.1007/BF01386390}. -#' -#' Opsahl, Tore, Filip Agneessens, and John Skvoretz. 2010. -#' "Node centrality in weighted networks: Generalizing degree and shortest paths". -#' _Social Networks_ 32(3): 245-51. -#' \doi{10.1016/j.socnet.2010.03.006}. -#' @examples -#' node_x_path(ison_adolescents) -#' node_x_path(ison_southern_women) -#' @export -node_x_path <- function(.data){ - .data <- manynet::expect_nodes(.data) - if(manynet::is_weighted(.data)){ - tore <- manynet::as_matrix(.data)/mean(manynet::as_matrix(.data)) - out <- 1/tore - } else out <- igraph::distances(manynet::as_igraph(.data)) - diag(out) <- 0 - make_node_motif(out, .data) -} - -# Network censuses #### +# Network cohesion #### -#' Motifs at the network level -#' +#' Motifs of network cohesion +#' @name motif_net #' @description #' These functions include ways to take a census of the graphlets #' in a network: #' -#' - `net_by_dyad()` returns a census of dyad motifs in a network. -#' - `net_by_triad()` returns a census of triad motifs in a network. -#' - `net_by_tetrad()` returns a census of tetrad motifs in a network. -#' - `net_by_mixed()` returns a census of triad motifs that span +#' - `net_x_dyad()` returns a census of dyad motifs in a network. +#' - `net_x_triad()` returns a census of triad motifs in a network. +#' - `net_x_tetrad()` returns a census of tetrad motifs in a network. +#' - `net_x_mixed()` returns a census of triad motifs that span #' a one-mode and a two-mode network. #' #' See also \href{https://www.graphclasses.org/smallgraphs.html}{graph classes}. #' -#' @name motif_net -#' @family motifs -#' @inheritParams motif_node +#' @template param_data +#' @family cohesion +#' @template net_motif #' @param object2 A second, two-mode network object. NULL @@ -526,25 +546,20 @@ net_x_mixed <- function (.data, object2) { make_network_motif(res, .data) } -# Diffusion #### +# Exposure #### -#' Motifs of diffusion -#' +#' Motifs of nodes exposure +#' @name motif_exposure #' @description -#' - `net_by_hazard()` measures the hazard rate or instantaneous probability that -#' nodes will adopt/become infected at that time. -#' - `node_by_exposure()` produces a motif matrix of nodes' exposure to +#' `node_x_exposure()` produces a motif matrix of nodes' exposure to #' infection/adoption by time step. #' -#' @family motifs +#' @template param_data #' @family diffusion -#' @inheritParams motif_node -#' @inheritParams measure_diffusion_net -#' @name motif_diffusion -#' +#' @template node_motif NULL -#' @rdname motif_diffusion +#' @rdname motif_exposure #' @examples #' node_x_exposure(play_diffusion(create_tree(12))) #' @export @@ -569,9 +584,23 @@ node_x_exposure <- function(.data){ make_node_motif(out, .data) } -#' @rdname motif_diffusion +# Hazard #### + +#' Motifs of network hazard +#' @name motif_hazard +#' @description +#' `net_x_hazard()` measures the hazard rate or instantaneous probability that +#' nodes will adopt/become infected at that time. +#' +#' @template param_data +#' @family diffusion +#' @template net_motif +NULL + +#' @rdname motif_hazard #' @section Hazard rate: -#' The hazard rate is the instantaneous probability of adoption/infection at each time point (Allison 1984). +#' The hazard rate is the instantaneous probability of adoption/infection +#' at each time point (Allison 1984). #' In survival analysis, hazard rate is formally defined as: #' #' \deqn{% diff --git a/man-roxygen/param_motf.R b/man-roxygen/param_motf.R new file mode 100644 index 0000000..f295158 --- /dev/null +++ b/man-roxygen/param_motf.R @@ -0,0 +1 @@ +#' @param motif A matrix returned by a `node_x_*()` function. diff --git a/man/member_equivalence.Rd b/man/member_equivalence.Rd index ba1ad4c..2077fcd 100644 --- a/man/member_equivalence.Rd +++ b/man/member_equivalence.Rd @@ -6,18 +6,18 @@ \alias{node_in_structural} \alias{node_in_regular} \alias{node_in_automorphic} -\title{Equivalence clustering algorithms} +\title{Memberships in equivalent classes} \source{ \url{https://github.com/aslez/concoR} } \usage{ node_in_equivalence( .data, - census, + motif, k = c("silhouette", "elbow", "strict"), cluster = c("hierarchical", "concor", "cosine"), distance = c("euclidean", "maximum", "manhattan", "canberra", "binary", "minkowski"), - range = 8L + Kmax = 8L ) node_in_structural( @@ -25,7 +25,7 @@ node_in_structural( k = c("silhouette", "elbow", "strict"), cluster = c("hierarchical", "concor", "cosine"), distance = c("euclidean", "maximum", "manhattan", "canberra", "binary", "minkowski"), - range = 8L + Kmax = 8L ) node_in_regular( @@ -33,7 +33,7 @@ node_in_regular( k = c("silhouette", "elbow", "strict"), cluster = c("hierarchical", "concor", "cosine"), distance = c("euclidean", "maximum", "manhattan", "canberra", "binary", "minkowski"), - range = 8L + Kmax = 8L ) node_in_automorphic( @@ -41,7 +41,7 @@ node_in_automorphic( k = c("silhouette", "elbow", "strict"), cluster = c("hierarchical", "concor", "cosine"), distance = c("euclidean", "maximum", "manhattan", "canberra", "binary", "minkowski"), - range = 8L + Kmax = 8L ) } \arguments{ @@ -49,7 +49,7 @@ node_in_automorphic( For more information on the standard coercion possible, see \code{\link[manynet:manip_as]{manynet::as_tidygraph()}}.} -\item{census}{A matrix returned by a \verb{node_by_*()} function.} +\item{motif}{A matrix returned by a \verb{node_x_*()} function.} \item{k}{Typically a character string indicating which method should be used to select the number of clusters to return. @@ -72,19 +72,24 @@ By default \code{"euclidean"}, but other options include \code{"maximum"}, \code{"manhattan"}, \code{"canberra"}, \code{"binary"}, and \code{"minkowski"}. Fewer, identifiable letters, e.g. \code{"e"} for Euclidean, is sufficient.} -\item{range}{Integer indicating the maximum number of (k) clusters +\item{Kmax}{Integer indicating the maximum number of (k) clusters to evaluate. Ignored when \code{k = "strict"} or a discrete number is given for \code{k}.} } +\value{ +A \code{node_member} character vector the length of the nodes in the network, +of group memberships "A", "B", etc for each node. +If the network is labelled, +then the assignments will be labelled with the nodes' names. +} \description{ -These functions combine an appropriate \verb{node_by_*()} function +These functions combine an appropriate \verb{node_x_*()} function together with methods for calculating the hierarchical clusters provided by a certain distance calculation. \itemize{ \item \code{node_in_equivalence()} assigns nodes membership based on their equivalence -with respective to some census/class. -The following functions call this function, together with an appropriate census. -\itemize{ +with respective to some motif/class. +The following functions call this function, together with an appropriate motif. \item \code{node_in_structural()} assigns nodes membership based on their having equivalent ties to the same other nodes. \item \code{node_in_regular()} assigns nodes membership based on their @@ -92,7 +97,6 @@ having equivalent patterns of ties. \item \code{node_in_automorphic()} assigns nodes membership based on their having equivalent distances to other nodes. } -} A \code{plot()} method exists for investigating the dendrogram of the hierarchical cluster and showing the returned cluster @@ -109,11 +113,44 @@ if(require("sna", quietly = TRUE)){ } \seealso{ Other memberships: +\code{\link{member_brokerage}}, +\code{\link{member_cliques}}, +\code{\link{member_community}}, +\code{\link{member_community_hier}}, +\code{\link{member_community_non}}, +\code{\link{member_components}}, +\code{\link{member_core}}, +\code{\link{member_diffusion}} + +Other nodal: \code{\link{mark_core}}, +\code{\link{mark_degree}}, +\code{\link{mark_diff}}, +\code{\link{mark_nodes}}, +\code{\link{mark_select_node}}, +\code{\link{measure_assort_node}}, +\code{\link{measure_broker_node}}, +\code{\link{measure_brokerage}}, +\code{\link{measure_central_between}}, +\code{\link{measure_central_close}}, +\code{\link{measure_central_degree}}, +\code{\link{measure_central_eigen}}, +\code{\link{measure_closure_node}}, +\code{\link{measure_core}}, +\code{\link{measure_diffusion_node}}, +\code{\link{measure_diverse_node}}, \code{\link{member_brokerage}}, \code{\link{member_cliques}}, +\code{\link{member_community}}, \code{\link{member_community_hier}}, \code{\link{member_community_non}}, -\code{\link{member_components}} +\code{\link{member_components}}, +\code{\link{member_core}}, +\code{\link{member_diffusion}}, +\code{\link{motif_brokerage_node}}, +\code{\link{motif_exposure}}, +\code{\link{motif_node}}, +\code{\link{motif_path}} } \concept{memberships} +\concept{nodal} diff --git a/man/model_cluster.Rd b/man/method_cluster.Rd similarity index 62% rename from man/model_cluster.Rd rename to man/method_cluster.Rd index b0d641c..353e9d3 100644 --- a/man/model_cluster.Rd +++ b/man/method_cluster.Rd @@ -1,20 +1,20 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/model_cluster.R -\name{model_cluster} -\alias{model_cluster} +% Please edit documentation in R/method_cluster.R +\name{method_cluster} +\alias{method_cluster} \alias{cluster_hierarchical} \alias{cluster_cosine} \alias{cluster_concor} \title{Methods for equivalence clustering} \usage{ -cluster_hierarchical(census, distance) +cluster_hierarchical(motif, distance) -cluster_cosine(census, distance) +cluster_cosine(motif, distance) -cluster_concor(.data, census) +cluster_concor(.data, motif) } \arguments{ -\item{census}{A matrix returned by a \verb{node_by_*()} function.} +\item{motif}{A matrix returned by a \verb{node_x_*()} function.} \item{distance}{Character string indicating which distance metric to pass on to \code{stats::dist}. @@ -26,8 +26,13 @@ Fewer, identifiable letters, e.g. \code{"e"} for Euclidean, is sufficient.} For more information on the standard coercion possible, see \code{\link[manynet:manip_as]{manynet::as_tidygraph()}}.} } +\value{ +A hierarchical clustering object created by \code{stats::hclust()}, +with an additional \code{distances} attribute containing the distance matrix +used for clustering. +} \description{ -These functions are used to cluster some census object: +These functions are used to cluster some motif census object: \itemize{ \item \code{cluster_hierarchical()} returns a hierarchical clustering object created by \code{stats::hclust()}. @@ -42,10 +47,31 @@ These functions are not intended to be called directly, but are called within \code{node_in_equivalence()} and related functions. They are exported and listed here to provide more detailed documentation. } +\section{Hierarchical clustering}{ + +This method uses \code{stats::hclust()} to create a hierarchical clustering object +from a distance matrix created from the correlations between nodes' profiles +in the given motif census. +First a matrix of Pearson correlation coefficients between each pair of +nodes' profiles in the given motif census is created. +Then a distance matrix is created by subtracting these correlations from \code{1}, +and this is given to \code{stats::hclust()} to enable dendrogram construction etc. +} + +\section{Cosine similarity}{ + +This method is similar to the hierarchical clustering method, +but uses cosine similarity rather than correlation as the clustering basis. +First a matrix of cosine similarities between each pair of nodes' profiles +in the given census is created. +Then a distance matrix is created by subtracting these similarities from \code{1}, +and this is given to \code{stats::hclust} to enable dendrogram construction etc. +} + \section{CONCOR}{ -First a matrix of Pearson correlation coefficients between each pair of nodes -profiles in the given census is created. +First a matrix of Pearson correlation coefficients between each pair of +nodes' profiles in the given motif census is created. Then, again, we find the correlations of this square, symmetric matrix, and continue to do this iteratively until each entry is either \code{1} or \code{-1}. These values are used to split the data into two partitions, diff --git a/man/method_kselect.Rd b/man/method_kselect.Rd index 81d09de..662163d 100644 --- a/man/method_kselect.Rd +++ b/man/method_kselect.Rd @@ -14,15 +14,22 @@ k_elbow(hc, .data, motif, Kmax) k_silhouette(hc, .data, Kmax) -k_gap(hc, motif, Kmax, B = 100) +k_gap(hc, motif, Kmax, sims = 100) } \arguments{ \item{hc}{A hierarchical clustering object.} +\item{.data}{A network object of class \code{mnet}, \code{igraph}, \code{tbl_graph}, \code{network}, or similar. +For more information on the standard coercion possible, +see \code{\link[manynet:manip_as]{manynet::as_tidygraph()}}.} + \item{motif}{A motif census object.} \item{Kmax}{An integer indicating the maximum number of options to consider. The minimum of this and the number of nodes in the network is used.} + +\item{sims}{Integer of how many simulations should be generated as a +reference distribution.} } \value{ A single integer indicating the number of clusters to return. diff --git a/man/motif_net.Rd b/man/motif_net.Rd index ea267f0..0e3317e 100644 --- a/man/motif_net.Rd +++ b/man/motif_net.Rd @@ -6,7 +6,7 @@ \alias{net_x_triad} \alias{net_x_tetrad} \alias{net_x_mixed} -\title{Motifs at the network level} +\title{Motifs of network cohesion} \source{ Alejandro Espinosa 'netmem' } @@ -26,14 +26,18 @@ see \code{\link[manynet:manip_as]{manynet::as_tidygraph()}}.} \item{object2}{A second, two-mode network object.} } +\value{ +A \code{network_motif} tibble with one row and a column for each motif type, +giving the count of each motif in the network. +} \description{ These functions include ways to take a census of the graphlets in a network: \itemize{ -\item \code{net_by_dyad()} returns a census of dyad motifs in a network. -\item \code{net_by_triad()} returns a census of triad motifs in a network. -\item \code{net_by_tetrad()} returns a census of tetrad motifs in a network. -\item \code{net_by_mixed()} returns a census of triad motifs that span +\item \code{net_x_dyad()} returns a census of dyad motifs in a network. +\item \code{net_x_triad()} returns a census of triad motifs in a network. +\item \code{net_x_tetrad()} returns a census of tetrad motifs in a network. +\item \code{net_x_mixed()} returns a census of triad motifs that span a one-mode and a two-mode network. } @@ -166,10 +170,22 @@ Hollway, James, Alessandro Lomi, Francesca Pallotti, and Christoph Stadtfeld. 20 } } \seealso{ +Other cohesion: +\code{\link{mark_triangles}}, +\code{\link{measure_breadth}}, +\code{\link{measure_cohesion}}, +\code{\link{measure_fragmentation}}, +\code{\link{motif_node}} + Other motifs: -\code{\link{motif_brokerage}}, -\code{\link{motif_diffusion}}, +\code{\link{motif_brokerage_net}}, +\code{\link{motif_brokerage_node}}, +\code{\link{motif_exposure}}, +\code{\link{motif_hazard}}, \code{\link{motif_hierarchy}}, -\code{\link{motif_node}} +\code{\link{motif_node}}, +\code{\link{motif_path}}, +\code{\link{motif_periods}} } +\concept{cohesion} \concept{motifs} diff --git a/man/motif_node.Rd b/man/motif_node.Rd index 353f4c7..9633109 100644 --- a/man/motif_node.Rd +++ b/man/motif_node.Rd @@ -2,40 +2,41 @@ % Please edit documentation in R/motif_census.R \name{motif_node} \alias{motif_node} -\alias{node_x_tie} \alias{node_x_dyad} \alias{node_x_triad} \alias{node_x_tetrad} -\alias{node_x_path} -\title{Motifs at the nodal level} +\title{Motifs of nodes cohesion} \usage{ -node_x_tie(.data) - node_x_dyad(.data) node_x_triad(.data) node_x_tetrad(.data) - -node_x_path(.data) } \arguments{ \item{.data}{A network object of class \code{mnet}, \code{igraph}, \code{tbl_graph}, \code{network}, or similar. For more information on the standard coercion possible, see \code{\link[manynet:manip_as]{manynet::as_tidygraph()}}.} } +\value{ +A \code{node_motif} tibble with one row for each node in the network and +a column for each motif type, +giving the count of each motif in which each node participates. +If the network is labelled, +then the node names will be in a column named \code{names}. +} \description{ These functions include ways to take a census of the positions of nodes in a network: \itemize{ -\item \code{node_by_tie()} returns a census of the ties in a network. +\item \code{node_x_tie()} returns a census of the ties in a network. For directed networks, out-ties and in-ties are bound together. For multiplex networks, the various types of ties are bound together. -\item \code{node_by_triad()} returns a census of the triad configurations +\item \code{node_x_triad()} returns a census of the triad configurations nodes are embedded in. -\item \code{node_by_tetrad()} returns a census of nodes' positions +\item \code{node_x_tetrad()} returns a census of nodes' positions in motifs of four nodes. -\item \code{node_by_path()} returns the shortest path lengths +\item \code{node_x_path()} returns the shortest path lengths of each node to every other node in the network. } } @@ -68,13 +69,10 @@ Graphs of these motifs can be shown using } \examples{ -task_eg <- to_named(to_uniplex(ison_algebra, "tasks")) -(tie_cen <- node_x_tie(task_eg)) node_x_dyad(ison_networkers) +task_eg <- to_named(to_uniplex(ison_algebra, "tasks")) (triad_cen <- node_x_triad(task_eg)) node_x_tetrad(ison_southern_women) -node_x_path(ison_adolescents) -node_x_path(ison_southern_women) } \references{ \subsection{On the dyad census}{ @@ -103,25 +101,55 @@ McMillan, Cassie, and Diane Felmlee. 2020. \emph{Social Psychology Quarterly} 83(4): 383-404. \doi{10.1177/0190272520944151} } - -\subsection{On paths}{ - -Dijkstra, Edsger W. 1959. -"A note on two problems in connexion with graphs". -\emph{Numerische Mathematik} 1, 269-71. -\doi{10.1007/BF01386390}. - -Opsahl, Tore, Filip Agneessens, and John Skvoretz. 2010. -"Node centrality in weighted networks: Generalizing degree and shortest paths". -\emph{Social Networks} 32(3): 245-51. -\doi{10.1016/j.socnet.2010.03.006}. -} } \seealso{ +Other cohesion: +\code{\link{mark_triangles}}, +\code{\link{measure_breadth}}, +\code{\link{measure_cohesion}}, +\code{\link{measure_fragmentation}}, +\code{\link{motif_net}} + Other motifs: -\code{\link{motif_brokerage}}, -\code{\link{motif_diffusion}}, +\code{\link{motif_brokerage_net}}, +\code{\link{motif_brokerage_node}}, +\code{\link{motif_exposure}}, +\code{\link{motif_hazard}}, \code{\link{motif_hierarchy}}, -\code{\link{motif_net}} +\code{\link{motif_net}}, +\code{\link{motif_path}}, +\code{\link{motif_periods}} + +Other nodal: +\code{\link{mark_core}}, +\code{\link{mark_degree}}, +\code{\link{mark_diff}}, +\code{\link{mark_nodes}}, +\code{\link{mark_select_node}}, +\code{\link{measure_assort_node}}, +\code{\link{measure_broker_node}}, +\code{\link{measure_brokerage}}, +\code{\link{measure_central_between}}, +\code{\link{measure_central_close}}, +\code{\link{measure_central_degree}}, +\code{\link{measure_central_eigen}}, +\code{\link{measure_closure_node}}, +\code{\link{measure_core}}, +\code{\link{measure_diffusion_node}}, +\code{\link{measure_diverse_node}}, +\code{\link{member_brokerage}}, +\code{\link{member_cliques}}, +\code{\link{member_community}}, +\code{\link{member_community_hier}}, +\code{\link{member_community_non}}, +\code{\link{member_components}}, +\code{\link{member_core}}, +\code{\link{member_diffusion}}, +\code{\link{member_equivalence}}, +\code{\link{motif_brokerage_node}}, +\code{\link{motif_exposure}}, +\code{\link{motif_path}} } +\concept{cohesion} \concept{motifs} +\concept{nodal} diff --git a/man/motif_path.Rd b/man/motif_path.Rd new file mode 100644 index 0000000..3a1ee1b --- /dev/null +++ b/man/motif_path.Rd @@ -0,0 +1,98 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/motif_census.R +\name{motif_path} +\alias{motif_path} +\alias{node_x_tie} +\alias{node_x_path} +\title{Motifs of nodes pathing} +\usage{ +node_x_tie(.data) + +node_x_path(.data) +} +\arguments{ +\item{.data}{A network object of class \code{mnet}, \code{igraph}, \code{tbl_graph}, \code{network}, or similar. +For more information on the standard coercion possible, +see \code{\link[manynet:manip_as]{manynet::as_tidygraph()}}.} +} +\value{ +A \code{node_motif} tibble with one row for each node in the network and +a column for each motif type, +giving the count of each motif in which each node participates. +If the network is labelled, +then the node names will be in a column named \code{names}. +} +\description{ +These functions include ways to take a census of the positions of nodes +in a network: +\itemize{ +\item \code{node_x_tie()} returns a census of the ties in a network. +For directed networks, out-ties and in-ties are bound together. +For multiplex networks, the various types of ties are bound together. +\item \code{node_x_path()} returns the shortest path lengths +of each node to every other node in the network. +} +} +\examples{ +task_eg <- to_named(to_uniplex(ison_algebra, "tasks")) +(tie_cen <- node_x_tie(task_eg)) +node_x_path(ison_adolescents) +node_x_path(ison_southern_women) +} +\references{ +\subsection{On paths}{ + +Dijkstra, Edsger W. 1959. +"A note on two problems in connexion with graphs". +\emph{Numerische Mathematik} 1, 269-71. +\doi{10.1007/BF01386390}. + +Opsahl, Tore, Filip Agneessens, and John Skvoretz. 2010. +"Node centrality in weighted networks: Generalizing degree and shortest paths". +\emph{Social Networks} 32(3): 245-51. +\doi{10.1016/j.socnet.2010.03.006}. +} +} +\seealso{ +Other motifs: +\code{\link{motif_brokerage_net}}, +\code{\link{motif_brokerage_node}}, +\code{\link{motif_exposure}}, +\code{\link{motif_hazard}}, +\code{\link{motif_hierarchy}}, +\code{\link{motif_net}}, +\code{\link{motif_node}}, +\code{\link{motif_periods}} + +Other nodal: +\code{\link{mark_core}}, +\code{\link{mark_degree}}, +\code{\link{mark_diff}}, +\code{\link{mark_nodes}}, +\code{\link{mark_select_node}}, +\code{\link{measure_assort_node}}, +\code{\link{measure_broker_node}}, +\code{\link{measure_brokerage}}, +\code{\link{measure_central_between}}, +\code{\link{measure_central_close}}, +\code{\link{measure_central_degree}}, +\code{\link{measure_central_eigen}}, +\code{\link{measure_closure_node}}, +\code{\link{measure_core}}, +\code{\link{measure_diffusion_node}}, +\code{\link{measure_diverse_node}}, +\code{\link{member_brokerage}}, +\code{\link{member_cliques}}, +\code{\link{member_community}}, +\code{\link{member_community_hier}}, +\code{\link{member_community_non}}, +\code{\link{member_components}}, +\code{\link{member_core}}, +\code{\link{member_diffusion}}, +\code{\link{member_equivalence}}, +\code{\link{motif_brokerage_node}}, +\code{\link{motif_exposure}}, +\code{\link{motif_node}} +} +\concept{motifs} +\concept{nodal} From a31f39997917efa0cd981b8f0e22fc27ba490a9a Mon Sep 17 00:00:00 2001 From: James Hollway Date: Sat, 21 Mar 2026 18:13:46 +0100 Subject: [PATCH 14/35] Rationalising select nodes and ties --- R/mark_nodes.R | 35 +++++------ R/mark_ties.R | 13 ++-- man/{mark_select.Rd => mark_select_node.Rd} | 52 ++++++++++++--- man/mark_select_tie.Rd | 70 +++++++++++++++++++++ 4 files changed, 138 insertions(+), 32 deletions(-) rename man/{mark_select.Rd => mark_select_node.Rd} (54%) create mode 100644 man/mark_select_tie.Rd diff --git a/R/mark_nodes.R b/R/mark_nodes.R index d944bc3..9abb04a 100644 --- a/R/mark_nodes.R +++ b/R/mark_nodes.R @@ -1,6 +1,7 @@ # Structural properties #### #' Marking nodes based on structural properties +#' @name mark_nodes #' @description #' These functions return logical vectors the length of the #' nodes in a network identifying which hold certain properties or positions in the network. @@ -13,8 +14,8 @@ #' triangles that are only connected by that node. #' - `node_is_mentor()` marks a proportion of high indegree nodes as 'mentors' (see details). #' - `node_is_neighbor()` marks nodes that are neighbours of a given node. +#' @template param_data #' @template node_mark -#' @name mark_nodes NULL #' @rdname mark_nodes @@ -149,8 +150,8 @@ node_is_neighbor <- function(.data, node){ # Degree properties #### #' Marking nodes based on degree properties -#' -#' @description +#' @name mark_degree +#' @description #' These functions return logical vectors the length of the #' nodes in a network identifying which hold certain properties or positions in the network. #' @@ -160,11 +161,9 @@ node_is_neighbor <- function(.data, node){ #' with exactly one incoming or outgoing tie. #' - `node_is_universal()` identifies whether nodes are adjacent to all other #' nodes in the network. -#' @param .data A network object of class `mnet`, `igraph`, `tbl_graph`, `network`, or similar. -#' For more information on what coercions are possible, see [manynet::as_tidygraph()]. -#' @template node_mark +#' @template param_data #' @family degree -#' @name mark_degree +#' @template node_mark NULL #' @rdname mark_degree @@ -401,6 +400,7 @@ node_is_exposed <- function(.data, mark, time = 0){ # Selection properties #### #' Marking nodes based on measures +#' @name mark_select_node #' @description #' These functions return logical vectors the length of the #' nodes in a network identifying which hold certain properties or positions in the network. @@ -410,26 +410,25 @@ node_is_exposed <- function(.data, mark, time = 0){ #' for converting the results from some node measure into a mark-class object. #' They can be particularly useful for highlighting which node or nodes #' are key because they minimise or, more often, maximise some measure. -#' @inheritParams mark_nodes -#' @template node_mark +#' @template param_data #' @family selection -#' @name mark_select +#' @template node_mark NULL -#' @rdname mark_select -#' @param size The number of nodes to select (as TRUE). +#' @rdname mark_select_node +#' @template param_select #' @examples #' node_is_random(ison_brandes, 2) #' @export -node_is_random <- function(.data, size = 1){ +node_is_random <- function(.data, select = 1){ .data <- manynet::expect_nodes(.data) n <- manynet::net_nodes(.data) out <- rep(FALSE, n) - out[sample.int(n, size)] <- TRUE + out[sample.int(n, select)] <- TRUE make_node_mark(out, .data) } -#' @rdname mark_select +#' @rdname mark_select_node #' @param node_measure An object created by a `node_` measure. #' @param ranks The number of ranks of max or min to return. #' For example, `ranks = 3` will return TRUE for nodes with @@ -461,7 +460,7 @@ node_is_max <- function(node_measure, ranks = 1){ out } -#' @rdname mark_select +#' @rdname mark_select_node #' @examples #' node_is_min(node_by_degree(ison_brandes)) #' @export @@ -487,9 +486,9 @@ node_is_min <- function(node_measure, ranks = 1){ out } -#' @rdname mark_select +#' @rdname mark_select_node #' @examples -#' node_is_mean(node_degree(ison_brandes)) +#' node_is_mean(node_by_degree(ison_brandes)) #' @export node_is_mean <- function(node_measure, ranks = 1){ if(!inherits(node_measure, "node_measure")) diff --git a/R/mark_ties.R b/R/mark_ties.R index 61da8a9..55e1f87 100644 --- a/R/mark_ties.R +++ b/R/mark_ties.R @@ -324,6 +324,7 @@ tie_is_imbalanced <- function(.data){ # Selection properties #### #' Marking ties based on measures +#' @name mark_select_tie #' @description #' These functions return logical vectors the length of the ties in a network: #' @@ -335,20 +336,20 @@ tie_is_imbalanced <- function(.data){ #' @template param_data #' @template tie_mark #' @family selection -#' @name mark_tie_select NULL -#' @rdname mark_tie_select +#' @rdname mark_select_tie +#' @template param_select #' @export -tie_is_random <- function(.data, size = 1){ +tie_is_random <- function(.data, select = 1){ .data <- manynet::expect_ties(.data) n <- manynet::net_ties(.data) out <- rep(FALSE, n) - out[sample.int(n, size)] <- TRUE + out[sample.int(n, select)] <- TRUE make_tie_mark(out, .data) } -#' @rdname mark_tie_select +#' @rdname mark_select_tie #' @param tie_measure An object created by a `tie_` measure. #' @examples #' tie_is_max(tie_by_betweenness(ison_brandes)) @@ -359,7 +360,7 @@ tie_is_max <- function(tie_measure){ out } -#' @rdname mark_tie_select +#' @rdname mark_select_tie #' @examples #' tie_is_min(tie_by_betweenness(ison_brandes)) #' @export diff --git a/man/mark_select.Rd b/man/mark_select_node.Rd similarity index 54% rename from man/mark_select.Rd rename to man/mark_select_node.Rd index 8261de8..64eca47 100644 --- a/man/mark_select.Rd +++ b/man/mark_select_node.Rd @@ -1,14 +1,14 @@ % Generated by roxygen2: do not edit by hand % Please edit documentation in R/mark_nodes.R -\name{mark_select} -\alias{mark_select} +\name{mark_select_node} +\alias{mark_select_node} \alias{node_is_random} \alias{node_is_max} \alias{node_is_min} \alias{node_is_mean} \title{Marking nodes based on measures} \usage{ -node_is_random(.data, size = 1) +node_is_random(.data, select = 1) node_is_max(node_measure, ranks = 1) @@ -17,7 +17,11 @@ node_is_min(node_measure, ranks = 1) node_is_mean(node_measure, ranks = 1) } \arguments{ -\item{size}{The number of nodes to select (as TRUE).} +\item{.data}{A network object of class \code{mnet}, \code{igraph}, \code{tbl_graph}, \code{network}, or similar. +For more information on the standard coercion possible, +see \code{\link[manynet:manip_as]{manynet::as_tidygraph()}}.} + +\item{select}{Number of elements to select (as TRUE).} \item{node_measure}{An object created by a \code{node_} measure.} @@ -47,20 +51,52 @@ are key because they minimise or, more often, maximise some measure. node_is_random(ison_brandes, 2) node_is_max(node_by_degree(ison_brandes)) node_is_min(node_by_degree(ison_brandes)) -node_is_mean(node_degree(ison_brandes)) +node_is_mean(node_by_degree(ison_brandes)) } \seealso{ +Other selection: +\code{\link{mark_select_tie}} + Other marks: +\code{\link{mark_core}}, \code{\link{mark_degree}}, \code{\link{mark_diff}}, \code{\link{mark_dyads}}, \code{\link{mark_nodes}}, -\code{\link{mark_tie_select}}, +\code{\link{mark_select_tie}}, \code{\link{mark_ties}}, \code{\link{mark_triangles}} -Other selection: -\code{\link{mark_tie_select}} +Other nodal: +\code{\link{mark_core}}, +\code{\link{mark_degree}}, +\code{\link{mark_diff}}, +\code{\link{mark_nodes}}, +\code{\link{measure_assort_node}}, +\code{\link{measure_broker_node}}, +\code{\link{measure_brokerage}}, +\code{\link{measure_central_between}}, +\code{\link{measure_central_close}}, +\code{\link{measure_central_degree}}, +\code{\link{measure_central_eigen}}, +\code{\link{measure_closure_node}}, +\code{\link{measure_core}}, +\code{\link{measure_diffusion_node}}, +\code{\link{measure_diverse_node}}, +\code{\link{member_brokerage}}, +\code{\link{member_cliques}}, +\code{\link{member_community}}, +\code{\link{member_community_hier}}, +\code{\link{member_community_non}}, +\code{\link{member_components}}, +\code{\link{member_core}}, +\code{\link{member_diffusion}}, +\code{\link{member_equivalence}}, +\code{\link{motif_brokerage_node}}, +\code{\link{motif_exposure}}, +\code{\link{motif_node}}, +\code{\link{motif_path}} } \concept{marks} +\concept{nodal} \concept{selection} diff --git a/man/mark_select_tie.Rd b/man/mark_select_tie.Rd new file mode 100644 index 0000000..c45ef98 --- /dev/null +++ b/man/mark_select_tie.Rd @@ -0,0 +1,70 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/mark_ties.R +\name{mark_select_tie} +\alias{mark_select_tie} +\alias{tie_is_random} +\alias{tie_is_max} +\alias{tie_is_min} +\title{Marking ties based on measures} +\usage{ +tie_is_random(.data, select = 1) + +tie_is_max(tie_measure) + +tie_is_min(tie_measure) +} +\arguments{ +\item{.data}{A network object of class \code{mnet}, \code{igraph}, \code{tbl_graph}, \code{network}, or similar. +For more information on the standard coercion possible, +see \code{\link[manynet:manip_as]{manynet::as_tidygraph()}}.} + +\item{select}{Number of elements to select (as TRUE).} + +\item{tie_measure}{An object created by a \code{tie_} measure.} +} +\value{ +A \code{tie_mark} logical vector the length of the ties in the network, +giving either TRUE or FALSE for each tie depending on +whether the condition is matched. +} +\description{ +These functions return logical vectors the length of the ties in a network: +\itemize{ +\item \code{tie_is_random()} marks one or more ties at random. +\item \code{tie_is_max()} and \code{tie_is_min()} are more useful +for converting the results from some tie measure into a mark-class object. +They can be particularly useful for highlighting which tie or ties +are key because they minimise or, more often, maximise some measure. +} +} +\examples{ +tie_is_max(tie_by_betweenness(ison_brandes)) +tie_is_min(tie_by_betweenness(ison_brandes)) +} +\seealso{ +Other marks: +\code{\link{mark_core}}, +\code{\link{mark_degree}}, +\code{\link{mark_diff}}, +\code{\link{mark_dyads}}, +\code{\link{mark_nodes}}, +\code{\link{mark_select_node}}, +\code{\link{mark_ties}}, +\code{\link{mark_triangles}} + +Other tie: +\code{\link{mark_dyads}}, +\code{\link{mark_ties}}, +\code{\link{mark_triangles}}, +\code{\link{measure_broker_tie}}, +\code{\link{measure_centralities_between}}, +\code{\link{measure_centralities_close}}, +\code{\link{measure_centralities_degree}}, +\code{\link{measure_centralities_eigen}} + +Other selection: +\code{\link{mark_select_node}} +} +\concept{marks} +\concept{selection} +\concept{tie} From fe4e8b1a99d07c05ee25bdbd89ba81686ec299b5 Mon Sep 17 00:00:00 2001 From: James Hollway Date: Sat, 21 Mar 2026 18:15:10 +0100 Subject: [PATCH 15/35] Fixed some documentation --- R/netrics-defunct.R | 2 + man/defunct.Rd | 4 ++ man/mark_nodes.Rd | 40 ++++++++++++- man/mark_tie_select.Rd | 56 ----------------- man/mark_ties.Rd | 16 ++++- man/measure_holes.Rd | 133 ----------------------------------------- 6 files changed, 58 insertions(+), 193 deletions(-) delete mode 100644 man/mark_tie_select.Rd delete mode 100644 man/measure_holes.Rd diff --git a/R/netrics-defunct.R b/R/netrics-defunct.R index 16086e5..aae724b 100644 --- a/R/netrics-defunct.R +++ b/R/netrics-defunct.R @@ -10,6 +10,8 @@ #' wherever possible and update your scripts accordingly. #' @name defunct #' @keywords internal +#' @returns Results as expected, +#' along with a warning to use new function naming in the future. NULL # nocov end \ No newline at end of file diff --git a/man/defunct.Rd b/man/defunct.Rd index 7f746c1..72502da 100644 --- a/man/defunct.Rd +++ b/man/defunct.Rd @@ -3,6 +3,10 @@ \name{defunct} \alias{defunct} \title{Functions that have been renamed, superseded, or are no longer working} +\value{ +Results as expected, +along with a warning to use new function naming in the future. +} \description{ \ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#deprecated}{\figure{lifecycle-deprecated.svg}{options: alt='[Deprecated]'}}}{\strong{[Deprecated]}} Generally these functions have been superseded or renamed. diff --git a/man/mark_nodes.Rd b/man/mark_nodes.Rd index 194b49e..7fd164c 100644 --- a/man/mark_nodes.Rd +++ b/man/mark_nodes.Rd @@ -20,6 +20,10 @@ node_is_mentor(.data, elites = 0.1) node_is_neighbor(.data, node) } \arguments{ +\item{.data}{A network object of class \code{mnet}, \code{igraph}, \code{tbl_graph}, \code{network}, or similar. +For more information on the standard coercion possible, +see \code{\link[manynet:manip_as]{manynet::as_tidygraph()}}.} + \item{elites}{The proportion of nodes to be selected as mentors. By default this is set at 0.1. This means that the top 10\% of nodes in terms of degree, @@ -94,12 +98,44 @@ Valente, Thomas, and Rebecca Davis. 1999. } \seealso{ Other marks: +\code{\link{mark_core}}, \code{\link{mark_degree}}, \code{\link{mark_diff}}, \code{\link{mark_dyads}}, -\code{\link{mark_select}}, -\code{\link{mark_tie_select}}, +\code{\link{mark_select_node}}, +\code{\link{mark_select_tie}}, \code{\link{mark_ties}}, \code{\link{mark_triangles}} + +Other nodal: +\code{\link{mark_core}}, +\code{\link{mark_degree}}, +\code{\link{mark_diff}}, +\code{\link{mark_select_node}}, +\code{\link{measure_assort_node}}, +\code{\link{measure_broker_node}}, +\code{\link{measure_brokerage}}, +\code{\link{measure_central_between}}, +\code{\link{measure_central_close}}, +\code{\link{measure_central_degree}}, +\code{\link{measure_central_eigen}}, +\code{\link{measure_closure_node}}, +\code{\link{measure_core}}, +\code{\link{measure_diffusion_node}}, +\code{\link{measure_diverse_node}}, +\code{\link{member_brokerage}}, +\code{\link{member_cliques}}, +\code{\link{member_community}}, +\code{\link{member_community_hier}}, +\code{\link{member_community_non}}, +\code{\link{member_components}}, +\code{\link{member_core}}, +\code{\link{member_diffusion}}, +\code{\link{member_equivalence}}, +\code{\link{motif_brokerage_node}}, +\code{\link{motif_exposure}}, +\code{\link{motif_node}}, +\code{\link{motif_path}} } \concept{marks} +\concept{nodal} diff --git a/man/mark_tie_select.Rd b/man/mark_tie_select.Rd deleted file mode 100644 index d9ce0d1..0000000 --- a/man/mark_tie_select.Rd +++ /dev/null @@ -1,56 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/mark_ties.R -\name{mark_tie_select} -\alias{mark_tie_select} -\alias{tie_is_random} -\alias{tie_is_max} -\alias{tie_is_min} -\title{Marking ties based on measures} -\usage{ -tie_is_random(.data, size = 1) - -tie_is_max(tie_measure) - -tie_is_min(tie_measure) -} -\arguments{ -\item{.data}{A network object of class \code{mnet}, \code{igraph}, \code{tbl_graph}, \code{network}, or similar. -For more information on the standard coercion possible, -see \code{\link[manynet:manip_as]{manynet::as_tidygraph()}}.} - -\item{tie_measure}{An object created by a \code{tie_} measure.} -} -\value{ -A \code{tie_mark} logical vector the length of the ties in the network, -giving either TRUE or FALSE for each tie depending on -whether the condition is matched. -} -\description{ -These functions return logical vectors the length of the ties in a network: -\itemize{ -\item \code{tie_is_random()} marks one or more ties at random. -\item \code{tie_is_max()} and \code{tie_is_min()} are more useful -for converting the results from some tie measure into a mark-class object. -They can be particularly useful for highlighting which tie or ties -are key because they minimise or, more often, maximise some measure. -} -} -\examples{ -tie_is_max(tie_by_betweenness(ison_brandes)) -tie_is_min(tie_by_betweenness(ison_brandes)) -} -\seealso{ -Other marks: -\code{\link{mark_degree}}, -\code{\link{mark_diff}}, -\code{\link{mark_dyads}}, -\code{\link{mark_nodes}}, -\code{\link{mark_select}}, -\code{\link{mark_ties}}, -\code{\link{mark_triangles}} - -Other selection: -\code{\link{mark_select}} -} -\concept{marks} -\concept{selection} diff --git a/man/mark_ties.Rd b/man/mark_ties.Rd index e11c055..13c3f06 100644 --- a/man/mark_ties.Rd +++ b/man/mark_ties.Rd @@ -55,12 +55,24 @@ ison_adolescents \%>\% } \seealso{ Other marks: +\code{\link{mark_core}}, \code{\link{mark_degree}}, \code{\link{mark_diff}}, \code{\link{mark_dyads}}, \code{\link{mark_nodes}}, -\code{\link{mark_select}}, -\code{\link{mark_tie_select}}, +\code{\link{mark_select_node}}, +\code{\link{mark_select_tie}}, \code{\link{mark_triangles}} + +Other tie: +\code{\link{mark_dyads}}, +\code{\link{mark_select_tie}}, +\code{\link{mark_triangles}}, +\code{\link{measure_broker_tie}}, +\code{\link{measure_centralities_between}}, +\code{\link{measure_centralities_close}}, +\code{\link{measure_centralities_degree}}, +\code{\link{measure_centralities_eigen}} } \concept{marks} +\concept{tie} diff --git a/man/measure_holes.Rd b/man/measure_holes.Rd deleted file mode 100644 index 4c1230d..0000000 --- a/man/measure_holes.Rd +++ /dev/null @@ -1,133 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/measure_holes.R -\name{measure_holes} -\alias{measure_holes} -\alias{node_by_bridges} -\alias{node_by_redundancy} -\alias{node_by_effsize} -\alias{node_by_efficiency} -\alias{node_by_constraint} -\alias{node_by_hierarchy} -\alias{node_by_neighbours_degree} -\alias{tie_by_cohesion} -\title{Measures of structural holes} -\usage{ -node_by_bridges(.data) - -node_by_redundancy(.data) - -node_by_effsize(.data) - -node_by_efficiency(.data) - -node_by_constraint(.data) - -node_by_hierarchy(.data) - -node_by_neighbours_degree(.data) - -tie_by_cohesion(.data) -} -\arguments{ -\item{.data}{A network object of class \code{mnet}, \code{igraph}, \code{tbl_graph}, \code{network}, or similar. -For more information on the standard coercion possible, -see \code{\link[manynet:manip_as]{manynet::as_tidygraph()}}.} -} -\description{ -These function provide different measures of the degree to which nodes -fill structural holes, as outlined in Burt (1992): -\itemize{ -\item \code{node_bridges()} measures the sum of bridges to which each node -is adjacent. -\item \code{node_redundancy()} measures the redundancy of each nodes' contacts. -\item \code{node_effsize()} measures nodes' effective size. -\item \code{node_efficiency()} measures nodes' efficiency. -\item \code{node_constraint()} measures nodes' constraint scores for one-mode networks -according to Burt (1992) and for two-mode networks according to Hollway et al (2020). -\item \code{node_hierarchy()} measures nodes' exposure to hierarchy, -where only one or two contacts are the source of closure. -\item \code{node_neighbours_degree()} measures nodes' average nearest neighbors degree, -or \eqn{knn}, a measure of the type of local environment a node finds itself in -\item \code{tie_cohesion()} measures the ratio between common neighbors to ties' -adjacent nodes and the total number of adjacent nodes, -where high values indicate ties' embeddedness in dense local environments -} - -Burt's theory holds that while those nodes embedded in dense clusters -of close connections are likely exposed to the same or similar ideas and information, -those who fill structural holes between two otherwise disconnected groups -can gain some comparative advantage from that position. -} -\details{ -A number of different ways of measuring these structural holes are available. -Note that we use Borgatti's reformulation for unweighted networks in -\code{node_redundancy()} and \code{node_effsize()}. -Redundancy is thus \eqn{\frac{2t}{n}}, -where \eqn{t} is the sum of ties and \eqn{n} the sum of nodes in each node's neighbourhood, -and effective size is calculated as \eqn{n - \frac{2t}{n}}. -Node efficiency is the node's effective size divided by its degree. -} -\examples{ -node_by_bridges(ison_adolescents) -node_by_bridges(ison_southern_women) -node_by_redundancy(ison_adolescents) -node_by_redundancy(ison_southern_women) -node_by_effsize(ison_adolescents) -node_by_effsize(ison_southern_women) -node_by_efficiency(ison_adolescents) -node_by_efficiency(ison_southern_women) -node_by_constraint(ison_southern_women) -node_by_hierarchy(ison_adolescents) -node_by_hierarchy(ison_southern_women) -} -\references{ -\subsection{On structural holes}{ - -Burt, Ronald S. 1992. -\emph{Structural Holes: The Social Structure of Competition}. -Cambridge, MA: Harvard University Press. -} - -Borgatti, Steven. 1997. -“\href{http://www.analytictech.com/connections/v20(1)/holes.htm}{Structural Holes: Unpacking Burt’s Redundancy Measures}” -\emph{Connections} 20(1):35-38. - -Burchard, Jake, and Benjamin Cornwell. 2018. -“Structural Holes and Bridging in Two-Mode Networks.” -\emph{Social Networks} 55:11–20. -\doi{10.1016/j.socnet.2018.04.001} - -Hollway, James, Jean-Frédéric Morin, and Joost Pauwelyn. 2020. -"Structural conditions for novelty: The introduction of new environmental clauses to the trade regime complex." -\emph{International Environmental Agreements: Politics, Law and Economics} 20 (1): 61–83. -\doi{10.1007/s10784-019-09464-5} - -\subsection{On neighbours average degree}{ - -Barrat, Alain, Marc Barthelemy, Romualdo Pastor-Satorras, and Alessandro Vespignani. 2004. -"The architecture of complex weighted networks", -\emph{Proc. Natl. Acad. Sci.} 101: 3747. -} -} -\seealso{ -Other measures: -\code{\link{measure_assortativity}}, -\code{\link{measure_breadth}}, -\code{\link{measure_brokerage}}, -\code{\link{measure_central_between}}, -\code{\link{measure_central_close}}, -\code{\link{measure_central_degree}}, -\code{\link{measure_central_eigen}}, -\code{\link{measure_closure}}, -\code{\link{measure_cohesion}}, -\code{\link{measure_diffusion_infection}}, -\code{\link{measure_diffusion_net}}, -\code{\link{measure_diffusion_node}}, -\code{\link{measure_features}}, -\code{\link{measure_fragmentation}}, -\code{\link{measure_heterogeneity}}, -\code{\link{measure_hierarchy}}, -\code{\link{measure_periods}}, -\code{\link{member_diffusion}} -} -\concept{measures} From 39ff13d10832f305aa35a2fd63a80f3517eb7655 Mon Sep 17 00:00:00 2001 From: James Hollway Date: Sat, 21 Mar 2026 18:16:51 +0100 Subject: [PATCH 16/35] Periodwise functions are now motifs not measures --- R/measure_change.R | 54 ++++++++++++++++++++++++++---------------- man/measure_periods.Rd | 51 +++++++++++++++++++-------------------- man/motif_periods.Rd | 53 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 111 insertions(+), 47 deletions(-) create mode 100644 man/motif_periods.Rd diff --git a/R/measure_change.R b/R/measure_change.R index a8471ee..88f71f8 100644 --- a/R/measure_change.R +++ b/R/measure_change.R @@ -1,19 +1,13 @@ -# Change #### +# Change measures #### #' Measures of network change +#' @name measure_periods #' @description -#' These functions measure certain topological features of networks: -#' -#' - `net_by_waves()` measures the number of waves in longitudinal network data. -#' - `net_by_change()` measures the Hamming distance between two or more networks. -#' - `net_by_stability()` measures the Jaccard index of stability between two or more networks. -#' - `net_by_correlation()` measures the product-moment correlation between two networks. +#' `net_by_waves()` measures the number of waves in longitudinal network data. #' -#' These `net_*()` functions return a numeric vector the length of the number -#' of networks minus one. E.g., the periods between waves. -#' @inheritParams mark_nodes -#' @name measure_periods -#' @family measures +#' @template param_data +#' @family change +#' @template net_measure NULL #' @rdname measure_periods @@ -29,10 +23,28 @@ net_by_waves <- function(.data){ .data, call = deparse(sys.call())) } -#' @rdname measure_periods +# Change motifs #### + +#' Motifs of network change +#' @name motif_periods +#' @description +#' These functions measure certain topological features of networks: +#' +#' - `net_x_change()` measures the Hamming distance between two or more networks. +#' - `net_x_stability()` measures the Jaccard index of stability between two or more networks. +#' - `net_x_correlation()` measures the product-moment correlation between two networks. +#' +#' These `net_*()` functions return a numeric vector the length of the number +#' of networks minus one. E.g., the periods between waves. +#' @template param_data +#' @family change +#' @template net_motif +NULL + +#' @rdname motif_periods #' @param object2 A network object. #' @export -net_by_change <- function(.data, object2){ +net_x_change <- function(.data, object2){ net <- manynet::expect_nodes(.data) if(!missing(object2)){ net <- list(net, object2) @@ -47,12 +59,12 @@ net_by_change <- function(.data, object2){ net2 <- manynet::as_matrix(net[[x+1]]) sum(net1 != net2) }, FUN.VALUE = numeric(1)) - make_network_measure(out, .data, call = deparse(sys.call())) + make_network_motif(out, .data) } -#' @rdname measure_periods +#' @rdname motif_periods #' @export -net_by_stability <- function(.data, object2){ +net_x_stability <- function(.data, object2){ net <- manynet::expect_nodes(.data) if(!missing(object2)){ net <- list(net, object2) @@ -70,12 +82,12 @@ net_by_stability <- function(.data, object2){ n10 <- sum(net1 * net2==0) n11 / (n01 + n10 + n11) }, FUN.VALUE = numeric(1)) - make_network_measure(out, .data, call = deparse(sys.call())) + make_network_motif(out, .data) } -#' @rdname measure_periods +#' @rdname motif_periods #' @export -net_by_correlation <- function(.data, object2){ +net_x_correlation <- function(.data, object2){ .data <- manynet::expect_nodes(.data) comp1 <- manynet::as_matrix(.data) comp2 <- manynet::as_matrix(object2) @@ -86,5 +98,5 @@ net_by_correlation <- function(.data, object2){ comp1[upper.tri(comp1)] <- NA } out <- cor(c(comp1), c(comp2), use = "complete.obs") - make_network_measure(out, .data, call = deparse(sys.call())) + make_network_motif(out, .data) } \ No newline at end of file diff --git a/man/measure_periods.Rd b/man/measure_periods.Rd index 067a754..8552c3f 100644 --- a/man/measure_periods.Rd +++ b/man/measure_periods.Rd @@ -3,57 +3,56 @@ \name{measure_periods} \alias{measure_periods} \alias{net_by_waves} -\alias{net_by_change} -\alias{net_by_stability} -\alias{net_by_correlation} \title{Measures of network change} \usage{ net_by_waves(.data) - -net_by_change(.data, object2) - -net_by_stability(.data, object2) - -net_by_correlation(.data, object2) } \arguments{ \item{.data}{A network object of class \code{mnet}, \code{igraph}, \code{tbl_graph}, \code{network}, or similar. For more information on the standard coercion possible, see \code{\link[manynet:manip_as]{manynet::as_tidygraph()}}.} - -\item{object2}{A network object.} } -\description{ -These functions measure certain topological features of networks: -\itemize{ -\item \code{net_by_waves()} measures the number of waves in longitudinal network data. -\item \code{net_by_change()} measures the Hamming distance between two or more networks. -\item \code{net_by_stability()} measures the Jaccard index of stability between two or more networks. -\item \code{net_by_correlation()} measures the product-moment correlation between two networks. +\value{ +A \code{network_measure} numeric score. } - -These \verb{net_*()} functions return a numeric vector the length of the number -of networks minus one. E.g., the periods between waves. +\description{ +\code{net_by_waves()} measures the number of waves in longitudinal network data. } \seealso{ +Other change: +\code{\link{motif_periods}} + Other measures: -\code{\link{measure_assortativity}}, +\code{\link{measure_assort_net}}, +\code{\link{measure_assort_node}}, \code{\link{measure_breadth}}, +\code{\link{measure_broker_node}}, +\code{\link{measure_broker_tie}}, \code{\link{measure_brokerage}}, \code{\link{measure_central_between}}, \code{\link{measure_central_close}}, \code{\link{measure_central_degree}}, \code{\link{measure_central_eigen}}, +\code{\link{measure_centralisation_between}}, +\code{\link{measure_centralisation_close}}, +\code{\link{measure_centralisation_degree}}, +\code{\link{measure_centralisation_eigen}}, +\code{\link{measure_centralities_between}}, +\code{\link{measure_centralities_close}}, +\code{\link{measure_centralities_degree}}, +\code{\link{measure_centralities_eigen}}, \code{\link{measure_closure}}, +\code{\link{measure_closure_node}}, \code{\link{measure_cohesion}}, +\code{\link{measure_core}}, \code{\link{measure_diffusion_infection}}, \code{\link{measure_diffusion_net}}, \code{\link{measure_diffusion_node}}, +\code{\link{measure_diverse_net}}, +\code{\link{measure_diverse_node}}, \code{\link{measure_features}}, \code{\link{measure_fragmentation}}, -\code{\link{measure_heterogeneity}}, -\code{\link{measure_hierarchy}}, -\code{\link{measure_holes}}, -\code{\link{member_diffusion}} +\code{\link{measure_hierarchy}} } +\concept{change} \concept{measures} diff --git a/man/motif_periods.Rd b/man/motif_periods.Rd new file mode 100644 index 0000000..16db108 --- /dev/null +++ b/man/motif_periods.Rd @@ -0,0 +1,53 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/measure_change.R +\name{motif_periods} +\alias{motif_periods} +\alias{net_x_change} +\alias{net_x_stability} +\alias{net_x_correlation} +\title{Motifs of network change} +\usage{ +net_x_change(.data, object2) + +net_x_stability(.data, object2) + +net_x_correlation(.data, object2) +} +\arguments{ +\item{.data}{A network object of class \code{mnet}, \code{igraph}, \code{tbl_graph}, \code{network}, or similar. +For more information on the standard coercion possible, +see \code{\link[manynet:manip_as]{manynet::as_tidygraph()}}.} + +\item{object2}{A network object.} +} +\value{ +A \code{network_motif} tibble with one row and a column for each motif type, +giving the count of each motif in the network. +} +\description{ +These functions measure certain topological features of networks: +\itemize{ +\item \code{net_x_change()} measures the Hamming distance between two or more networks. +\item \code{net_x_stability()} measures the Jaccard index of stability between two or more networks. +\item \code{net_x_correlation()} measures the product-moment correlation between two networks. +} + +These \verb{net_*()} functions return a numeric vector the length of the number +of networks minus one. E.g., the periods between waves. +} +\seealso{ +Other change: +\code{\link{measure_periods}} + +Other motifs: +\code{\link{motif_brokerage_net}}, +\code{\link{motif_brokerage_node}}, +\code{\link{motif_exposure}}, +\code{\link{motif_hazard}}, +\code{\link{motif_hierarchy}}, +\code{\link{motif_net}}, +\code{\link{motif_node}}, +\code{\link{motif_path}} +} +\concept{change} +\concept{motifs} From fd67ce62b3660e46cff7e12c5fe6f479b7363b72 Mon Sep 17 00:00:00 2001 From: James Hollway Date: Sat, 21 Mar 2026 18:19:28 +0100 Subject: [PATCH 17/35] Updated documentation for cohesion, closure, cliques, and components --- R/measure_closure.R | 133 +++++++++++++++++++++--------------- R/measure_cohesion.R | 49 +++++-------- R/member_cliques.R | 7 +- R/member_components.R | 7 +- man/measure_closure.Rd | 49 ++++++------- man/measure_closure_node.Rd | 112 ++++++++++++++++++++++++++++++ man/measure_cohesion.Rd | 53 +++++++------- man/member_cliques.Rd | 43 +++++++++++- man/member_components.Rd | 43 +++++++++++- 9 files changed, 350 insertions(+), 146 deletions(-) create mode 100644 man/measure_closure_node.Rd diff --git a/R/measure_closure.R b/R/measure_closure.R index a190f7a..1d82264 100644 --- a/R/measure_closure.R +++ b/R/measure_closure.R @@ -1,16 +1,16 @@ -#' Measures of network closure -#' +# Network closure #### + +#' Measuring network closure +#' @name measure_closure #' @description #' These functions offer methods for summarising the closure in configurations #' in one-, two-, and three-mode networks: #' -#' - `net_reciprocity()` measures reciprocity in a (usually directed) network. -#' - `node_reciprocity()` measures nodes' reciprocity. -#' - `net_transitivity()` measures transitivity in a network. -#' - `node_transitivity()` measures nodes' transitivity. -#' - `net_equivalency()` measures equivalence or reinforcement +#' - `net_by_reciprocity()` measures reciprocity in a (usually directed) network. +#' - `net_by_transitivity()` measures transitivity in a network. +#' - `net_by_equivalency()` measures equivalence or reinforcement #' in a (usually two-mode) network. -#' - `net_congruency()` measures congruency across two two-mode networks. +#' - `net_by_congruency()` measures congruency across two two-mode networks. #' #' @details #' For one-mode networks, shallow wrappers of igraph versions exist via @@ -22,12 +22,11 @@ #' For three-mode networks, `net_congruency` calculates the proportion of three-paths #' spanning two two-mode networks that are closed by a fourth tie to establish a #' "congruent four-cycle" structure. -#' @inheritParams mark_nodes +#' @template param_data +#' @template net_measure #' @param object2 Optionally, a second (two-mode) matrix, igraph, or tidygraph #' @param method For reciprocity, either `default` or `ratio`. #' See `?igraph::reciprocity` -#' @name measure_closure -#' @family measures NULL #' @rdname measure_closure @@ -41,17 +40,6 @@ net_by_reciprocity <- function(.data, method = "default") { .data, call = deparse(sys.call())) } -#' @rdname measure_closure -#' @examples -#' node_by_reciprocity(to_unweighted(ison_networkers)) -#' @export -node_by_reciprocity <- function(.data) { - .data <- manynet::expect_nodes(.data) - out <- manynet::as_matrix(.data) - make_node_measure(rowSums(out * t(out))/rowSums(out), - .data) -} - #' @rdname measure_closure #' @importFrom igraph transitivity #' @examples @@ -63,17 +51,6 @@ net_by_transitivity <- function(.data) { .data, call = deparse(sys.call())) } -#' @rdname measure_closure -#' @examples -#' node_by_transitivity(ison_adolescents) -#' @export -node_by_transitivity <- function(.data) { - .data <- manynet::expect_nodes(.data) - make_node_measure(igraph::transitivity(manynet::as_igraph(.data), - type = "local"), - .data) -} - #' @rdname measure_closure #' @section Equivalency: #' The `net_by_equivalency()` function calculates the Robins and Alexander (2004) @@ -118,27 +95,6 @@ net_by_equivalency <- function(.data) { make_network_measure(out, .data, call = deparse(sys.call())) } -#' @rdname measure_closure -#' @examples -#' # node_by_equivalency(ison_southern_women) -#' @export -node_by_equivalency <- function(.data) { - .data <- manynet::expect_nodes(.data) - # if(is_weighted(.data)) - # snet_info("Using unweighted form of the network.") - out <- vapply(manynet::snet_progress_seq(.data), function(i){ - threepaths <- igraph::all_simple_paths(.data, i, cutoff = 3, - mode = "all") - onepaths <- threepaths[vapply(threepaths, length, - FUN.VALUE = numeric(1))==2] - threepaths <- threepaths[vapply(threepaths, length, - FUN.VALUE = numeric(1))==4] - mean(sapply(threepaths,"[[",4) %in% sapply(onepaths,"[[",2)) - }, FUN.VALUE = numeric(1)) - if (any(is.nan(out))) out[is.nan(out)] <- 0 - make_node_measure(out, .data) -} - #' @rdname measure_closure #' @references #' ## On congruency @@ -155,8 +111,8 @@ net_by_congruency <- function(.data, object2){ manynet::snet_abort("This function expects two two-mode networks") if(manynet::net_dims(.data)[2] != manynet::net_dims(object2)[1]) manynet::snet_abort(paste("This function expects the number of nodes", - "in the second mode of the first network", "to be the same as the number of nodes", - "in the first mode of the second network.")) + "in the second mode of the first network", "to be the same as the number of nodes", + "in the first mode of the second network.")) mat1 <- manynet::as_matrix(.data) mat2 <- manynet::as_matrix(object2) connects <- ncol(mat1) @@ -175,3 +131,68 @@ net_by_congruency <- function(.data, object2){ if (is.nan(output)) output <- 1 make_network_measure(output, .data, call = deparse(sys.call())) } + +# Nodal closure #### + +#' Measuring node closure +#' @name measure_closure_node +#' @description +#' These functions offer methods for summarising the closure in configurations +#' in one- and two-mode networks: +#' +#' - `node_by_reciprocity()` measures nodes' reciprocity. +#' - `node_by_transitivity()` measures nodes' transitivity. +#' - `node_by_equivalency()` measures nodes' equivalence or reinforcement +#' in a (usually two-mode) network. +#' +#' @details +#' For one-mode networks, shallow wrappers of igraph versions exist via +#' `node_by_reciprocity` and `node_by_transitivity`. +#' +#' For two-mode networks, `node_by_equivalency` calculates the proportion of three-paths in the network +#' that are closed by fourth tie to establish a "shared four-cycle" structure. +#' @template param_data +#' @template node_measure +NULL + +#' @rdname measure_closure_node +#' @examples +#' node_by_reciprocity(to_unweighted(ison_networkers)) +#' @export +node_by_reciprocity <- function(.data) { + .data <- manynet::expect_nodes(.data) + out <- manynet::as_matrix(.data) + make_node_measure(rowSums(out * t(out))/rowSums(out), + .data) +} + +#' @rdname measure_closure_node +#' @examples +#' node_by_transitivity(ison_adolescents) +#' @export +node_by_transitivity <- function(.data) { + .data <- manynet::expect_nodes(.data) + make_node_measure(igraph::transitivity(manynet::as_igraph(.data), + type = "local"), + .data) +} + +#' @rdname measure_closure_node +#' @export +node_by_equivalency <- function(.data) { + .data <- manynet::expect_nodes(.data) + # if(is_weighted(.data)) + # snet_info("Using unweighted form of the network.") + out <- vapply(manynet::snet_progress_seq(.data), function(i){ + threepaths <- igraph::all_simple_paths(.data, i, cutoff = 3, + mode = "all") + onepaths <- threepaths[vapply(threepaths, length, + FUN.VALUE = numeric(1))==2] + threepaths <- threepaths[vapply(threepaths, length, + FUN.VALUE = numeric(1))==4] + mean(sapply(threepaths,"[[",4) %in% sapply(onepaths,"[[",2)) + }, FUN.VALUE = numeric(1)) + if (any(is.nan(out))) out[is.nan(out)] <- 0 + make_node_measure(out, .data) +} + diff --git a/R/measure_cohesion.R b/R/measure_cohesion.R index cf0e3f6..216bd61 100644 --- a/R/measure_cohesion.R +++ b/R/measure_cohesion.R @@ -1,31 +1,20 @@ # Cohesion #### #' Measures of network cohesion -#' +#' @name measure_cohesion #' @description #' These functions return values or vectors relating to how cohesive a network is: #' -#' - `net_density()` measures the ratio of ties to the number +#' - `net_by_density()` measures the ratio of ties to the number #' of possible ties. -#' - `net_components()` measures the number of (strong) components +#' - `net_by_components()` measures the number of (strong) components #' in the network. -#' - `net_cohesion()` measures the minimum number of nodes to remove -#' from the network needed to increase the number of components. -#' - `net_adhesion()` measures the minimum number of ties to remove -#' from the network needed to increase the number of components. -#' - `net_diameter()` measures the maximum path length in the network. -#' - `net_length()` measures the average path length in the network. -#' - `net_independence()` measures the independence number, +#' - `net_by_independence()` measures the independence number, #' or size of the largest independent set in the network. -#' - `net_strength()` measures the number of ties that would need to be -#' removed from a network to increase its number of components. -#' - `net_toughness()` measures the number of nodes that would need to be -#' removed from a network to increase its number of components. #' -#' @inheritParams mark_nodes -#' @name measure_cohesion -#' @family measures +#' @template param_data #' @family cohesion +#' @template net_measure NULL #' @rdname measure_cohesion @@ -79,17 +68,16 @@ net_by_independence <- function(.data){ # Breadth #### #' Measures of network breadth -#' +#' @name measure_breadth #' @description #' These functions return values or vectors relating to how broad a network is. #' -#' - `net_diameter()` measures the maximum path length in the network. -#' - `net_length()` measures the average path length in the network. +#' - `net_by_diameter()` measures the maximum path length in the network. +#' - `net_by_length()` measures the average path length in the network. #' -#' @inheritParams mark_nodes -#' @name measure_breadth -#' @family measures +#' @template param_data #' @family cohesion +#' @template net_measure NULL #' @rdname measure_breadth @@ -123,24 +111,23 @@ net_by_length <- function(.data){ # Fragmentation #### #' Measures of network fragmentation -#' +#' @name measure_fragmentation #' @description #' These functions return values relating to how connected a network is #' and the number of nodes or edges to remove that would increase fragmentation. #' -#' - `net_cohesion()` measures the minimum number of nodes to remove +#' - `net_by_cohesion()` measures the minimum number of nodes to remove #' from the network needed to increase the number of components. -#' - `net_toughness()` measures the number of nodes that would need to be +#' - `net_by_toughness()` measures the number of nodes that would need to be #' removed from a network to increase its number of components. -#' - `net_adhesion()` measures the minimum number of ties to remove +#' - `net_by_adhesion()` measures the minimum number of ties to remove #' from the network needed to increase the number of components. -#' - `net_strength()` measures the number of ties that would need to be +#' - `net_by_strength()` measures the number of ties that would need to be #' removed from a network to increase its number of components. #' -#' @inheritParams mark_nodes -#' @name measure_fragmentation -#' @family measures +#' @template param_data #' @family cohesion +#' @template net_measure NULL #' @rdname measure_fragmentation diff --git a/R/member_cliques.R b/R/member_cliques.R index 8b9e1ff..c224249 100644 --- a/R/member_cliques.R +++ b/R/member_cliques.R @@ -1,5 +1,4 @@ -#' Clique partitioning algorithms -#' +#' Memberships in maximally diverse cliques #' @description #' These functions create a vector of nodes' memberships in #' cliques: @@ -28,9 +27,9 @@ #' It includes both weak and strong perturbations to an initial solution #' to ensure that a robust solution from the broader state space is identified. #' The user is referred to Lai and Hao (2016) and Lai et al (2021) for more details. -#' @inheritParams mark_nodes +#' @template param_data +#' @template node_member #' @name member_cliques -#' @family memberships NULL #' @rdname member_cliques diff --git a/R/member_components.R b/R/member_components.R index 17e2cfb..69b3295 100644 --- a/R/member_components.R +++ b/R/member_components.R @@ -1,5 +1,4 @@ -#' Membership in components -#' +#' Memberships in components #' @description #' These functions create a vector of nodes' memberships in components: #' @@ -21,9 +20,9 @@ #' Weakly connected components consist of subgraphs where there is a path #' in either direction between member nodes. #' -#' @inheritParams mark_nodes +#' @template param_data +#' @template node_member #' @name member_components -#' @family memberships NULL #' @rdname member_components diff --git a/man/measure_closure.Rd b/man/measure_closure.Rd index d36e57b..2ebbfcf 100644 --- a/man/measure_closure.Rd +++ b/man/measure_closure.Rd @@ -3,26 +3,17 @@ \name{measure_closure} \alias{measure_closure} \alias{net_by_reciprocity} -\alias{node_by_reciprocity} \alias{net_by_transitivity} -\alias{node_by_transitivity} \alias{net_by_equivalency} -\alias{node_by_equivalency} \alias{net_by_congruency} -\title{Measures of network closure} +\title{Measuring network closure} \usage{ net_by_reciprocity(.data, method = "default") -node_by_reciprocity(.data) - net_by_transitivity(.data) -node_by_transitivity(.data) - net_by_equivalency(.data) -node_by_equivalency(.data) - net_by_congruency(.data, object2) } \arguments{ @@ -35,17 +26,18 @@ See \code{?igraph::reciprocity}} \item{object2}{Optionally, a second (two-mode) matrix, igraph, or tidygraph} } +\value{ +A \code{network_measure} numeric score. +} \description{ These functions offer methods for summarising the closure in configurations in one-, two-, and three-mode networks: \itemize{ -\item \code{net_reciprocity()} measures reciprocity in a (usually directed) network. -\item \code{node_reciprocity()} measures nodes' reciprocity. -\item \code{net_transitivity()} measures transitivity in a network. -\item \code{node_transitivity()} measures nodes' transitivity. -\item \code{net_equivalency()} measures equivalence or reinforcement +\item \code{net_by_reciprocity()} measures reciprocity in a (usually directed) network. +\item \code{net_by_transitivity()} measures transitivity in a network. +\item \code{net_by_equivalency()} measures equivalence or reinforcement in a (usually two-mode) network. -\item \code{net_congruency()} measures congruency across two two-mode networks. +\item \code{net_by_congruency()} measures congruency across two two-mode networks. } } \details{ @@ -68,11 +60,8 @@ Note that for weighted two-mode networks, the result is divided by the average t \examples{ net_by_reciprocity(ison_southern_women) -node_by_reciprocity(to_unweighted(ison_networkers)) net_by_transitivity(ison_adolescents) -node_by_transitivity(ison_adolescents) net_by_equivalency(ison_southern_women) -# node_by_equivalency(ison_southern_women) } \references{ \subsection{On equivalency or four-cycles}{ @@ -93,23 +82,35 @@ Cambridge University Press. Cambridge University Press. } \seealso{ Other measures: -\code{\link{measure_assortativity}}, +\code{\link{measure_assort_net}}, +\code{\link{measure_assort_node}}, \code{\link{measure_breadth}}, +\code{\link{measure_broker_node}}, +\code{\link{measure_broker_tie}}, \code{\link{measure_brokerage}}, \code{\link{measure_central_between}}, \code{\link{measure_central_close}}, \code{\link{measure_central_degree}}, \code{\link{measure_central_eigen}}, +\code{\link{measure_centralisation_between}}, +\code{\link{measure_centralisation_close}}, +\code{\link{measure_centralisation_degree}}, +\code{\link{measure_centralisation_eigen}}, +\code{\link{measure_centralities_between}}, +\code{\link{measure_centralities_close}}, +\code{\link{measure_centralities_degree}}, +\code{\link{measure_centralities_eigen}}, +\code{\link{measure_closure_node}}, \code{\link{measure_cohesion}}, +\code{\link{measure_core}}, \code{\link{measure_diffusion_infection}}, \code{\link{measure_diffusion_net}}, \code{\link{measure_diffusion_node}}, +\code{\link{measure_diverse_net}}, +\code{\link{measure_diverse_node}}, \code{\link{measure_features}}, \code{\link{measure_fragmentation}}, -\code{\link{measure_heterogeneity}}, \code{\link{measure_hierarchy}}, -\code{\link{measure_holes}}, -\code{\link{measure_periods}}, -\code{\link{member_diffusion}} +\code{\link{measure_periods}} } \concept{measures} diff --git a/man/measure_closure_node.Rd b/man/measure_closure_node.Rd new file mode 100644 index 0000000..a1eff59 --- /dev/null +++ b/man/measure_closure_node.Rd @@ -0,0 +1,112 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/measure_closure.R +\name{measure_closure_node} +\alias{measure_closure_node} +\alias{node_by_reciprocity} +\alias{node_by_transitivity} +\alias{node_by_equivalency} +\title{Measuring node closure} +\usage{ +node_by_reciprocity(.data) + +node_by_transitivity(.data) + +node_by_equivalency(.data) +} +\arguments{ +\item{.data}{A network object of class \code{mnet}, \code{igraph}, \code{tbl_graph}, \code{network}, or similar. +For more information on the standard coercion possible, +see \code{\link[manynet:manip_as]{manynet::as_tidygraph()}}.} +} +\value{ +A \code{node_measure} numeric vector the length of the nodes in the network, +providing the scores for each node. +If the network is labelled, +then the scores will be labelled with the nodes' names. +} +\description{ +These functions offer methods for summarising the closure in configurations +in one- and two-mode networks: +\itemize{ +\item \code{node_by_reciprocity()} measures nodes' reciprocity. +\item \code{node_by_transitivity()} measures nodes' transitivity. +\item \code{node_by_equivalency()} measures nodes' equivalence or reinforcement +in a (usually two-mode) network. +} +} +\details{ +For one-mode networks, shallow wrappers of igraph versions exist via +\code{node_by_reciprocity} and \code{node_by_transitivity}. + +For two-mode networks, \code{node_by_equivalency} calculates the proportion of three-paths in the network +that are closed by fourth tie to establish a "shared four-cycle" structure. +} +\examples{ +node_by_reciprocity(to_unweighted(ison_networkers)) +node_by_transitivity(ison_adolescents) +} +\seealso{ +Other measures: +\code{\link{measure_assort_net}}, +\code{\link{measure_assort_node}}, +\code{\link{measure_breadth}}, +\code{\link{measure_broker_node}}, +\code{\link{measure_broker_tie}}, +\code{\link{measure_brokerage}}, +\code{\link{measure_central_between}}, +\code{\link{measure_central_close}}, +\code{\link{measure_central_degree}}, +\code{\link{measure_central_eigen}}, +\code{\link{measure_centralisation_between}}, +\code{\link{measure_centralisation_close}}, +\code{\link{measure_centralisation_degree}}, +\code{\link{measure_centralisation_eigen}}, +\code{\link{measure_centralities_between}}, +\code{\link{measure_centralities_close}}, +\code{\link{measure_centralities_degree}}, +\code{\link{measure_centralities_eigen}}, +\code{\link{measure_closure}}, +\code{\link{measure_cohesion}}, +\code{\link{measure_core}}, +\code{\link{measure_diffusion_infection}}, +\code{\link{measure_diffusion_net}}, +\code{\link{measure_diffusion_node}}, +\code{\link{measure_diverse_net}}, +\code{\link{measure_diverse_node}}, +\code{\link{measure_features}}, +\code{\link{measure_fragmentation}}, +\code{\link{measure_hierarchy}}, +\code{\link{measure_periods}} + +Other nodal: +\code{\link{mark_core}}, +\code{\link{mark_degree}}, +\code{\link{mark_diff}}, +\code{\link{mark_nodes}}, +\code{\link{mark_select_node}}, +\code{\link{measure_assort_node}}, +\code{\link{measure_broker_node}}, +\code{\link{measure_brokerage}}, +\code{\link{measure_central_between}}, +\code{\link{measure_central_close}}, +\code{\link{measure_central_degree}}, +\code{\link{measure_central_eigen}}, +\code{\link{measure_core}}, +\code{\link{measure_diffusion_node}}, +\code{\link{measure_diverse_node}}, +\code{\link{member_brokerage}}, +\code{\link{member_cliques}}, +\code{\link{member_community}}, +\code{\link{member_community_hier}}, +\code{\link{member_community_non}}, +\code{\link{member_components}}, +\code{\link{member_core}}, +\code{\link{member_diffusion}}, +\code{\link{member_equivalence}}, +\code{\link{motif_brokerage_node}}, +\code{\link{motif_exposure}}, +\code{\link{motif_node}}, +\code{\link{motif_path}} +} +\concept{measures} +\concept{nodal} diff --git a/man/measure_cohesion.Rd b/man/measure_cohesion.Rd index 1818a85..570fc35 100644 --- a/man/measure_cohesion.Rd +++ b/man/measure_cohesion.Rd @@ -18,25 +18,18 @@ net_by_independence(.data) For more information on the standard coercion possible, see \code{\link[manynet:manip_as]{manynet::as_tidygraph()}}.} } +\value{ +A \code{network_measure} numeric score. +} \description{ These functions return values or vectors relating to how cohesive a network is: \itemize{ -\item \code{net_density()} measures the ratio of ties to the number +\item \code{net_by_density()} measures the ratio of ties to the number of possible ties. -\item \code{net_components()} measures the number of (strong) components +\item \code{net_by_components()} measures the number of (strong) components in the network. -\item \code{net_cohesion()} measures the minimum number of nodes to remove -from the network needed to increase the number of components. -\item \code{net_adhesion()} measures the minimum number of ties to remove -from the network needed to increase the number of components. -\item \code{net_diameter()} measures the maximum path length in the network. -\item \code{net_length()} measures the average path length in the network. -\item \code{net_independence()} measures the independence number, +\item \code{net_by_independence()} measures the independence number, or size of the largest independent set in the network. -\item \code{net_strength()} measures the number of ties that would need to be -removed from a network to increase its number of components. -\item \code{net_toughness()} measures the number of nodes that would need to be -removed from a network to increase its number of components. } } \section{Components}{ @@ -53,30 +46,44 @@ net_by_density(ison_southern_women) net_by_independence(ison_adolescents) } \seealso{ +Other cohesion: +\code{\link{mark_triangles}}, +\code{\link{measure_breadth}}, +\code{\link{measure_fragmentation}}, +\code{\link{motif_net}}, +\code{\link{motif_node}} + Other measures: -\code{\link{measure_assortativity}}, +\code{\link{measure_assort_net}}, +\code{\link{measure_assort_node}}, \code{\link{measure_breadth}}, +\code{\link{measure_broker_node}}, +\code{\link{measure_broker_tie}}, \code{\link{measure_brokerage}}, \code{\link{measure_central_between}}, \code{\link{measure_central_close}}, \code{\link{measure_central_degree}}, \code{\link{measure_central_eigen}}, +\code{\link{measure_centralisation_between}}, +\code{\link{measure_centralisation_close}}, +\code{\link{measure_centralisation_degree}}, +\code{\link{measure_centralisation_eigen}}, +\code{\link{measure_centralities_between}}, +\code{\link{measure_centralities_close}}, +\code{\link{measure_centralities_degree}}, +\code{\link{measure_centralities_eigen}}, \code{\link{measure_closure}}, +\code{\link{measure_closure_node}}, +\code{\link{measure_core}}, \code{\link{measure_diffusion_infection}}, \code{\link{measure_diffusion_net}}, \code{\link{measure_diffusion_node}}, +\code{\link{measure_diverse_net}}, +\code{\link{measure_diverse_node}}, \code{\link{measure_features}}, \code{\link{measure_fragmentation}}, -\code{\link{measure_heterogeneity}}, \code{\link{measure_hierarchy}}, -\code{\link{measure_holes}}, -\code{\link{measure_periods}}, -\code{\link{member_diffusion}} - -Other cohesion: -\code{\link{mark_triangles}}, -\code{\link{measure_breadth}}, -\code{\link{measure_fragmentation}} +\code{\link{measure_periods}} } \concept{cohesion} \concept{measures} diff --git a/man/member_cliques.Rd b/man/member_cliques.Rd index 7ac8a70..b2693b6 100644 --- a/man/member_cliques.Rd +++ b/man/member_cliques.Rd @@ -3,7 +3,7 @@ \name{member_cliques} \alias{member_cliques} \alias{node_in_roulette} -\title{Clique partitioning algorithms} +\title{Memberships in maximally diverse cliques} \usage{ node_in_roulette(.data, num_groups, group_size, times = NULL) } @@ -26,6 +26,12 @@ At every 10th iteration, a stronger perturbation of a number of successive chang approximately the number of nodes divided by the number of groups, will take place irrespective of whether it improves the objective function.} } +\value{ +A \code{node_member} character vector the length of the nodes in the network, +of group memberships "A", "B", etc for each node. +If the network is labelled, +then the assignments will be labelled with the nodes' names. +} \description{ These functions create a vector of nodes' memberships in cliques: @@ -74,11 +80,44 @@ Lai, Xiangjing, Jin-Kao Hao, Zhang-Hua Fu, and Dong Yue. 2021. } \seealso{ Other memberships: -\code{\link{mark_core}}, \code{\link{member_brokerage}}, +\code{\link{member_community}}, \code{\link{member_community_hier}}, \code{\link{member_community_non}}, \code{\link{member_components}}, +\code{\link{member_core}}, +\code{\link{member_diffusion}}, \code{\link{member_equivalence}} + +Other nodal: +\code{\link{mark_core}}, +\code{\link{mark_degree}}, +\code{\link{mark_diff}}, +\code{\link{mark_nodes}}, +\code{\link{mark_select_node}}, +\code{\link{measure_assort_node}}, +\code{\link{measure_broker_node}}, +\code{\link{measure_brokerage}}, +\code{\link{measure_central_between}}, +\code{\link{measure_central_close}}, +\code{\link{measure_central_degree}}, +\code{\link{measure_central_eigen}}, +\code{\link{measure_closure_node}}, +\code{\link{measure_core}}, +\code{\link{measure_diffusion_node}}, +\code{\link{measure_diverse_node}}, +\code{\link{member_brokerage}}, +\code{\link{member_community}}, +\code{\link{member_community_hier}}, +\code{\link{member_community_non}}, +\code{\link{member_components}}, +\code{\link{member_core}}, +\code{\link{member_diffusion}}, +\code{\link{member_equivalence}}, +\code{\link{motif_brokerage_node}}, +\code{\link{motif_exposure}}, +\code{\link{motif_node}}, +\code{\link{motif_path}} } \concept{memberships} +\concept{nodal} diff --git a/man/member_components.Rd b/man/member_components.Rd index 156926a..4805fb5 100644 --- a/man/member_components.Rd +++ b/man/member_components.Rd @@ -5,7 +5,7 @@ \alias{node_in_component} \alias{node_in_weak} \alias{node_in_strong} -\title{Membership in components} +\title{Memberships in components} \usage{ node_in_component(.data) @@ -18,6 +18,12 @@ node_in_strong(.data) For more information on the standard coercion possible, see \code{\link[manynet:manip_as]{manynet::as_tidygraph()}}.} } +\value{ +A \code{node_member} character vector the length of the nodes in the network, +of group memberships "A", "B", etc for each node. +If the network is labelled, +then the assignments will be labelled with the nodes' names. +} \description{ These functions create a vector of nodes' memberships in components: \itemize{ @@ -46,11 +52,44 @@ ison_monks \%>\% to_uniplex("esteem") \%>\% } \seealso{ Other memberships: -\code{\link{mark_core}}, \code{\link{member_brokerage}}, \code{\link{member_cliques}}, +\code{\link{member_community}}, \code{\link{member_community_hier}}, \code{\link{member_community_non}}, +\code{\link{member_core}}, +\code{\link{member_diffusion}}, \code{\link{member_equivalence}} + +Other nodal: +\code{\link{mark_core}}, +\code{\link{mark_degree}}, +\code{\link{mark_diff}}, +\code{\link{mark_nodes}}, +\code{\link{mark_select_node}}, +\code{\link{measure_assort_node}}, +\code{\link{measure_broker_node}}, +\code{\link{measure_brokerage}}, +\code{\link{measure_central_between}}, +\code{\link{measure_central_close}}, +\code{\link{measure_central_degree}}, +\code{\link{measure_central_eigen}}, +\code{\link{measure_closure_node}}, +\code{\link{measure_core}}, +\code{\link{measure_diffusion_node}}, +\code{\link{measure_diverse_node}}, +\code{\link{member_brokerage}}, +\code{\link{member_cliques}}, +\code{\link{member_community}}, +\code{\link{member_community_hier}}, +\code{\link{member_community_non}}, +\code{\link{member_core}}, +\code{\link{member_diffusion}}, +\code{\link{member_equivalence}}, +\code{\link{motif_brokerage_node}}, +\code{\link{motif_exposure}}, +\code{\link{motif_node}}, +\code{\link{motif_path}} } \concept{memberships} +\concept{nodal} From ff399a2dbc8495866cdce0b94e451cb13565b320 Mon Sep 17 00:00:00 2001 From: James Hollway Date: Sat, 21 Mar 2026 18:22:15 +0100 Subject: [PATCH 18/35] Updated features and hierarchy documentation --- R/measure_features.R | 15 ++++++------ R/measure_hierarchy.R | 32 ++++++++++++------------- man/mark_degree.Rd | 45 ++++++++++++++++++++++++++++++++---- man/mark_diff.Rd | 43 +++++++++++++++++++++++++++++++--- man/mark_dyads.Rd | 16 +++++++++++-- man/mark_triangles.Rd | 20 +++++++++++++--- man/measure_breadth.Rd | 41 ++++++++++++++++++++++---------- man/measure_features.Rd | 35 ++++++++++++++++++++-------- man/measure_fragmentation.Rd | 45 +++++++++++++++++++++++++----------- man/measure_hierarchy.Rd | 31 ++++++++++++++++++------- man/motif_hierarchy.Rd | 32 +++++++++++++++---------- 11 files changed, 262 insertions(+), 93 deletions(-) diff --git a/R/measure_features.R b/R/measure_features.R index 6248a2d..608d6fc 100644 --- a/R/measure_features.R +++ b/R/measure_features.R @@ -1,6 +1,7 @@ # Topological features #### -#' Measures of network topological features +#' Measuring network topological features +#' @name measure_features #' @description #' These functions measure certain topological features of networks: #' @@ -24,11 +25,9 @@ #' ranging between `0` if all triangles are imbalanced and #' `1` if all triangles are balanced. #' -#' These `net_*()` functions return a single numeric scalar or value. -#' @inheritParams mark_nodes -#' @param membership A vector of partition membership. -#' @name measure_features -#' @family measures +#' @template param_data +#' @template param_memb +#' @template net_measure NULL #' @rdname measure_features @@ -343,11 +342,11 @@ net_by_smallworld <- function(.data, net_by_scalefree <- function(.data){ .data <- manynet::expect_nodes(.data) out <- igraph::fit_power_law(node_by_deg(.data)) - if (!"KS.p" %in% names(out)) out$KS.p <- ks.test(seq(0, 1 - out$KS.stat, + if (!"KS.p" %in% names(out)) out$KS.p <- stats::ks.test(seq(0, 1 - out$KS.stat, length.out = manynet::net_nodes(.data)), "punif")$p.value if(out$KS.p < 0.05) - snet_info("Note: Kolgomorov-Smirnov test that data could have been drawn", + manynet::snet_info("Note: Kolgomorov-Smirnov test that data could have been drawn", "from a power-law distribution rejected.") make_network_measure(out$alpha, .data, call = deparse(sys.call())) diff --git a/R/measure_hierarchy.R b/R/measure_hierarchy.R index fd4fc4e..1c8845f 100644 --- a/R/measure_hierarchy.R +++ b/R/measure_hierarchy.R @@ -1,25 +1,24 @@ # Motifs #### -#' Motifs of hierarchy -#' +#' Motifs of network hierarchy +#' @name motif_hierarchy #' @description -#' This function collects the measures of hierarchy into a single motif, +#' `net_x_hierarchy()` collects the measures of hierarchy into a single motif, #' which can be used to compare the relative hierarchy of different networks. #' The measures of hierarchy are: -#' - `net_connectedness()` measures the proportion of dyads in the network +#' - `net_by_connectedness()` measures the proportion of dyads in the network #' that are reachable to one another, #' or the degree to which network is a single component. -#' - `net_efficiency()` measures the Krackhardt efficiency score. -#' - `net_upperbound()` measures the Krackhardt (least) upper bound +#' - `net_by_efficiency()` measures the Krackhardt efficiency score. +#' - `net_by_upperbound()` measures the Krackhardt (least) upper bound #' score. -#' - `net_reciprocity()` measures the proportion of ties in the network that +#' - `net_by_reciprocity()` measures the proportion of ties in the network that #' are reciprocated, #' which is a measure of the degree to which the network is non-hierarchical. #' -#' @inheritParams mark_nodes -#' @name motif_hierarchy -#' @family motifs +#' @template param_data #' @family hierarchy +#' @template net_motif #' @references #' ## On hierarchy #' Krackhardt, David. 1994. @@ -49,20 +48,19 @@ net_x_hierarchy <- function(.data){ # Measures #### #' Measures of hierarchy -#' +#' @name measure_hierarchy #' @description #' These functions, together with `net_reciprocity()`, are used jointly to #' measure how hierarchical a network is: #' -#' - `net_connectedness()` measures the proportion of dyads in the network +#' - `net_by_connectedness()` measures the proportion of dyads in the network #' that are reachable to one another, #' or the degree to which network is a single component. -#' - `net_efficiency()` measures the Krackhardt efficiency score. -#' - `net_upperbound()` measures the Krackhardt (least) upper bound score. +#' - `net_by_efficiency()` measures the Krackhardt efficiency score. +#' - `net_by_upperbound()` measures the Krackhardt (least) upper bound score. #' -#' @inheritParams mark_nodes -#' @name measure_hierarchy -#' @family measures +#' @template param_data +#' @template net_measure #' @family hierarchy #' @references #' ## On hierarchy diff --git a/man/mark_degree.Rd b/man/mark_degree.Rd index 2938978..1632bde 100644 --- a/man/mark_degree.Rd +++ b/man/mark_degree.Rd @@ -15,7 +15,8 @@ node_is_universal(.data) } \arguments{ \item{.data}{A network object of class \code{mnet}, \code{igraph}, \code{tbl_graph}, \code{network}, or similar. -For more information on what coercions are possible, see \code{\link[manynet:manip_as]{manynet::as_tidygraph()}}.} +For more information on the standard coercion possible, +see \code{\link[manynet:manip_as]{manynet::as_tidygraph()}}.} } \value{ A \code{node_mark} logical vector the length of the nodes in the network, @@ -50,17 +51,51 @@ node_is_isolate(ison_brandes) node_is_universal(create_star(11)) } \seealso{ +Other degree: +\code{\link{measure_central_degree}}, +\code{\link{measure_centralisation_degree}}, +\code{\link{measure_centralities_degree}} + Other marks: +\code{\link{mark_core}}, \code{\link{mark_diff}}, \code{\link{mark_dyads}}, \code{\link{mark_nodes}}, -\code{\link{mark_select}}, -\code{\link{mark_tie_select}}, +\code{\link{mark_select_node}}, +\code{\link{mark_select_tie}}, \code{\link{mark_ties}}, \code{\link{mark_triangles}} -Other degree: -\code{\link{measure_central_degree}} +Other nodal: +\code{\link{mark_core}}, +\code{\link{mark_diff}}, +\code{\link{mark_nodes}}, +\code{\link{mark_select_node}}, +\code{\link{measure_assort_node}}, +\code{\link{measure_broker_node}}, +\code{\link{measure_brokerage}}, +\code{\link{measure_central_between}}, +\code{\link{measure_central_close}}, +\code{\link{measure_central_degree}}, +\code{\link{measure_central_eigen}}, +\code{\link{measure_closure_node}}, +\code{\link{measure_core}}, +\code{\link{measure_diffusion_node}}, +\code{\link{measure_diverse_node}}, +\code{\link{member_brokerage}}, +\code{\link{member_cliques}}, +\code{\link{member_community}}, +\code{\link{member_community_hier}}, +\code{\link{member_community_non}}, +\code{\link{member_components}}, +\code{\link{member_core}}, +\code{\link{member_diffusion}}, +\code{\link{member_equivalence}}, +\code{\link{motif_brokerage_node}}, +\code{\link{motif_exposure}}, +\code{\link{motif_node}}, +\code{\link{motif_path}} } \concept{degree} \concept{marks} +\concept{nodal} diff --git a/man/mark_diff.Rd b/man/mark_diff.Rd index 135cc71..18c0188 100644 --- a/man/mark_diff.Rd +++ b/man/mark_diff.Rd @@ -17,6 +17,10 @@ node_is_recovered(.data, time = 0) node_is_exposed(.data, mark, time = 0) } \arguments{ +\item{.data}{A network object of class \code{mnet}, \code{igraph}, \code{tbl_graph}, \code{network}, or similar. +For more information on the standard coercion possible, +see \code{\link[manynet:manip_as]{manynet::as_tidygraph()}}.} + \item{time}{A time step at which nodes are identified.} \item{mark}{vector denoting which nodes are infected} @@ -61,20 +65,53 @@ in that diffusion. } \seealso{ Other marks: +\code{\link{mark_core}}, \code{\link{mark_degree}}, \code{\link{mark_dyads}}, \code{\link{mark_nodes}}, -\code{\link{mark_select}}, -\code{\link{mark_tie_select}}, +\code{\link{mark_select_node}}, +\code{\link{mark_select_tie}}, \code{\link{mark_ties}}, \code{\link{mark_triangles}} +Other nodal: +\code{\link{mark_core}}, +\code{\link{mark_degree}}, +\code{\link{mark_nodes}}, +\code{\link{mark_select_node}}, +\code{\link{measure_assort_node}}, +\code{\link{measure_broker_node}}, +\code{\link{measure_brokerage}}, +\code{\link{measure_central_between}}, +\code{\link{measure_central_close}}, +\code{\link{measure_central_degree}}, +\code{\link{measure_central_eigen}}, +\code{\link{measure_closure_node}}, +\code{\link{measure_core}}, +\code{\link{measure_diffusion_node}}, +\code{\link{measure_diverse_node}}, +\code{\link{member_brokerage}}, +\code{\link{member_cliques}}, +\code{\link{member_community}}, +\code{\link{member_community_hier}}, +\code{\link{member_community_non}}, +\code{\link{member_components}}, +\code{\link{member_core}}, +\code{\link{member_diffusion}}, +\code{\link{member_equivalence}}, +\code{\link{motif_brokerage_node}}, +\code{\link{motif_exposure}}, +\code{\link{motif_node}}, +\code{\link{motif_path}} + Other diffusion: \code{\link{measure_diffusion_infection}}, \code{\link{measure_diffusion_net}}, \code{\link{measure_diffusion_node}}, \code{\link{member_diffusion}}, -\code{\link{motif_diffusion}} +\code{\link{motif_exposure}}, +\code{\link{motif_hazard}} } \concept{diffusion} \concept{marks} +\concept{nodal} diff --git a/man/mark_dyads.Rd b/man/mark_dyads.Rd index c5b9723..a46b149 100644 --- a/man/mark_dyads.Rd +++ b/man/mark_dyads.Rd @@ -37,12 +37,24 @@ tie_is_reciprocated(ison_algebra) } \seealso{ Other marks: +\code{\link{mark_core}}, \code{\link{mark_degree}}, \code{\link{mark_diff}}, \code{\link{mark_nodes}}, -\code{\link{mark_select}}, -\code{\link{mark_tie_select}}, +\code{\link{mark_select_node}}, +\code{\link{mark_select_tie}}, \code{\link{mark_ties}}, \code{\link{mark_triangles}} + +Other tie: +\code{\link{mark_select_tie}}, +\code{\link{mark_ties}}, +\code{\link{mark_triangles}}, +\code{\link{measure_broker_tie}}, +\code{\link{measure_centralities_between}}, +\code{\link{measure_centralities_close}}, +\code{\link{measure_centralities_degree}}, +\code{\link{measure_centralities_eigen}} } \concept{marks} +\concept{tie} diff --git a/man/mark_triangles.Rd b/man/mark_triangles.Rd index 660b370..bc486a5 100644 --- a/man/mark_triangles.Rd +++ b/man/mark_triangles.Rd @@ -63,18 +63,32 @@ fict_marvel \%>\% to_uniplex("relationship") \%>\% tie_is_imbalanced() } \seealso{ Other marks: +\code{\link{mark_core}}, \code{\link{mark_degree}}, \code{\link{mark_diff}}, \code{\link{mark_dyads}}, \code{\link{mark_nodes}}, -\code{\link{mark_select}}, -\code{\link{mark_tie_select}}, +\code{\link{mark_select_node}}, +\code{\link{mark_select_tie}}, \code{\link{mark_ties}} +Other tie: +\code{\link{mark_dyads}}, +\code{\link{mark_select_tie}}, +\code{\link{mark_ties}}, +\code{\link{measure_broker_tie}}, +\code{\link{measure_centralities_between}}, +\code{\link{measure_centralities_close}}, +\code{\link{measure_centralities_degree}}, +\code{\link{measure_centralities_eigen}} + Other cohesion: \code{\link{measure_breadth}}, \code{\link{measure_cohesion}}, -\code{\link{measure_fragmentation}} +\code{\link{measure_fragmentation}}, +\code{\link{motif_net}}, +\code{\link{motif_node}} } \concept{cohesion} \concept{marks} +\concept{tie} diff --git a/man/measure_breadth.Rd b/man/measure_breadth.Rd index 17c9608..b84e960 100644 --- a/man/measure_breadth.Rd +++ b/man/measure_breadth.Rd @@ -15,11 +15,14 @@ net_by_length(.data) For more information on the standard coercion possible, see \code{\link[manynet:manip_as]{manynet::as_tidygraph()}}.} } +\value{ +A \code{network_measure} numeric score. +} \description{ These functions return values or vectors relating to how broad a network is. \itemize{ -\item \code{net_diameter()} measures the maximum path length in the network. -\item \code{net_length()} measures the average path length in the network. +\item \code{net_by_diameter()} measures the maximum path length in the network. +\item \code{net_by_length()} measures the average path length in the network. } } \examples{ @@ -29,30 +32,44 @@ net_by_length(fict_marvel) net_by_length(to_giant(fict_marvel)) } \seealso{ +Other cohesion: +\code{\link{mark_triangles}}, +\code{\link{measure_cohesion}}, +\code{\link{measure_fragmentation}}, +\code{\link{motif_net}}, +\code{\link{motif_node}} + Other measures: -\code{\link{measure_assortativity}}, +\code{\link{measure_assort_net}}, +\code{\link{measure_assort_node}}, +\code{\link{measure_broker_node}}, +\code{\link{measure_broker_tie}}, \code{\link{measure_brokerage}}, \code{\link{measure_central_between}}, \code{\link{measure_central_close}}, \code{\link{measure_central_degree}}, \code{\link{measure_central_eigen}}, +\code{\link{measure_centralisation_between}}, +\code{\link{measure_centralisation_close}}, +\code{\link{measure_centralisation_degree}}, +\code{\link{measure_centralisation_eigen}}, +\code{\link{measure_centralities_between}}, +\code{\link{measure_centralities_close}}, +\code{\link{measure_centralities_degree}}, +\code{\link{measure_centralities_eigen}}, \code{\link{measure_closure}}, +\code{\link{measure_closure_node}}, \code{\link{measure_cohesion}}, +\code{\link{measure_core}}, \code{\link{measure_diffusion_infection}}, \code{\link{measure_diffusion_net}}, \code{\link{measure_diffusion_node}}, +\code{\link{measure_diverse_net}}, +\code{\link{measure_diverse_node}}, \code{\link{measure_features}}, \code{\link{measure_fragmentation}}, -\code{\link{measure_heterogeneity}}, \code{\link{measure_hierarchy}}, -\code{\link{measure_holes}}, -\code{\link{measure_periods}}, -\code{\link{member_diffusion}} - -Other cohesion: -\code{\link{mark_triangles}}, -\code{\link{measure_cohesion}}, -\code{\link{measure_fragmentation}} +\code{\link{measure_periods}} } \concept{cohesion} \concept{measures} diff --git a/man/measure_features.Rd b/man/measure_features.Rd index 4dc1322..d5006fd 100644 --- a/man/measure_features.Rd +++ b/man/measure_features.Rd @@ -9,7 +9,7 @@ \alias{net_by_smallworld} \alias{net_by_scalefree} \alias{net_by_balance} -\title{Measures of network topological features} +\title{Measuring network topological features} \source{ \code{{signnet}} by David Schoch } @@ -63,7 +63,11 @@ with the same dimensions. but where there may not be a network for which \eqn{SWI = 1}. }} -\item{membership}{A vector of partition membership.} +\item{membership}{A character vector of categorical membership. +This is a vector of the same length as the number of nodes in the network, +where each element is a character string indicating the membership of the corresponding node. +While this may often be a vector created using \verb{node_in_*()} functions, +it can be any character vector that assigns nodes to groups or categories.} \item{resolution}{A proportion indicating the resolution scale. By default 1, which returns the original definition of modularity. @@ -72,6 +76,9 @@ The lower this parameter, the fewer larger communities are likely to be found.} \item{times}{Integer of number of simulations.} } +\value{ +A \code{network_measure} numeric score. +} \description{ These functions measure certain topological features of networks: \itemize{ @@ -95,8 +102,6 @@ the proportion of balanced triangles, ranging between \code{0} if all triangles are imbalanced and \code{1} if all triangles are balanced. } - -These \verb{net_*()} functions return a single numeric scalar or value. } \section{Core-Periphery}{ @@ -234,23 +239,35 @@ Cartwright, D., and Frank Harary. 1956. for how clustering is calculated Other measures: -\code{\link{measure_assortativity}}, +\code{\link{measure_assort_net}}, +\code{\link{measure_assort_node}}, \code{\link{measure_breadth}}, +\code{\link{measure_broker_node}}, +\code{\link{measure_broker_tie}}, \code{\link{measure_brokerage}}, \code{\link{measure_central_between}}, \code{\link{measure_central_close}}, \code{\link{measure_central_degree}}, \code{\link{measure_central_eigen}}, +\code{\link{measure_centralisation_between}}, +\code{\link{measure_centralisation_close}}, +\code{\link{measure_centralisation_degree}}, +\code{\link{measure_centralisation_eigen}}, +\code{\link{measure_centralities_between}}, +\code{\link{measure_centralities_close}}, +\code{\link{measure_centralities_degree}}, +\code{\link{measure_centralities_eigen}}, \code{\link{measure_closure}}, +\code{\link{measure_closure_node}}, \code{\link{measure_cohesion}}, +\code{\link{measure_core}}, \code{\link{measure_diffusion_infection}}, \code{\link{measure_diffusion_net}}, \code{\link{measure_diffusion_node}}, +\code{\link{measure_diverse_net}}, +\code{\link{measure_diverse_node}}, \code{\link{measure_fragmentation}}, -\code{\link{measure_heterogeneity}}, \code{\link{measure_hierarchy}}, -\code{\link{measure_holes}}, -\code{\link{measure_periods}}, -\code{\link{member_diffusion}} +\code{\link{measure_periods}} } \concept{measures} diff --git a/man/measure_fragmentation.Rd b/man/measure_fragmentation.Rd index 29b1427..8709f0d 100644 --- a/man/measure_fragmentation.Rd +++ b/man/measure_fragmentation.Rd @@ -21,17 +21,20 @@ net_by_toughness(.data) For more information on the standard coercion possible, see \code{\link[manynet:manip_as]{manynet::as_tidygraph()}}.} } +\value{ +A \code{network_measure} numeric score. +} \description{ These functions return values relating to how connected a network is and the number of nodes or edges to remove that would increase fragmentation. \itemize{ -\item \code{net_cohesion()} measures the minimum number of nodes to remove +\item \code{net_by_cohesion()} measures the minimum number of nodes to remove from the network needed to increase the number of components. -\item \code{net_toughness()} measures the number of nodes that would need to be +\item \code{net_by_toughness()} measures the number of nodes that would need to be removed from a network to increase its number of components. -\item \code{net_adhesion()} measures the minimum number of ties to remove +\item \code{net_by_adhesion()} measures the minimum number of ties to remove from the network needed to increase the number of components. -\item \code{net_strength()} measures the number of ties that would need to be +\item \code{net_by_strength()} measures the number of ties that would need to be removed from a network to increase its number of components. } } @@ -53,30 +56,44 @@ White, Douglas R and Frank Harary. 2001. } } \seealso{ +Other cohesion: +\code{\link{mark_triangles}}, +\code{\link{measure_breadth}}, +\code{\link{measure_cohesion}}, +\code{\link{motif_net}}, +\code{\link{motif_node}} + Other measures: -\code{\link{measure_assortativity}}, +\code{\link{measure_assort_net}}, +\code{\link{measure_assort_node}}, \code{\link{measure_breadth}}, +\code{\link{measure_broker_node}}, +\code{\link{measure_broker_tie}}, \code{\link{measure_brokerage}}, \code{\link{measure_central_between}}, \code{\link{measure_central_close}}, \code{\link{measure_central_degree}}, \code{\link{measure_central_eigen}}, +\code{\link{measure_centralisation_between}}, +\code{\link{measure_centralisation_close}}, +\code{\link{measure_centralisation_degree}}, +\code{\link{measure_centralisation_eigen}}, +\code{\link{measure_centralities_between}}, +\code{\link{measure_centralities_close}}, +\code{\link{measure_centralities_degree}}, +\code{\link{measure_centralities_eigen}}, \code{\link{measure_closure}}, +\code{\link{measure_closure_node}}, \code{\link{measure_cohesion}}, +\code{\link{measure_core}}, \code{\link{measure_diffusion_infection}}, \code{\link{measure_diffusion_net}}, \code{\link{measure_diffusion_node}}, +\code{\link{measure_diverse_net}}, +\code{\link{measure_diverse_node}}, \code{\link{measure_features}}, -\code{\link{measure_heterogeneity}}, \code{\link{measure_hierarchy}}, -\code{\link{measure_holes}}, -\code{\link{measure_periods}}, -\code{\link{member_diffusion}} - -Other cohesion: -\code{\link{mark_triangles}}, -\code{\link{measure_breadth}}, -\code{\link{measure_cohesion}} +\code{\link{measure_periods}} } \concept{cohesion} \concept{measures} diff --git a/man/measure_hierarchy.Rd b/man/measure_hierarchy.Rd index 3f9ca79..45f59b5 100644 --- a/man/measure_hierarchy.Rd +++ b/man/measure_hierarchy.Rd @@ -18,15 +18,18 @@ net_by_upperbound(.data) For more information on the standard coercion possible, see \code{\link[manynet:manip_as]{manynet::as_tidygraph()}}.} } +\value{ +A \code{network_measure} numeric score. +} \description{ These functions, together with \code{net_reciprocity()}, are used jointly to measure how hierarchical a network is: \itemize{ -\item \code{net_connectedness()} measures the proportion of dyads in the network +\item \code{net_by_connectedness()} measures the proportion of dyads in the network that are reachable to one another, or the degree to which network is a single component. -\item \code{net_efficiency()} measures the Krackhardt efficiency score. -\item \code{net_upperbound()} measures the Krackhardt (least) upper bound score. +\item \code{net_by_efficiency()} measures the Krackhardt efficiency score. +\item \code{net_by_upperbound()} measures the Krackhardt (least) upper bound score. } } \examples{ @@ -51,24 +54,36 @@ Everett, Martin, and David Krackhardt. 2012. } \seealso{ Other measures: -\code{\link{measure_assortativity}}, +\code{\link{measure_assort_net}}, +\code{\link{measure_assort_node}}, \code{\link{measure_breadth}}, +\code{\link{measure_broker_node}}, +\code{\link{measure_broker_tie}}, \code{\link{measure_brokerage}}, \code{\link{measure_central_between}}, \code{\link{measure_central_close}}, \code{\link{measure_central_degree}}, \code{\link{measure_central_eigen}}, +\code{\link{measure_centralisation_between}}, +\code{\link{measure_centralisation_close}}, +\code{\link{measure_centralisation_degree}}, +\code{\link{measure_centralisation_eigen}}, +\code{\link{measure_centralities_between}}, +\code{\link{measure_centralities_close}}, +\code{\link{measure_centralities_degree}}, +\code{\link{measure_centralities_eigen}}, \code{\link{measure_closure}}, +\code{\link{measure_closure_node}}, \code{\link{measure_cohesion}}, +\code{\link{measure_core}}, \code{\link{measure_diffusion_infection}}, \code{\link{measure_diffusion_net}}, \code{\link{measure_diffusion_node}}, +\code{\link{measure_diverse_net}}, +\code{\link{measure_diverse_node}}, \code{\link{measure_features}}, \code{\link{measure_fragmentation}}, -\code{\link{measure_heterogeneity}}, -\code{\link{measure_holes}}, -\code{\link{measure_periods}}, -\code{\link{member_diffusion}} +\code{\link{measure_periods}} Other hierarchy: \code{\link{motif_hierarchy}} diff --git a/man/motif_hierarchy.Rd b/man/motif_hierarchy.Rd index ac38c62..0664ca2 100644 --- a/man/motif_hierarchy.Rd +++ b/man/motif_hierarchy.Rd @@ -3,7 +3,7 @@ \name{motif_hierarchy} \alias{motif_hierarchy} \alias{net_x_hierarchy} -\title{Motifs of hierarchy} +\title{Motifs of network hierarchy} \usage{ net_x_hierarchy(.data) } @@ -12,18 +12,22 @@ net_x_hierarchy(.data) For more information on the standard coercion possible, see \code{\link[manynet:manip_as]{manynet::as_tidygraph()}}.} } +\value{ +A \code{network_motif} tibble with one row and a column for each motif type, +giving the count of each motif in the network. +} \description{ -This function collects the measures of hierarchy into a single motif, +\code{net_x_hierarchy()} collects the measures of hierarchy into a single motif, which can be used to compare the relative hierarchy of different networks. The measures of hierarchy are: \itemize{ -\item \code{net_connectedness()} measures the proportion of dyads in the network +\item \code{net_by_connectedness()} measures the proportion of dyads in the network that are reachable to one another, or the degree to which network is a single component. -\item \code{net_efficiency()} measures the Krackhardt efficiency score. -\item \code{net_upperbound()} measures the Krackhardt (least) upper bound +\item \code{net_by_efficiency()} measures the Krackhardt efficiency score. +\item \code{net_by_upperbound()} measures the Krackhardt (least) upper bound score. -\item \code{net_reciprocity()} measures the proportion of ties in the network that +\item \code{net_by_reciprocity()} measures the proportion of ties in the network that are reciprocated, which is a measure of the degree to which the network is non-hierarchical. } @@ -46,14 +50,18 @@ Everett, Martin, and David Krackhardt. 2012. } } \seealso{ -Other motifs: -\code{\link{motif_brokerage}}, -\code{\link{motif_diffusion}}, -\code{\link{motif_net}}, -\code{\link{motif_node}} - Other hierarchy: \code{\link{measure_hierarchy}} + +Other motifs: +\code{\link{motif_brokerage_net}}, +\code{\link{motif_brokerage_node}}, +\code{\link{motif_exposure}}, +\code{\link{motif_hazard}}, +\code{\link{motif_net}}, +\code{\link{motif_node}}, +\code{\link{motif_path}}, +\code{\link{motif_periods}} } \concept{hierarchy} \concept{motifs} From 1a5c722cddfb33d713cbd3d250a138085c48b738 Mon Sep 17 00:00:00 2001 From: James Hollway Date: Sat, 21 Mar 2026 18:23:13 +0100 Subject: [PATCH 19/35] Separated node_in_community() from hierarchical and non-hierarchical algorithms --- R/member_community.R | 95 ++++++++++++++++++++---------------- man/member_community.Rd | 79 ++++++++++++++++++++++++++++++ man/member_community_hier.Rd | 44 ++++++++++++++++- man/member_community_non.Rd | 61 ++++++++++++++++------- 4 files changed, 218 insertions(+), 61 deletions(-) create mode 100644 man/member_community.Rd diff --git a/R/member_community.R b/R/member_community.R index feb08d8..0afc6e9 100644 --- a/R/member_community.R +++ b/R/member_community.R @@ -1,53 +1,31 @@ -# Non-hierarchical community clustering #### +# Community clustering #### -#' Non-hierarchical community clustering algorithms -#' +#' Memberships in communities +#' @name member_community #' @description -#' These functions offer algorithms for partitioning -#' networks into sets of communities: -#' -#' - `node_in_community()` runs either optimal or, for larger networks, -#' finds the algorithm that maximises modularity and returns that membership -#' vector. -#' - `node_in_optimal()` is a problem-solving algorithm that seeks to maximise -#' modularity over all possible partitions. -#' - `node_in_partition()` is a greedy, iterative, deterministic -#' partitioning algorithm that results in two equally-sized communities. -#' - `node_in_infomap()` is an algorithm based on the information in random walks. -#' - `node_in_spinglass()` is a greedy, iterative, probabilistic algorithm, -#' based on analogy to model from statistical physics. -#' - `node_in_fluid()` is a propogation-based partitioning algorithm, -#' based on analogy to model from fluid dynamics. -#' - `node_in_louvain()` is an agglomerative multilevel algorithm that seeks to maximise -#' modularity over all possible partitions. -#' - `node_in_leiden()` is an agglomerative multilevel algorithm that seeks to maximise -#' the Constant Potts Model over all possible partitions. -#' -#' The different algorithms offer various advantages in terms of computation time, -#' availability on different types of networks, ability to maximise modularity, -#' and their logic or domain of inspiration. -#' -#' @inheritParams mark_nodes -#' @name member_community_non -#' @family memberships -#' @family community -NULL - -#' @rdname member_community_non -#' @section Community: -#' This function runs through all available community detection algorithms +#' `node_in_community()` runs through all available community detection algorithms #' for a given network type, finds the algorithm that returns the #' largest modularity score, and returns the corresponding membership #' partition. #' Where feasible (a small enough network), the optimal problem solving #' technique is used to ensure the maximal modularity partition. +#' For larger networks, it identifies the applicable algorithms and +#' finds the algorithm that maximises modularity and +#' returns that membership vector. +#' +#' @template param_data +#' @family community +#' @template node_member +NULL + +#' @rdname member_community #' @export node_in_community <- function(.data){ .data <- manynet::expect_nodes(.data) if(manynet::net_nodes(.data)<100){ # don't use node_in_betweenness because slow and poorer quality to optimal manynet::snet_success("{.fn node_in_optimal} available and", - "will return the highest modularity partition.") + "will return the highest modularity partition.") netrics::node_in_optimal(.data) } else { manynet::snet_info("Excluding {.fn node_in_optimal} because network rather large.") @@ -85,6 +63,40 @@ node_in_community <- function(.data){ } } +# Non-hierarchical community clustering #### + +#' Memberships in non-hierarchical communities +#' @name member_community_non +#' @description +#' These functions offer algorithms for partitioning +#' networks into sets of communities: +#' +#' - `node_in_community()` runs either optimal or, for larger networks, +#' finds the algorithm that maximises modularity and returns that membership +#' vector. +#' - `node_in_optimal()` is a problem-solving algorithm that seeks to maximise +#' modularity over all possible partitions. +#' - `node_in_partition()` is a greedy, iterative, deterministic +#' partitioning algorithm that results in two equally-sized communities. +#' - `node_in_infomap()` is an algorithm based on the information in random walks. +#' - `node_in_spinglass()` is a greedy, iterative, probabilistic algorithm, +#' based on analogy to model from statistical physics. +#' - `node_in_fluid()` is a propogation-based partitioning algorithm, +#' based on analogy to model from fluid dynamics. +#' - `node_in_louvain()` is an agglomerative multilevel algorithm that seeks to maximise +#' modularity over all possible partitions. +#' - `node_in_leiden()` is an agglomerative multilevel algorithm that seeks to maximise +#' the Constant Potts Model over all possible partitions. +#' +#' The different algorithms offer various advantages in terms of computation time, +#' availability on different types of networks, ability to maximise modularity, +#' and their logic or domain of inspiration. +#' +#' @template param_data +#' @family community +#' @template node_member +NULL + #' @rdname member_community_non #' @section Optimal: #' The general idea is to calculate the modularity of all possible partitions, @@ -358,8 +370,8 @@ node_in_leiden <- function(.data, resolution = 1){ # Hierarchical community clustering #### -#' Hierarchical community clustering algorithms -#' +#' Memberships in hierarchical communities +#' @name member_community_hier #' @description #' These functions offer algorithms for hierarchically clustering #' networks into communities. Since all of the following are hierarchical, @@ -377,9 +389,8 @@ node_in_leiden <- function(.data, resolution = 1){ #' availability on different types of networks, ability to maximise modularity, #' and their logic or domain of inspiration. #' -#' @inheritParams member_community_non -#' @name member_community_hier -#' @family memberships +#' @template param_data +#' @template node_member #' @family community NULL diff --git a/man/member_community.Rd b/man/member_community.Rd new file mode 100644 index 0000000..1d2eebe --- /dev/null +++ b/man/member_community.Rd @@ -0,0 +1,79 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/member_community.R +\name{member_community} +\alias{member_community} +\alias{node_in_community} +\title{Memberships in communities} +\usage{ +node_in_community(.data) +} +\arguments{ +\item{.data}{A network object of class \code{mnet}, \code{igraph}, \code{tbl_graph}, \code{network}, or similar. +For more information on the standard coercion possible, +see \code{\link[manynet:manip_as]{manynet::as_tidygraph()}}.} +} +\value{ +A \code{node_member} character vector the length of the nodes in the network, +of group memberships "A", "B", etc for each node. +If the network is labelled, +then the assignments will be labelled with the nodes' names. +} +\description{ +\code{node_in_community()} runs through all available community detection algorithms +for a given network type, finds the algorithm that returns the +largest modularity score, and returns the corresponding membership +partition. +Where feasible (a small enough network), the optimal problem solving +technique is used to ensure the maximal modularity partition. +For larger networks, it identifies the applicable algorithms and +finds the algorithm that maximises modularity and +returns that membership vector. +} +\seealso{ +Other community: +\code{\link{member_community_hier}}, +\code{\link{member_community_non}} + +Other memberships: +\code{\link{member_brokerage}}, +\code{\link{member_cliques}}, +\code{\link{member_community_hier}}, +\code{\link{member_community_non}}, +\code{\link{member_components}}, +\code{\link{member_core}}, +\code{\link{member_diffusion}}, +\code{\link{member_equivalence}} + +Other nodal: +\code{\link{mark_core}}, +\code{\link{mark_degree}}, +\code{\link{mark_diff}}, +\code{\link{mark_nodes}}, +\code{\link{mark_select_node}}, +\code{\link{measure_assort_node}}, +\code{\link{measure_broker_node}}, +\code{\link{measure_brokerage}}, +\code{\link{measure_central_between}}, +\code{\link{measure_central_close}}, +\code{\link{measure_central_degree}}, +\code{\link{measure_central_eigen}}, +\code{\link{measure_closure_node}}, +\code{\link{measure_core}}, +\code{\link{measure_diffusion_node}}, +\code{\link{measure_diverse_node}}, +\code{\link{member_brokerage}}, +\code{\link{member_cliques}}, +\code{\link{member_community_hier}}, +\code{\link{member_community_non}}, +\code{\link{member_components}}, +\code{\link{member_core}}, +\code{\link{member_diffusion}}, +\code{\link{member_equivalence}}, +\code{\link{motif_brokerage_node}}, +\code{\link{motif_exposure}}, +\code{\link{motif_node}}, +\code{\link{motif_path}} +} +\concept{community} +\concept{memberships} +\concept{nodal} diff --git a/man/member_community_hier.Rd b/man/member_community_hier.Rd index f2232b7..daa772b 100644 --- a/man/member_community_hier.Rd +++ b/man/member_community_hier.Rd @@ -6,7 +6,7 @@ \alias{node_in_greedy} \alias{node_in_eigen} \alias{node_in_walktrap} -\title{Hierarchical community clustering algorithms} +\title{Memberships in hierarchical communities} \usage{ node_in_betweenness(.data) @@ -24,6 +24,12 @@ see \code{\link[manynet:manip_as]{manynet::as_tidygraph()}}.} \item{times}{Integer indicating number of simulations/walks used. By default, \code{times=50}.} } +\value{ +A \code{node_member} character vector the length of the nodes in the network, +of group memberships "A", "B", etc for each node. +If the network is labelled, +then the assignments will be labelled with the nodes' names. +} \description{ These functions offer algorithms for hierarchically clustering networks into communities. Since all of the following are hierarchical, @@ -124,15 +130,49 @@ Pons, Pascal, and Matthieu Latapy. 2005. } \seealso{ Other memberships: -\code{\link{mark_core}}, \code{\link{member_brokerage}}, \code{\link{member_cliques}}, +\code{\link{member_community}}, \code{\link{member_community_non}}, \code{\link{member_components}}, +\code{\link{member_core}}, +\code{\link{member_diffusion}}, \code{\link{member_equivalence}} +Other nodal: +\code{\link{mark_core}}, +\code{\link{mark_degree}}, +\code{\link{mark_diff}}, +\code{\link{mark_nodes}}, +\code{\link{mark_select_node}}, +\code{\link{measure_assort_node}}, +\code{\link{measure_broker_node}}, +\code{\link{measure_brokerage}}, +\code{\link{measure_central_between}}, +\code{\link{measure_central_close}}, +\code{\link{measure_central_degree}}, +\code{\link{measure_central_eigen}}, +\code{\link{measure_closure_node}}, +\code{\link{measure_core}}, +\code{\link{measure_diffusion_node}}, +\code{\link{measure_diverse_node}}, +\code{\link{member_brokerage}}, +\code{\link{member_cliques}}, +\code{\link{member_community}}, +\code{\link{member_community_non}}, +\code{\link{member_components}}, +\code{\link{member_core}}, +\code{\link{member_diffusion}}, +\code{\link{member_equivalence}}, +\code{\link{motif_brokerage_node}}, +\code{\link{motif_exposure}}, +\code{\link{motif_node}}, +\code{\link{motif_path}} + Other community: +\code{\link{member_community}}, \code{\link{member_community_non}} } \concept{community} \concept{memberships} +\concept{nodal} diff --git a/man/member_community_non.Rd b/man/member_community_non.Rd index e1ad097..e3c663e 100644 --- a/man/member_community_non.Rd +++ b/man/member_community_non.Rd @@ -2,7 +2,6 @@ % Please edit documentation in R/member_community.R \name{member_community_non} \alias{member_community_non} -\alias{node_in_community} \alias{node_in_optimal} \alias{node_in_partition} \alias{node_in_infomap} @@ -10,10 +9,8 @@ \alias{node_in_fluid} \alias{node_in_louvain} \alias{node_in_leiden} -\title{Non-hierarchical community clustering algorithms} +\title{Memberships in non-hierarchical communities} \usage{ -node_in_community(.data) - node_in_optimal(.data) node_in_partition(.data) @@ -44,6 +41,12 @@ By default 1, making existing and non-existing ties equally important. Smaller values make existing ties more important, and larger values make missing ties more important.} } +\value{ +A \code{node_member} character vector the length of the nodes in the network, +of group memberships "A", "B", etc for each node. +If the network is labelled, +then the assignments will be labelled with the nodes' names. +} \description{ These functions offer algorithms for partitioning networks into sets of communities: @@ -70,16 +73,6 @@ The different algorithms offer various advantages in terms of computation time, availability on different types of networks, ability to maximise modularity, and their logic or domain of inspiration. } -\section{Community}{ - -This function runs through all available community detection algorithms -for a given network type, finds the algorithm that returns the -largest modularity score, and returns the corresponding membership -partition. -Where feasible (a small enough network), the optimal problem solving -technique is used to ensure the maximal modularity partition. -} - \section{Optimal}{ The general idea is to calculate the modularity of all possible partitions, @@ -222,16 +215,50 @@ Traag, Vincent A., Ludo Waltman, and Nees Jan van Eck. 2019. } } \seealso{ +Other community: +\code{\link{member_community}}, +\code{\link{member_community_hier}} + Other memberships: -\code{\link{mark_core}}, \code{\link{member_brokerage}}, \code{\link{member_cliques}}, +\code{\link{member_community}}, \code{\link{member_community_hier}}, \code{\link{member_components}}, +\code{\link{member_core}}, +\code{\link{member_diffusion}}, \code{\link{member_equivalence}} -Other community: -\code{\link{member_community_hier}} +Other nodal: +\code{\link{mark_core}}, +\code{\link{mark_degree}}, +\code{\link{mark_diff}}, +\code{\link{mark_nodes}}, +\code{\link{mark_select_node}}, +\code{\link{measure_assort_node}}, +\code{\link{measure_broker_node}}, +\code{\link{measure_brokerage}}, +\code{\link{measure_central_between}}, +\code{\link{measure_central_close}}, +\code{\link{measure_central_degree}}, +\code{\link{measure_central_eigen}}, +\code{\link{measure_closure_node}}, +\code{\link{measure_core}}, +\code{\link{measure_diffusion_node}}, +\code{\link{measure_diverse_node}}, +\code{\link{member_brokerage}}, +\code{\link{member_cliques}}, +\code{\link{member_community}}, +\code{\link{member_community_hier}}, +\code{\link{member_components}}, +\code{\link{member_core}}, +\code{\link{member_diffusion}}, +\code{\link{member_equivalence}}, +\code{\link{motif_brokerage_node}}, +\code{\link{motif_exposure}}, +\code{\link{motif_node}}, +\code{\link{motif_path}} } \concept{community} \concept{memberships} +\concept{nodal} From 051c90c168beb680249b404f21f8f62deb2ca2d1 Mon Sep 17 00:00:00 2001 From: James Hollway Date: Sat, 21 Mar 2026 18:24:01 +0100 Subject: [PATCH 20/35] Separated out core documentation into mark, measure, and member --- R/member_core.R | 74 ++++++++++++++++--------- man/mark_core.Rd | 129 ++++++++++++++++++-------------------------- man/measure_core.Rd | 128 +++++++++++++++++++++++++++++++++++++++++++ man/member_core.Rd | 101 ++++++++++++++++++++++++++++++++++ 4 files changed, 330 insertions(+), 102 deletions(-) create mode 100644 man/measure_core.Rd create mode 100644 man/member_core.Rd diff --git a/R/member_core.R b/R/member_core.R index f3dfae8..16d4044 100644 --- a/R/member_core.R +++ b/R/member_core.R @@ -1,24 +1,20 @@ -#' Core-periphery clustering algorithms +# Marking core #### + +#' Marking nodes as core or periphery +#' @name mark_core #' @description -#' These functions identify nodes belonging to (some level of) the core of a network: -#' -#' - `node_is_core()` identifies whether nodes belong to the core of the +#' `node_is_core()` identifies whether nodes belong to the core of the #' network, as opposed to the periphery. -#' - `node_in_core()` categorizes nodes into two or more core/periphery -#' categories based on their coreness. -#' - `node_coreness()` returns a continuous measure of how closely each node -#' resembles a typical core node. -#' - `node_kcoreness()` assigns nodes to their level of k-coreness. #' -#' @inheritParams mark_nodes -#' @param method Which method to use to identify cores and periphery. +#' @template param_data +#' @family core-periphery +#' @template node_mark +#' @param centrality Which centrality measure to use to identify cores and periphery. #' By default this is "degree", #' which relies on the heuristic that high degree nodes are more likely to be in the core. #' An alternative is "eigenvector", which instead begins with high eigenvector nodes. #' Other methods, such as a genetic algorithm, CONCOR, and Rombach-Porter, #' can be added if there is interest. -#' @name mark_core -#' @family memberships NULL #' @rdname mark_core @@ -45,18 +41,17 @@ NULL #' \doi{10.48550/arXiv.1102.5511} #' @examples #' node_is_core(ison_adolescents) -#' #ison_adolescents %>% -#' # mutate(corep = node_is_core()) %>% -#' # graphr(node_color = "corep") +#' ison_adolescents %>% +#' mutate(corep = node_is_core()) #' @export -node_is_core <- function(.data, method = c("degree", "eigenvector")){ +node_is_core <- function(.data, centrality = c("degree", "eigenvector")){ .data <- manynet::expect_nodes(.data) - method <- match.arg(method) + centrality <- match.arg(centrality) if(manynet::is_directed(.data)) warning("Asymmetric core-periphery not yet implemented.") - if(method == "degree"){ + if(centrality == "degree"){ degi <- node_by_degree(.data, normalized = FALSE, - alpha = ifelse(manynet::is_weighted(.data), 1, 0)) - } else if (method == "eigenvector") { + alpha = ifelse(manynet::is_weighted(.data), 1, 0)) + } else if (centrality == "eigenvector") { degi <- node_by_eigenvector(.data, normalized = FALSE) } else manynet::snet_abort("This function expects either 'degree' or 'eigenvector' method to be specified.") nord <- order(degi, decreasing = TRUE) @@ -71,11 +66,27 @@ node_is_core <- function(.data, method = c("degree", "eigenvector")){ } } out <- ifelse(seq_len(manynet::net_nodes(.data)) %in% nord[seq_len(kbest)], - 1,2) + 1,2) make_node_mark(out==1, .data) } -#' @rdname mark_core +# Measuring core #### + +#' Measuring nodes' coreness +#' @name measure_core +#' @description +#' These functions identify nodes belonging to (some level of) the core of a network: +#' +#' - `node_by_coreness()` returns a continuous measure of how closely each node +#' resembles a typical core node. +#' - `node_by_kcoreness()` assigns nodes to their level of k-coreness. +#' +#' @template param_data +#' @family core-periphery +#' @template node_measure +NULL + +#' @rdname measure_core #' @section k-coreness: #' k-coreness captures the maximal subgraphs in which each vertex has at least #' degree _k_, where _k_ is also the order of the subgraph. @@ -103,7 +114,7 @@ node_by_kcoreness <- function(.data){ make_node_measure(out, .data) } -#' @rdname mark_core +#' @rdname measure_core #' @examples #' node_by_coreness(ison_adolescents) #' @export @@ -124,7 +135,20 @@ node_by_coreness <- function(.data) { make_node_measure(result$par, .data) } -#' @rdname mark_core +# Membering core #### + +#' Memberships in core-periphery categories +#' @name member_core +#' @description +#' `node_in_core()` categorizes nodes into two or more core/periphery +#' categories based on their coreness. +#' +#' @template param_data +#' @family core-periphery +#' @template node_member +NULL + +#' @rdname member_core #' @param groups Number of categories to create. Must be at least 2 and at most #' the number of nodes in the network. Default is 3. #' @param cluster_by Method to use to create the categories. diff --git a/man/mark_core.Rd b/man/mark_core.Rd index 857f2fd..4519441 100644 --- a/man/mark_core.Rd +++ b/man/mark_core.Rd @@ -3,49 +3,30 @@ \name{mark_core} \alias{mark_core} \alias{node_is_core} -\alias{node_by_kcoreness} -\alias{node_by_coreness} -\alias{node_in_core} -\title{Core-periphery clustering algorithms} +\title{Marking nodes as core or periphery} \usage{ -node_is_core(.data, method = c("degree", "eigenvector")) - -node_by_kcoreness(.data) - -node_by_coreness(.data) - -node_in_core(.data, groups = 3, cluster_by = c("bins", "quantiles", "kmeans")) +node_is_core(.data, centrality = c("degree", "eigenvector")) } \arguments{ \item{.data}{A network object of class \code{mnet}, \code{igraph}, \code{tbl_graph}, \code{network}, or similar. For more information on the standard coercion possible, see \code{\link[manynet:manip_as]{manynet::as_tidygraph()}}.} -\item{method}{Which method to use to identify cores and periphery. +\item{centrality}{Which centrality measure to use to identify cores and periphery. By default this is "degree", which relies on the heuristic that high degree nodes are more likely to be in the core. An alternative is "eigenvector", which instead begins with high eigenvector nodes. Other methods, such as a genetic algorithm, CONCOR, and Rombach-Porter, can be added if there is interest.} - -\item{groups}{Number of categories to create. Must be at least 2 and at most -the number of nodes in the network. Default is 3.} - -\item{cluster_by}{Method to use to create the categories. -One of "bins" (equal-width bins), "quantiles" (quantile-based bins), -or "kmeans" (k-means clustering). Default is "bins".} +} +\value{ +A \code{node_mark} logical vector the length of the nodes in the network, +giving either TRUE or FALSE for each node depending on +whether the condition is matched. } \description{ -These functions identify nodes belonging to (some level of) the core of a network: -\itemize{ -\item \code{node_is_core()} identifies whether nodes belong to the core of the +\code{node_is_core()} identifies whether nodes belong to the core of the network, as opposed to the periphery. -\item \code{node_in_core()} categorizes nodes into two or more core/periphery -categories based on their coreness. -\item \code{node_coreness()} returns a continuous measure of how closely each node -resembles a typical core node. -\item \code{node_kcoreness()} assigns nodes to their level of k-coreness. -} } \section{Core-periphery}{ @@ -61,33 +42,10 @@ and minimises density in the periphery block; it ignores ties between these blocks. } -\section{k-coreness}{ - -k-coreness captures the maximal subgraphs in which each vertex has at least -degree \emph{k}, where \emph{k} is also the order of the subgraph. -As described in \code{igraph::coreness}, -a node's coreness is \emph{k} if it belongs to the \emph{k}-core -but not to the (\emph{k}+1)-core. -} - -\section{Core-periphery categories}{ - -This function categorizes nodes based on their coreness into a specified -number of groups. The groups are labeled as "Core", "Semi-core", -"Semi-periphery", and "Periphery" depending on the number of groups -specified. -The categorization can be done using different methods: equal-width bins, -quantile-based bins, or k-means clustering. -} - \examples{ node_is_core(ison_adolescents) -#ison_adolescents \%>\% -# mutate(corep = node_is_core()) \%>\% -# graphr(node_color = "corep") -node_by_kcoreness(ison_adolescents) -node_by_coreness(ison_adolescents) -node_in_core(ison_adolescents) +ison_adolescents \%>\% + mutate(corep = node_is_core()) } \references{ \subsection{On core-periphery partitioning}{ @@ -101,35 +59,52 @@ Lip, Sean Z. W. 2011. “A Fast Algorithm for the Discrete Core/Periphery Bipartitioning Problem.” \doi{10.48550/arXiv.1102.5511} } - -\subsection{On k-coreness}{ - -Seidman, Stephen B. 1983. -"Network structure and minimum degree". -\emph{Social Networks}, 5(3), 269-287. -\doi{10.1016/0378-8733(83)90028-X} - -Batagelj, Vladimir, and Matjaz Zaversnik. 2003. -"An O(m) algorithm for cores decomposition of networks". -\emph{arXiv preprint} cs/0310049. -\doi{10.48550/arXiv.cs/0310049} -} - -\subsection{On core-periphery categorization}{ - -Wallerstein, Immanuel. 1974. -"Dependence in an Interdependent World: The Limited Possibilities of Transformation Within the Capitalist World Economy." -\emph{African Studies Review}, 17(1), 1-26. -\doi{https://doi.org/10.2307/523574} -} } \seealso{ -Other memberships: +Other core-periphery: +\code{\link{measure_core}}, +\code{\link{member_core}} + +Other marks: +\code{\link{mark_degree}}, +\code{\link{mark_diff}}, +\code{\link{mark_dyads}}, +\code{\link{mark_nodes}}, +\code{\link{mark_select_node}}, +\code{\link{mark_select_tie}}, +\code{\link{mark_ties}}, +\code{\link{mark_triangles}} + +Other nodal: +\code{\link{mark_degree}}, +\code{\link{mark_diff}}, +\code{\link{mark_nodes}}, +\code{\link{mark_select_node}}, +\code{\link{measure_assort_node}}, +\code{\link{measure_broker_node}}, +\code{\link{measure_brokerage}}, +\code{\link{measure_central_between}}, +\code{\link{measure_central_close}}, +\code{\link{measure_central_degree}}, +\code{\link{measure_central_eigen}}, +\code{\link{measure_closure_node}}, +\code{\link{measure_core}}, +\code{\link{measure_diffusion_node}}, +\code{\link{measure_diverse_node}}, \code{\link{member_brokerage}}, \code{\link{member_cliques}}, +\code{\link{member_community}}, \code{\link{member_community_hier}}, \code{\link{member_community_non}}, \code{\link{member_components}}, -\code{\link{member_equivalence}} +\code{\link{member_core}}, +\code{\link{member_diffusion}}, +\code{\link{member_equivalence}}, +\code{\link{motif_brokerage_node}}, +\code{\link{motif_exposure}}, +\code{\link{motif_node}}, +\code{\link{motif_path}} } -\concept{memberships} +\concept{core-periphery} +\concept{marks} +\concept{nodal} diff --git a/man/measure_core.Rd b/man/measure_core.Rd new file mode 100644 index 0000000..4f8e9e2 --- /dev/null +++ b/man/measure_core.Rd @@ -0,0 +1,128 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/member_core.R +\name{measure_core} +\alias{measure_core} +\alias{node_by_kcoreness} +\alias{node_by_coreness} +\title{Measuring nodes' coreness} +\usage{ +node_by_kcoreness(.data) + +node_by_coreness(.data) +} +\arguments{ +\item{.data}{A network object of class \code{mnet}, \code{igraph}, \code{tbl_graph}, \code{network}, or similar. +For more information on the standard coercion possible, +see \code{\link[manynet:manip_as]{manynet::as_tidygraph()}}.} +} +\value{ +A \code{node_measure} numeric vector the length of the nodes in the network, +providing the scores for each node. +If the network is labelled, +then the scores will be labelled with the nodes' names. +} +\description{ +These functions identify nodes belonging to (some level of) the core of a network: +\itemize{ +\item \code{node_by_coreness()} returns a continuous measure of how closely each node +resembles a typical core node. +\item \code{node_by_kcoreness()} assigns nodes to their level of k-coreness. +} +} +\section{k-coreness}{ + +k-coreness captures the maximal subgraphs in which each vertex has at least +degree \emph{k}, where \emph{k} is also the order of the subgraph. +As described in \code{igraph::coreness}, +a node's coreness is \emph{k} if it belongs to the \emph{k}-core +but not to the (\emph{k}+1)-core. +} + +\examples{ +node_by_kcoreness(ison_adolescents) +node_by_coreness(ison_adolescents) +} +\references{ +\subsection{On k-coreness}{ + +Seidman, Stephen B. 1983. +"Network structure and minimum degree". +\emph{Social Networks}, 5(3), 269-287. +\doi{10.1016/0378-8733(83)90028-X} + +Batagelj, Vladimir, and Matjaz Zaversnik. 2003. +"An O(m) algorithm for cores decomposition of networks". +\emph{arXiv preprint} cs/0310049. +\doi{10.48550/arXiv.cs/0310049} +} +} +\seealso{ +Other core-periphery: +\code{\link{mark_core}}, +\code{\link{member_core}} + +Other measures: +\code{\link{measure_assort_net}}, +\code{\link{measure_assort_node}}, +\code{\link{measure_breadth}}, +\code{\link{measure_broker_node}}, +\code{\link{measure_broker_tie}}, +\code{\link{measure_brokerage}}, +\code{\link{measure_central_between}}, +\code{\link{measure_central_close}}, +\code{\link{measure_central_degree}}, +\code{\link{measure_central_eigen}}, +\code{\link{measure_centralisation_between}}, +\code{\link{measure_centralisation_close}}, +\code{\link{measure_centralisation_degree}}, +\code{\link{measure_centralisation_eigen}}, +\code{\link{measure_centralities_between}}, +\code{\link{measure_centralities_close}}, +\code{\link{measure_centralities_degree}}, +\code{\link{measure_centralities_eigen}}, +\code{\link{measure_closure}}, +\code{\link{measure_closure_node}}, +\code{\link{measure_cohesion}}, +\code{\link{measure_diffusion_infection}}, +\code{\link{measure_diffusion_net}}, +\code{\link{measure_diffusion_node}}, +\code{\link{measure_diverse_net}}, +\code{\link{measure_diverse_node}}, +\code{\link{measure_features}}, +\code{\link{measure_fragmentation}}, +\code{\link{measure_hierarchy}}, +\code{\link{measure_periods}} + +Other nodal: +\code{\link{mark_core}}, +\code{\link{mark_degree}}, +\code{\link{mark_diff}}, +\code{\link{mark_nodes}}, +\code{\link{mark_select_node}}, +\code{\link{measure_assort_node}}, +\code{\link{measure_broker_node}}, +\code{\link{measure_brokerage}}, +\code{\link{measure_central_between}}, +\code{\link{measure_central_close}}, +\code{\link{measure_central_degree}}, +\code{\link{measure_central_eigen}}, +\code{\link{measure_closure_node}}, +\code{\link{measure_diffusion_node}}, +\code{\link{measure_diverse_node}}, +\code{\link{member_brokerage}}, +\code{\link{member_cliques}}, +\code{\link{member_community}}, +\code{\link{member_community_hier}}, +\code{\link{member_community_non}}, +\code{\link{member_components}}, +\code{\link{member_core}}, +\code{\link{member_diffusion}}, +\code{\link{member_equivalence}}, +\code{\link{motif_brokerage_node}}, +\code{\link{motif_exposure}}, +\code{\link{motif_node}}, +\code{\link{motif_path}} +} +\concept{core-periphery} +\concept{measures} +\concept{nodal} diff --git a/man/member_core.Rd b/man/member_core.Rd new file mode 100644 index 0000000..88d2d4b --- /dev/null +++ b/man/member_core.Rd @@ -0,0 +1,101 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/member_core.R +\name{member_core} +\alias{member_core} +\alias{node_in_core} +\title{Memberships in core-periphery categories} +\usage{ +node_in_core(.data, groups = 3, cluster_by = c("bins", "quantiles", "kmeans")) +} +\arguments{ +\item{.data}{A network object of class \code{mnet}, \code{igraph}, \code{tbl_graph}, \code{network}, or similar. +For more information on the standard coercion possible, +see \code{\link[manynet:manip_as]{manynet::as_tidygraph()}}.} + +\item{groups}{Number of categories to create. Must be at least 2 and at most +the number of nodes in the network. Default is 3.} + +\item{cluster_by}{Method to use to create the categories. +One of "bins" (equal-width bins), "quantiles" (quantile-based bins), +or "kmeans" (k-means clustering). Default is "bins".} +} +\value{ +A \code{node_member} character vector the length of the nodes in the network, +of group memberships "A", "B", etc for each node. +If the network is labelled, +then the assignments will be labelled with the nodes' names. +} +\description{ +\code{node_in_core()} categorizes nodes into two or more core/periphery +categories based on their coreness. +} +\section{Core-periphery categories}{ + +This function categorizes nodes based on their coreness into a specified +number of groups. The groups are labeled as "Core", "Semi-core", +"Semi-periphery", and "Periphery" depending on the number of groups +specified. +The categorization can be done using different methods: equal-width bins, +quantile-based bins, or k-means clustering. +} + +\examples{ +node_in_core(ison_adolescents) +} +\references{ +\subsection{On core-periphery categorization}{ + +Wallerstein, Immanuel. 1974. +"Dependence in an Interdependent World: The Limited Possibilities of Transformation Within the Capitalist World Economy." +\emph{African Studies Review}, 17(1), 1-26. +\doi{https://doi.org/10.2307/523574} +} +} +\seealso{ +Other core-periphery: +\code{\link{mark_core}}, +\code{\link{measure_core}} + +Other memberships: +\code{\link{member_brokerage}}, +\code{\link{member_cliques}}, +\code{\link{member_community}}, +\code{\link{member_community_hier}}, +\code{\link{member_community_non}}, +\code{\link{member_components}}, +\code{\link{member_diffusion}}, +\code{\link{member_equivalence}} + +Other nodal: +\code{\link{mark_core}}, +\code{\link{mark_degree}}, +\code{\link{mark_diff}}, +\code{\link{mark_nodes}}, +\code{\link{mark_select_node}}, +\code{\link{measure_assort_node}}, +\code{\link{measure_broker_node}}, +\code{\link{measure_brokerage}}, +\code{\link{measure_central_between}}, +\code{\link{measure_central_close}}, +\code{\link{measure_central_degree}}, +\code{\link{measure_central_eigen}}, +\code{\link{measure_closure_node}}, +\code{\link{measure_core}}, +\code{\link{measure_diffusion_node}}, +\code{\link{measure_diverse_node}}, +\code{\link{member_brokerage}}, +\code{\link{member_cliques}}, +\code{\link{member_community}}, +\code{\link{member_community_hier}}, +\code{\link{member_community_non}}, +\code{\link{member_components}}, +\code{\link{member_diffusion}}, +\code{\link{member_equivalence}}, +\code{\link{motif_brokerage_node}}, +\code{\link{motif_exposure}}, +\code{\link{motif_node}}, +\code{\link{motif_path}} +} +\concept{core-periphery} +\concept{memberships} +\concept{nodal} From 8301deb7f30efff13a29e3bb2de5e594805861e2 Mon Sep 17 00:00:00 2001 From: James Hollway Date: Sat, 21 Mar 2026 18:26:34 +0100 Subject: [PATCH 21/35] Renamed node_adoption_time() and node_thresholds() to node_by_adopt_time() and node_by_adopt_threshold() respectively --- R/measure_diffusion.R | 63 +++++++------ man/measure_diffusion_infection.Rd | 53 +++++++---- man/measure_diffusion_net.Rd | 43 ++++++--- man/measure_diffusion_node.Rd | 99 ++++++++++++++++----- man/member_diffusion.Rd | 60 +++++++++---- man/motif_exposure.Rd | 80 +++++++++++++++++ man/{motif_diffusion.Rd => motif_hazard.Rd} | 42 ++++----- 7 files changed, 317 insertions(+), 123 deletions(-) create mode 100644 man/motif_exposure.Rd rename man/{motif_diffusion.Rd => motif_hazard.Rd} (82%) diff --git a/R/measure_diffusion.R b/R/measure_diffusion.R index 0c55e4a..775a846 100644 --- a/R/measure_diffusion.R +++ b/R/measure_diffusion.R @@ -1,29 +1,29 @@ # net_diffusion #### #' Measures of network diffusion +#' @name measure_diffusion_net #' @description #' These functions allow measurement of various features of #' a diffusion process at the network level: #' -#' - `net_transmissibility()` measures the average transmissibility observed +#' - `net_by_transmissibility()` measures the average transmissibility observed #' in a diffusion simulation, or the number of new infections over #' the number of susceptible nodes. -#' - `net_recovery()` measures the average number of time steps +#' - `net_by_recovery()` measures the average number of time steps #' nodes remain infected once they become infected. -#' - `net_reproduction()` measures the observed reproductive number +#' - `net_by_reproduction()` measures the observed reproductive number #' in a diffusion simulation as the network's transmissibility over #' the network's average infection length. -#' - `net_immunity()` measures the proportion of nodes that would need +#' - `net_by_immunity()` measures the proportion of nodes that would need #' to be protected through vaccination, isolation, or recovery for herd immunity to be reached. #' #' @param .data Network data with nodal changes, #' as created by `play_diffusion()`, #' or a valid network diffusion model, #' as created by `as_diffusion()`. -#' @inheritParams measure_central_degree -#' @family measures +#' @template param_norm +#' @template net_measure #' @family diffusion -#' @name measure_diffusion_net #' @examples #' smeg <- generate_smallworld(15, 0.025) #' smeg_diff <- play_diffusion(smeg, recovery = 0.2) @@ -191,26 +191,26 @@ net_by_immunity <- function(.data, normalized = TRUE){ # net_infection #### #' Measures of network infection +#' @name measure_diffusion_infection #' @description #' These functions allow measurement of various features of #' a diffusion process at the network level: #' -#' - `net_infection_complete()` measures the number of time steps until +#' - `net_by_infection_complete()` measures the number of time steps until #' (the first instance of) complete infection. #' For diffusions that are not observed to complete, #' this function returns the value of `Inf` (infinity). #' This makes sure that at least ordinality is respected. -#' - `net_infection_total()` measures the proportion or total number of nodes +#' - `net_by_infection_total()` measures the proportion or total number of nodes #' that are infected/activated at some time by the end of the diffusion process. #' This includes nodes that subsequently recover. #' Where reinfection is possible, the proportion may be higher than 1. -#' - `net_infection_peak()` measures the number of time steps until the +#' - `net_by_infection_peak()` measures the number of time steps until the #' highest infection rate is observed. #' #' @inheritParams measure_diffusion_net -#' @family measures #' @family diffusion -#' @name measure_diffusion_infection +#' @template net_measure #' @rdname measure_diffusion_infection #' @examples @@ -265,24 +265,24 @@ net_by_infection_peak <- function(.data){ # node_diffusion #### #' Measures of nodes in a diffusion +#' @name measure_diffusion_node #' @description #' These functions allow measurement of various features of #' a diffusion process: #' -#' - `node_adoption_time()`: Measures the number of time steps until +#' - `node_by_adopt_time()`: Measures the number of time steps until #' nodes adopt/become infected -#' - `node_thresholds()`: Measures nodes' thresholds from the amount +#' - `node_by_adopt_threshold()`: Measures nodes' thresholds from the amount #' of exposure they had when they became infected -#' - `node_infection_length()`: Measures the average length nodes that become +#' - `node_by_infection_length()`: Measures the average length nodes that become #' infected remain infected in a compartmental model with recovery -#' - `node_exposure()`: Measures how many exposures nodes have to +#' - `node_by_exposure()`: Measures how many exposures nodes have to #' a given mark #' -#' @inheritParams mark_nodes -#' @inheritParams measure_diffusion_net -#' @family measures +#' @template param_data +#' @template param_norm #' @family diffusion -#' @name measure_diffusion_node +#' @template node_measure #' @examples #' smeg <- generate_smallworld(15, 0.025) #' smeg_diff <- play_diffusion(smeg, recovery = 0.2) @@ -295,14 +295,14 @@ NULL #' @rdname measure_diffusion_node #' @section Adoption time: -#' `node_adoption_time()` measures the time units it took +#' `node_by_adopt_time()` measures the time units it took #' until each node became infected. #' Note that an adoption time of 0 indicates that this was a seed node. #' @examples #' # To measure when nodes adopted a diffusion/were infected -#' (times <- node_by_adoption_time(smeg_diff)) +#' (times <- node_by_adopt_time(smeg_diff)) #' @export -node_by_adoption_time <- function(.data){ +node_by_adopt_time <- function(.data){ if(inherits(.data, "diff_model")){ net <- attr(.data, "network") @@ -348,7 +348,7 @@ node_by_adoption_time <- function(.data){ #' @param lag The number of time steps back upon which the thresholds are #' inferred. #' @section Thresholds: -#' `node_thresholds()` infers nodes' thresholds based on how much +#' `node_by_adopt_threshold()` infers nodes' thresholds based on how much #' exposure they had when they were infected. #' This inference is of course imperfect, #' especially where there is a sudden increase in exposure, @@ -364,9 +364,9 @@ node_by_adoption_time <- function(.data){ #' and works regardless of whether \eqn{w} is weighted or not. #' @examples #' # To infer nodes' thresholds -#' node_by_thresholds(smeg_diff) +#' node_by_adopt_threshold(smeg_diff) #' @export -node_by_thresholds <- function(.data, normalized = TRUE, lag = 1){ +node_by_adopt_threshold <- function(.data, normalized = TRUE, lag = 1){ if(inherits(.data, "diff_model")){ net <- attr(.data, "network") diff_model <- manynet::as_diffusion(.data) @@ -525,9 +525,9 @@ node_by_exposure <- function(.data, mark, time = 0){ make_node_measure(out, .data) } -# node_diffusion #### +# Diffusion membership #### -#' Membership of nodes in a diffusion +#' Memberships in a diffusion process #' @description #' `node_in_adopter()` classifies membership of nodes into diffusion categories #' by where on the distribution of adopters they fell. @@ -546,9 +546,8 @@ node_by_exposure <- function(.data, mark, time = 0){ #' - _Non-adopter_: those without an adoption time, #' i.e. never adopted #' -#' @inheritParams mark_nodes -#' @inheritParams measure_diffusion_net -#' @family measures +#' @template param_data +#' @template node_member #' @family diffusion #' @name member_diffusion #' @references @@ -567,7 +566,7 @@ NULL #' summary(adopts) #' @export node_in_adopter <- function(.data){ - toa <- node_by_adoption_time(.data) + toa <- node_by_adopt_time(.data) toa[is.infinite(toa)] <- NA avg <- mean(toa, na.rm = TRUE) sdv <- stats::sd(toa, na.rm = TRUE) diff --git a/man/measure_diffusion_infection.Rd b/man/measure_diffusion_infection.Rd index 43db7fb..ddd3322 100644 --- a/man/measure_diffusion_infection.Rd +++ b/man/measure_diffusion_infection.Rd @@ -19,24 +19,28 @@ as created by \code{play_diffusion()}, or a valid network diffusion model, as created by \code{as_diffusion()}.} -\item{normalized}{Logical scalar, whether the centrality scores are normalized. -Different denominators are used depending on whether the object is one-mode or two-mode, -the type of centrality, and other arguments.} +\item{normalized}{Logical scalar, whether scores are normalized. +Different denominators may be used depending on the measure, +whether the object is one-mode or two-mode, and other arguments. +By default TRUE.} +} +\value{ +A \code{network_measure} numeric score. } \description{ These functions allow measurement of various features of a diffusion process at the network level: \itemize{ -\item \code{net_infection_complete()} measures the number of time steps until +\item \code{net_by_infection_complete()} measures the number of time steps until (the first instance of) complete infection. For diffusions that are not observed to complete, this function returns the value of \code{Inf} (infinity). This makes sure that at least ordinality is respected. -\item \code{net_infection_total()} measures the proportion or total number of nodes +\item \code{net_by_infection_total()} measures the proportion or total number of nodes that are infected/activated at some time by the end of the diffusion process. This includes nodes that subsequently recover. Where reinfection is possible, the proportion may be higher than 1. -\item \code{net_infection_peak()} measures the number of time steps until the +\item \code{net_by_infection_peak()} measures the number of time steps until the highest infection rate is observed. } } @@ -48,32 +52,45 @@ highest infection rate is observed. net_by_infection_peak(smeg_diff) } \seealso{ +Other diffusion: +\code{\link{mark_diff}}, +\code{\link{measure_diffusion_net}}, +\code{\link{measure_diffusion_node}}, +\code{\link{member_diffusion}}, +\code{\link{motif_exposure}}, +\code{\link{motif_hazard}} + Other measures: -\code{\link{measure_assortativity}}, +\code{\link{measure_assort_net}}, +\code{\link{measure_assort_node}}, \code{\link{measure_breadth}}, +\code{\link{measure_broker_node}}, +\code{\link{measure_broker_tie}}, \code{\link{measure_brokerage}}, \code{\link{measure_central_between}}, \code{\link{measure_central_close}}, \code{\link{measure_central_degree}}, \code{\link{measure_central_eigen}}, +\code{\link{measure_centralisation_between}}, +\code{\link{measure_centralisation_close}}, +\code{\link{measure_centralisation_degree}}, +\code{\link{measure_centralisation_eigen}}, +\code{\link{measure_centralities_between}}, +\code{\link{measure_centralities_close}}, +\code{\link{measure_centralities_degree}}, +\code{\link{measure_centralities_eigen}}, \code{\link{measure_closure}}, +\code{\link{measure_closure_node}}, \code{\link{measure_cohesion}}, +\code{\link{measure_core}}, \code{\link{measure_diffusion_net}}, \code{\link{measure_diffusion_node}}, +\code{\link{measure_diverse_net}}, +\code{\link{measure_diverse_node}}, \code{\link{measure_features}}, \code{\link{measure_fragmentation}}, -\code{\link{measure_heterogeneity}}, \code{\link{measure_hierarchy}}, -\code{\link{measure_holes}}, -\code{\link{measure_periods}}, -\code{\link{member_diffusion}} - -Other diffusion: -\code{\link{mark_diff}}, -\code{\link{measure_diffusion_net}}, -\code{\link{measure_diffusion_node}}, -\code{\link{member_diffusion}}, -\code{\link{motif_diffusion}} +\code{\link{measure_periods}} } \concept{diffusion} \concept{measures} diff --git a/man/measure_diffusion_net.Rd b/man/measure_diffusion_net.Rd index 27e9039..c274efd 100644 --- a/man/measure_diffusion_net.Rd +++ b/man/measure_diffusion_net.Rd @@ -27,23 +27,27 @@ of the simulation, right censored values can be replaced by the number of steps. By default TRUE. Note that this will likely still underestimate recovery.} -\item{normalized}{Logical scalar, whether the centrality scores are normalized. -Different denominators are used depending on whether the object is one-mode or two-mode, -the type of centrality, and other arguments.} +\item{normalized}{Logical scalar, whether scores are normalized. +Different denominators may be used depending on the measure, +whether the object is one-mode or two-mode, and other arguments. +By default TRUE.} +} +\value{ +A \code{network_measure} numeric score. } \description{ These functions allow measurement of various features of a diffusion process at the network level: \itemize{ -\item \code{net_transmissibility()} measures the average transmissibility observed +\item \code{net_by_transmissibility()} measures the average transmissibility observed in a diffusion simulation, or the number of new infections over the number of susceptible nodes. -\item \code{net_recovery()} measures the average number of time steps +\item \code{net_by_recovery()} measures the average number of time steps nodes remain infected once they become infected. -\item \code{net_reproduction()} measures the observed reproductive number +\item \code{net_by_reproduction()} measures the observed reproductive number in a diffusion simulation as the network's transmissibility over the network's average infection length. -\item \code{net_immunity()} measures the proportion of nodes that would need +\item \code{net_by_immunity()} measures the proportion of nodes that would need to be protected through vaccination, isolation, or recovery for herd immunity to be reached. } } @@ -165,31 +169,44 @@ Garnett, G.P. 2005. } \seealso{ Other measures: -\code{\link{measure_assortativity}}, +\code{\link{measure_assort_net}}, +\code{\link{measure_assort_node}}, \code{\link{measure_breadth}}, +\code{\link{measure_broker_node}}, +\code{\link{measure_broker_tie}}, \code{\link{measure_brokerage}}, \code{\link{measure_central_between}}, \code{\link{measure_central_close}}, \code{\link{measure_central_degree}}, \code{\link{measure_central_eigen}}, +\code{\link{measure_centralisation_between}}, +\code{\link{measure_centralisation_close}}, +\code{\link{measure_centralisation_degree}}, +\code{\link{measure_centralisation_eigen}}, +\code{\link{measure_centralities_between}}, +\code{\link{measure_centralities_close}}, +\code{\link{measure_centralities_degree}}, +\code{\link{measure_centralities_eigen}}, \code{\link{measure_closure}}, +\code{\link{measure_closure_node}}, \code{\link{measure_cohesion}}, +\code{\link{measure_core}}, \code{\link{measure_diffusion_infection}}, \code{\link{measure_diffusion_node}}, +\code{\link{measure_diverse_net}}, +\code{\link{measure_diverse_node}}, \code{\link{measure_features}}, \code{\link{measure_fragmentation}}, -\code{\link{measure_heterogeneity}}, \code{\link{measure_hierarchy}}, -\code{\link{measure_holes}}, -\code{\link{measure_periods}}, -\code{\link{member_diffusion}} +\code{\link{measure_periods}} Other diffusion: \code{\link{mark_diff}}, \code{\link{measure_diffusion_infection}}, \code{\link{measure_diffusion_node}}, \code{\link{member_diffusion}}, -\code{\link{motif_diffusion}} +\code{\link{motif_exposure}}, +\code{\link{motif_hazard}} } \concept{diffusion} \concept{measures} diff --git a/man/measure_diffusion_node.Rd b/man/measure_diffusion_node.Rd index a4d5380..cc0d9a7 100644 --- a/man/measure_diffusion_node.Rd +++ b/man/measure_diffusion_node.Rd @@ -2,15 +2,15 @@ % Please edit documentation in R/measure_diffusion.R \name{measure_diffusion_node} \alias{measure_diffusion_node} -\alias{node_by_adoption_time} -\alias{node_by_thresholds} +\alias{node_by_adopt_time} +\alias{node_by_adopt_threshold} \alias{node_by_recovery} \alias{node_by_exposure} \title{Measures of nodes in a diffusion} \usage{ -node_by_adoption_time(.data) +node_by_adopt_time(.data) -node_by_thresholds(.data, normalized = TRUE, lag = 1) +node_by_adopt_threshold(.data, normalized = TRUE, lag = 1) node_by_recovery(.data) @@ -21,9 +21,10 @@ node_by_exposure(.data, mark, time = 0) For more information on the standard coercion possible, see \code{\link[manynet:manip_as]{manynet::as_tidygraph()}}.} -\item{normalized}{Logical scalar, whether the centrality scores are normalized. -Different denominators are used depending on whether the object is one-mode or two-mode, -the type of centrality, and other arguments.} +\item{normalized}{Logical scalar, whether scores are normalized. +Different denominators may be used depending on the measure, +whether the object is one-mode or two-mode, and other arguments. +By default TRUE.} \item{lag}{The number of time steps back upon which the thresholds are inferred.} @@ -35,30 +36,36 @@ the number of nodes in the network.} \item{time}{A time point until which infections/adoptions should be identified. By default \code{time = 0}.} } +\value{ +A \code{node_measure} numeric vector the length of the nodes in the network, +providing the scores for each node. +If the network is labelled, +then the scores will be labelled with the nodes' names. +} \description{ These functions allow measurement of various features of a diffusion process: \itemize{ -\item \code{node_adoption_time()}: Measures the number of time steps until +\item \code{node_by_adopt_time()}: Measures the number of time steps until nodes adopt/become infected -\item \code{node_thresholds()}: Measures nodes' thresholds from the amount +\item \code{node_by_adopt_threshold()}: Measures nodes' thresholds from the amount of exposure they had when they became infected -\item \code{node_infection_length()}: Measures the average length nodes that become +\item \code{node_by_infection_length()}: Measures the average length nodes that become infected remain infected in a compartmental model with recovery -\item \code{node_exposure()}: Measures how many exposures nodes have to +\item \code{node_by_exposure()}: Measures how many exposures nodes have to a given mark } } \section{Adoption time}{ -\code{node_adoption_time()} measures the time units it took +\code{node_by_adopt_time()} measures the time units it took until each node became infected. Note that an adoption time of 0 indicates that this was a seed node. } \section{Thresholds}{ -\code{node_thresholds()} infers nodes' thresholds based on how much +\code{node_by_adopt_threshold()} infers nodes' thresholds based on how much exposure they had when they were infected. This inference is of course imperfect, especially where there is a sudden increase in exposure, @@ -97,9 +104,9 @@ nodes exposure at \eqn{t = 0}. smeg_diff <- play_diffusion(smeg, recovery = 0.2) plot(smeg_diff) # To measure when nodes adopted a diffusion/were infected - (times <- node_by_adoption_time(smeg_diff)) + (times <- node_by_adopt_time(smeg_diff)) # To infer nodes' thresholds - node_by_thresholds(smeg_diff) + node_by_adopt_threshold(smeg_diff) # To measure how long each node remains infected for node_by_recovery(smeg_diff) # To measure how much exposure nodes have to a given mark @@ -114,32 +121,76 @@ Valente, Tom W. 1995. \emph{Network models of the diffusion of innovations} } } \seealso{ +Other diffusion: +\code{\link{mark_diff}}, +\code{\link{measure_diffusion_infection}}, +\code{\link{measure_diffusion_net}}, +\code{\link{member_diffusion}}, +\code{\link{motif_exposure}}, +\code{\link{motif_hazard}} + Other measures: -\code{\link{measure_assortativity}}, +\code{\link{measure_assort_net}}, +\code{\link{measure_assort_node}}, \code{\link{measure_breadth}}, +\code{\link{measure_broker_node}}, +\code{\link{measure_broker_tie}}, \code{\link{measure_brokerage}}, \code{\link{measure_central_between}}, \code{\link{measure_central_close}}, \code{\link{measure_central_degree}}, \code{\link{measure_central_eigen}}, +\code{\link{measure_centralisation_between}}, +\code{\link{measure_centralisation_close}}, +\code{\link{measure_centralisation_degree}}, +\code{\link{measure_centralisation_eigen}}, +\code{\link{measure_centralities_between}}, +\code{\link{measure_centralities_close}}, +\code{\link{measure_centralities_degree}}, +\code{\link{measure_centralities_eigen}}, \code{\link{measure_closure}}, +\code{\link{measure_closure_node}}, \code{\link{measure_cohesion}}, +\code{\link{measure_core}}, \code{\link{measure_diffusion_infection}}, \code{\link{measure_diffusion_net}}, +\code{\link{measure_diverse_net}}, +\code{\link{measure_diverse_node}}, \code{\link{measure_features}}, \code{\link{measure_fragmentation}}, -\code{\link{measure_heterogeneity}}, \code{\link{measure_hierarchy}}, -\code{\link{measure_holes}}, -\code{\link{measure_periods}}, -\code{\link{member_diffusion}} +\code{\link{measure_periods}} -Other diffusion: +Other nodal: +\code{\link{mark_core}}, +\code{\link{mark_degree}}, \code{\link{mark_diff}}, -\code{\link{measure_diffusion_infection}}, -\code{\link{measure_diffusion_net}}, +\code{\link{mark_nodes}}, +\code{\link{mark_select_node}}, +\code{\link{measure_assort_node}}, +\code{\link{measure_broker_node}}, +\code{\link{measure_brokerage}}, +\code{\link{measure_central_between}}, +\code{\link{measure_central_close}}, +\code{\link{measure_central_degree}}, +\code{\link{measure_central_eigen}}, +\code{\link{measure_closure_node}}, +\code{\link{measure_core}}, +\code{\link{measure_diverse_node}}, +\code{\link{member_brokerage}}, +\code{\link{member_cliques}}, +\code{\link{member_community}}, +\code{\link{member_community_hier}}, +\code{\link{member_community_non}}, +\code{\link{member_components}}, +\code{\link{member_core}}, \code{\link{member_diffusion}}, -\code{\link{motif_diffusion}} +\code{\link{member_equivalence}}, +\code{\link{motif_brokerage_node}}, +\code{\link{motif_exposure}}, +\code{\link{motif_node}}, +\code{\link{motif_path}} } \concept{diffusion} \concept{measures} +\concept{nodal} diff --git a/man/member_diffusion.Rd b/man/member_diffusion.Rd index d067505..026825a 100644 --- a/man/member_diffusion.Rd +++ b/man/member_diffusion.Rd @@ -3,7 +3,7 @@ \name{member_diffusion} \alias{member_diffusion} \alias{node_in_adopter} -\title{Membership of nodes in a diffusion} +\title{Memberships in a diffusion process} \usage{ node_in_adopter(.data) } @@ -12,6 +12,12 @@ node_in_adopter(.data) For more information on the standard coercion possible, see \code{\link[manynet:manip_as]{manynet::as_tidygraph()}}.} } +\value{ +A \code{node_member} character vector the length of the nodes in the network, +of group memberships "A", "B", etc for each node. +If the network is labelled, +then the assignments will be labelled with the nodes' names. +} \description{ \code{node_in_adopter()} classifies membership of nodes into diffusion categories by where on the distribution of adopters they fell. @@ -47,32 +53,54 @@ Valente, Tom W. 1995. } } \seealso{ -Other measures: -\code{\link{measure_assortativity}}, -\code{\link{measure_breadth}}, +Other memberships: +\code{\link{member_brokerage}}, +\code{\link{member_cliques}}, +\code{\link{member_community}}, +\code{\link{member_community_hier}}, +\code{\link{member_community_non}}, +\code{\link{member_components}}, +\code{\link{member_core}}, +\code{\link{member_equivalence}} + +Other nodal: +\code{\link{mark_core}}, +\code{\link{mark_degree}}, +\code{\link{mark_diff}}, +\code{\link{mark_nodes}}, +\code{\link{mark_select_node}}, +\code{\link{measure_assort_node}}, +\code{\link{measure_broker_node}}, \code{\link{measure_brokerage}}, \code{\link{measure_central_between}}, \code{\link{measure_central_close}}, \code{\link{measure_central_degree}}, \code{\link{measure_central_eigen}}, -\code{\link{measure_closure}}, -\code{\link{measure_cohesion}}, -\code{\link{measure_diffusion_infection}}, -\code{\link{measure_diffusion_net}}, +\code{\link{measure_closure_node}}, +\code{\link{measure_core}}, \code{\link{measure_diffusion_node}}, -\code{\link{measure_features}}, -\code{\link{measure_fragmentation}}, -\code{\link{measure_heterogeneity}}, -\code{\link{measure_hierarchy}}, -\code{\link{measure_holes}}, -\code{\link{measure_periods}} +\code{\link{measure_diverse_node}}, +\code{\link{member_brokerage}}, +\code{\link{member_cliques}}, +\code{\link{member_community}}, +\code{\link{member_community_hier}}, +\code{\link{member_community_non}}, +\code{\link{member_components}}, +\code{\link{member_core}}, +\code{\link{member_equivalence}}, +\code{\link{motif_brokerage_node}}, +\code{\link{motif_exposure}}, +\code{\link{motif_node}}, +\code{\link{motif_path}} Other diffusion: \code{\link{mark_diff}}, \code{\link{measure_diffusion_infection}}, \code{\link{measure_diffusion_net}}, \code{\link{measure_diffusion_node}}, -\code{\link{motif_diffusion}} +\code{\link{motif_exposure}}, +\code{\link{motif_hazard}} } \concept{diffusion} -\concept{measures} +\concept{memberships} +\concept{nodal} diff --git a/man/motif_exposure.Rd b/man/motif_exposure.Rd new file mode 100644 index 0000000..a753403 --- /dev/null +++ b/man/motif_exposure.Rd @@ -0,0 +1,80 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/motif_census.R +\name{motif_exposure} +\alias{motif_exposure} +\alias{node_x_exposure} +\title{Motifs of nodes exposure} +\usage{ +node_x_exposure(.data) +} +\arguments{ +\item{.data}{A network object of class \code{mnet}, \code{igraph}, \code{tbl_graph}, \code{network}, or similar. +For more information on the standard coercion possible, +see \code{\link[manynet:manip_as]{manynet::as_tidygraph()}}.} +} +\value{ +A \code{node_motif} tibble with one row for each node in the network and +a column for each motif type, +giving the count of each motif in which each node participates. +If the network is labelled, +then the node names will be in a column named \code{names}. +} +\description{ +\code{node_x_exposure()} produces a motif matrix of nodes' exposure to +infection/adoption by time step. +} +\examples{ +node_x_exposure(play_diffusion(create_tree(12))) +} +\seealso{ +Other diffusion: +\code{\link{mark_diff}}, +\code{\link{measure_diffusion_infection}}, +\code{\link{measure_diffusion_net}}, +\code{\link{measure_diffusion_node}}, +\code{\link{member_diffusion}}, +\code{\link{motif_hazard}} + +Other motifs: +\code{\link{motif_brokerage_net}}, +\code{\link{motif_brokerage_node}}, +\code{\link{motif_hazard}}, +\code{\link{motif_hierarchy}}, +\code{\link{motif_net}}, +\code{\link{motif_node}}, +\code{\link{motif_path}}, +\code{\link{motif_periods}} + +Other nodal: +\code{\link{mark_core}}, +\code{\link{mark_degree}}, +\code{\link{mark_diff}}, +\code{\link{mark_nodes}}, +\code{\link{mark_select_node}}, +\code{\link{measure_assort_node}}, +\code{\link{measure_broker_node}}, +\code{\link{measure_brokerage}}, +\code{\link{measure_central_between}}, +\code{\link{measure_central_close}}, +\code{\link{measure_central_degree}}, +\code{\link{measure_central_eigen}}, +\code{\link{measure_closure_node}}, +\code{\link{measure_core}}, +\code{\link{measure_diffusion_node}}, +\code{\link{measure_diverse_node}}, +\code{\link{member_brokerage}}, +\code{\link{member_cliques}}, +\code{\link{member_community}}, +\code{\link{member_community_hier}}, +\code{\link{member_community_non}}, +\code{\link{member_components}}, +\code{\link{member_core}}, +\code{\link{member_diffusion}}, +\code{\link{member_equivalence}}, +\code{\link{motif_brokerage_node}}, +\code{\link{motif_node}}, +\code{\link{motif_path}} +} +\concept{diffusion} +\concept{motifs} +\concept{nodal} diff --git a/man/motif_diffusion.Rd b/man/motif_hazard.Rd similarity index 82% rename from man/motif_diffusion.Rd rename to man/motif_hazard.Rd index 4a7541c..0981587 100644 --- a/man/motif_diffusion.Rd +++ b/man/motif_hazard.Rd @@ -1,16 +1,13 @@ % Generated by roxygen2: do not edit by hand % Please edit documentation in R/motif_census.R -\name{motif_diffusion} -\alias{motif_diffusion} -\alias{node_x_exposure} +\name{motif_hazard} +\alias{motif_hazard} \alias{net_x_hazard} -\title{Motifs of diffusion} +\title{Motifs of network hazard} \source{ \code{{netdiffuseR}} } \usage{ -node_x_exposure(.data) - net_x_hazard(.data) } \arguments{ @@ -18,17 +15,18 @@ net_x_hazard(.data) For more information on the standard coercion possible, see \code{\link[manynet:manip_as]{manynet::as_tidygraph()}}.} } +\value{ +A \code{network_motif} tibble with one row and a column for each motif type, +giving the count of each motif in the network. +} \description{ -\itemize{ -\item \code{net_by_hazard()} measures the hazard rate or instantaneous probability that +\code{net_x_hazard()} measures the hazard rate or instantaneous probability that nodes will adopt/become infected at that time. -\item \code{node_by_exposure()} produces a motif matrix of nodes' exposure to -infection/adoption by time step. -} } \section{Hazard rate}{ -The hazard rate is the instantaneous probability of adoption/infection at each time point (Allison 1984). +The hazard rate is the instantaneous probability of adoption/infection +at each time point (Allison 1984). In survival analysis, hazard rate is formally defined as: \deqn{% @@ -69,7 +67,6 @@ those that oscillate indicate variability in adoption behavior over time. } \examples{ -node_x_exposure(play_diffusion(create_tree(12))) # To calculate the hazard rates at each time point smeg <- generate_smallworld(15, 0.025) net_x_hazard(play_diffusion(smeg, transmissibility = 0.3)) @@ -88,18 +85,23 @@ Cambridge: MIT Press. } } \seealso{ -Other motifs: -\code{\link{motif_brokerage}}, -\code{\link{motif_hierarchy}}, -\code{\link{motif_net}}, -\code{\link{motif_node}} - Other diffusion: \code{\link{mark_diff}}, \code{\link{measure_diffusion_infection}}, \code{\link{measure_diffusion_net}}, \code{\link{measure_diffusion_node}}, -\code{\link{member_diffusion}} +\code{\link{member_diffusion}}, +\code{\link{motif_exposure}} + +Other motifs: +\code{\link{motif_brokerage_net}}, +\code{\link{motif_brokerage_node}}, +\code{\link{motif_exposure}}, +\code{\link{motif_hierarchy}}, +\code{\link{motif_net}}, +\code{\link{motif_node}}, +\code{\link{motif_path}}, +\code{\link{motif_periods}} } \concept{diffusion} \concept{motifs} From cc17982b6fe97e9ffed636f54e76b57b0b6cc9e6 Mon Sep 17 00:00:00 2001 From: James Hollway Date: Sat, 21 Mar 2026 18:29:46 +0100 Subject: [PATCH 22/35] Updated tests --- tests/testthat/test-measure_net.R | 4 ---- tests/testthat/test-measure_nodes.R | 2 +- tests/testthat/test-motif_net.R | 4 ++++ 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/testthat/test-measure_net.R b/tests/testthat/test-measure_net.R index 8ddb97c..894a48d 100644 --- a/tests/testthat/test-measure_net.R +++ b/tests/testthat/test-measure_net.R @@ -24,10 +24,6 @@ for(fn in names(net_meas)) { if(ob == "diffusion") expect_s3_class(net_meas[[fn]](data_objs[[ob]]), "network_measure") else succeed("Only used for diffusion objects") - } else if(grepl("correlation|change|stability", fn)){ - if(ob == "labelled") - expect_s3_class(net_meas[[fn]](data_objs[[ob]], data_objs[[ob]]), "network_measure") else - succeed("Only used for multi objects") } else { expect_s3_class(net_meas[[fn]](data_objs[[ob]]), "network_measure") } diff --git a/tests/testthat/test-measure_nodes.R b/tests/testthat/test-measure_nodes.R index f9b4082..45a8e95 100644 --- a/tests/testthat/test-measure_nodes.R +++ b/tests/testthat/test-measure_nodes.R @@ -8,7 +8,7 @@ for(fn in names(node_meas)) { if(ob == "attribute") expect_s3_class(node_meas[[fn]](data_objs[[ob]], "group"), "node_measure") else succeed("Only used for attribute objects") - } else if(grepl("adoption|threshold|recovery|exposure",fn)){ + } else if(grepl("adopt|recovery|exposure",fn)){ if(ob == "diffusion") expect_s3_class(node_meas[[fn]](data_objs[[ob]]), "node_measure") else succeed("Only used for diffusion objects") diff --git a/tests/testthat/test-motif_net.R b/tests/testthat/test-motif_net.R index 715ffc3..cac986f 100644 --- a/tests/testthat/test-motif_net.R +++ b/tests/testthat/test-motif_net.R @@ -8,6 +8,10 @@ for(fn in names(net_motifs)) { if(ob == "attribute") expect_s3_class(net_motifs[[fn]](data_objs[[ob]], "group"), "network_motif") else succeed("Only used for attribute objects") + } else if(grepl("correlation|change|stability", fn)){ + if(ob == "labelled") + expect_s3_class(net_motifs[[fn]](data_objs[[ob]], data_objs[[ob]]), "network_motif") else + succeed("Only used for multi objects") } else { expect_s3_class(net_motifs[[fn]](data_objs[[ob]]), "network_motif") } From 6e19bc1a0c417d948b24c687907439120d17c362 Mon Sep 17 00:00:00 2001 From: James Hollway Date: Sat, 21 Mar 2026 18:29:57 +0100 Subject: [PATCH 23/35] Updated pkgdown --- pkgdown/_pkgdown.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/pkgdown/_pkgdown.yml b/pkgdown/_pkgdown.yml index ec08648..fb40760 100644 --- a/pkgdown/_pkgdown.yml +++ b/pkgdown/_pkgdown.yml @@ -64,18 +64,18 @@ reference: - subtitle: "Centrality" contents: - starts_with("measure_central") - - measure_holes - - measure_brokerage + - starts_with("measure_broker") - measure_hierarchy - subtitle: "Cohesion" contents: - measure_cohesion - - measure_closure + - starts_with("measure_closure") - measure_features - - measure_heterogeneity - - measure_assortativity - measure_fragmentation + - starts_with("measure_assort") + - starts_with("measure_diverse") - measure_breadth + - measure_core - subtitle: "Dynamics" contents: - measure_periods @@ -99,5 +99,5 @@ reference: - title: "Methods" desc: "Methods used in other functions but documented here:" contents: - - starts_with("model_") + - starts_with("method_") From 8ff7e4c550e35650302d5906e4b212e7644aeee2 Mon Sep 17 00:00:00 2001 From: James Hollway Date: Sat, 21 Mar 2026 18:30:16 +0100 Subject: [PATCH 24/35] Updated namespace --- .Rbuildignore | 1 + NAMESPACE | 11 ++++++----- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/.Rbuildignore b/.Rbuildignore index b80fbe7..cf845c5 100644 --- a/.Rbuildignore +++ b/.Rbuildignore @@ -1,5 +1,6 @@ ^CODE_OF_CONDUCT\.md$ ^LICENSE\.md$ +man-roxygen ^.*\.Rproj$ ^\.Rproj\.user$ ^working$ diff --git a/NAMESPACE b/NAMESPACE index 04cd795..8f0fc30 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -5,20 +5,19 @@ export(cluster_concor) export(cluster_cosine) export(cluster_hierarchical) export(k_elbow) +export(k_gap) export(k_silhouette) export(k_strict) export(net_by_adhesion) export(net_by_assortativity) export(net_by_balance) export(net_by_betweenness) -export(net_by_change) export(net_by_closeness) export(net_by_cohesion) export(net_by_components) export(net_by_congruency) export(net_by_connectedness) export(net_by_core) -export(net_by_correlation) export(net_by_degree) export(net_by_density) export(net_by_diameter) @@ -48,7 +47,6 @@ export(net_by_richness) export(net_by_scalefree) export(net_by_smallworld) export(net_by_spatial) -export(net_by_stability) export(net_by_strength) export(net_by_toughness) export(net_by_transitivity) @@ -56,13 +54,17 @@ export(net_by_transmissibility) export(net_by_upperbound) export(net_by_waves) export(net_x_brokerage) +export(net_x_change) +export(net_x_correlation) export(net_x_dyad) export(net_x_hazard) export(net_x_hierarchy) export(net_x_mixed) +export(net_x_stability) export(net_x_tetrad) export(net_x_triad) -export(node_by_adoption_time) +export(node_by_adopt_threshold) +export(node_by_adopt_time) export(node_by_alpha) export(node_by_authority) export(node_by_betweenness) @@ -107,7 +109,6 @@ export(node_by_redundancy) export(node_by_richness) export(node_by_stress) export(node_by_subgraph) -export(node_by_thresholds) export(node_by_transitivity) export(node_by_vitality) export(node_in_adopter) From bda410539984c2dce91a9a539f5118471f54dda2 Mon Sep 17 00:00:00 2001 From: James Hollway Date: Sat, 21 Mar 2026 18:31:33 +0100 Subject: [PATCH 25/35] Updated README --- README.Rmd | 5 ++-- README.md | 87 +++++++++++++++++++++++++++--------------------------- 2 files changed, 45 insertions(+), 47 deletions(-) diff --git a/README.Rmd b/README.Rmd index 8134e15..de9980c 100644 --- a/README.Rmd +++ b/README.Rmd @@ -132,11 +132,10 @@ For example, you might want to know about: - _Centrality_: `r list_functions("degree|betweenness|closeness|eigenvector")` - _Cohesion_: `r list_functions("density|reciprocity|transitivity|equivalency|congruency")` - _Hierarchy_: `r list_functions("hierarchy|connectedness|upper|efficiency|reciprocity")` -- _Innovation_: `r list_functions("hole|redundancy|constraint|effsize")` -- _Diversity_: `r list_functions("diversity|phily|richness|assort")` - _Topology_: `r list_functions("core|factions|modularity|smallworld|balance|richclub")` - _Resilience_: `r list_functions("cutpoint|bridge|hesion|articul")` -- _Brokerage_: `r list_functions("broke")` +- _Brokerage_: `r list_functions("broke|hole|redundancy|constraint|effsize")` +- _Diversity_: `r list_functions("diversity|phily|richness|assort")` - _Diffusion_: `r list_functions("adopt|infect|expos")` ## Installation diff --git a/README.md b/README.md index d33818f..78c2576 100644 --- a/README.md +++ b/README.md @@ -85,39 +85,38 @@ maximum or minimum, respectively, node or tie according to some measure network, node, and tie level. These include: - `net_by_adhesion()`, `net_by_assortativity()`, `net_by_balance()`, - `net_by_betweenness()`, `net_by_change()`, `net_by_closeness()`, - `net_by_cohesion()`, `net_by_components()`, `net_by_congruency()`, - `net_by_connectedness()`, `net_by_core()`, `net_by_correlation()`, - `net_by_degree()`, `net_by_density()`, `net_by_diameter()`, - `net_by_diversity()`, `net_by_efficiency()`, `net_by_eigenvector()`, - `net_by_equivalency()`, `net_by_factions()`, `net_by_harmonic()`, - `net_by_heterophily()`, `net_by_homophily()`, `net_by_immunity()`, - `net_by_indegree()`, `net_by_independence()`, - `net_by_infection_complete()`, `net_by_infection_peak()`, - `net_by_infection_total()`, `net_by_length()`, `net_by_modularity()`, - `net_by_outdegree()`, `net_by_reach()`, `net_by_reciprocity()`, - `net_by_recovery()`, `net_by_reproduction()`, `net_by_richclub()`, - `net_by_richness()`, `net_by_scalefree()`, `net_by_smallworld()`, - `net_by_spatial()`, `net_by_stability()`, `net_by_strength()`, - `net_by_toughness()`, `net_by_transitivity()`, + `net_by_betweenness()`, `net_by_closeness()`, `net_by_cohesion()`, + `net_by_components()`, `net_by_congruency()`, + `net_by_connectedness()`, `net_by_core()`, `net_by_degree()`, + `net_by_density()`, `net_by_diameter()`, `net_by_diversity()`, + `net_by_efficiency()`, `net_by_eigenvector()`, `net_by_equivalency()`, + `net_by_factions()`, `net_by_harmonic()`, `net_by_heterophily()`, + `net_by_homophily()`, `net_by_immunity()`, `net_by_indegree()`, + `net_by_independence()`, `net_by_infection_complete()`, + `net_by_infection_peak()`, `net_by_infection_total()`, + `net_by_length()`, `net_by_modularity()`, `net_by_outdegree()`, + `net_by_reach()`, `net_by_reciprocity()`, `net_by_recovery()`, + `net_by_reproduction()`, `net_by_richclub()`, `net_by_richness()`, + `net_by_scalefree()`, `net_by_smallworld()`, `net_by_spatial()`, + `net_by_strength()`, `net_by_toughness()`, `net_by_transitivity()`, `net_by_transmissibility()`, `net_by_upperbound()`, `net_by_waves()`, - `node_by_adoption_time()`, `node_by_alpha()`, `node_by_authority()`, - `node_by_betweenness()`, `node_by_bridges()`, - `node_by_brokering_activity()`, `node_by_brokering_exclusivity()`, - `node_by_closeness()`, `node_by_constraint()`, `node_by_coreness()`, - `node_by_deg()`, `node_by_degree()`, `node_by_distance()`, - `node_by_diversity()`, `node_by_eccentricity()`, - `node_by_efficiency()`, `node_by_effsize()`, `node_by_eigenvector()`, - `node_by_equivalency()`, `node_by_exposure()`, `node_by_flow()`, - `node_by_harmonic()`, `node_by_heterophily()`, `node_by_hierarchy()`, - `node_by_homophily()`, `node_by_hub()`, `node_by_indegree()`, - `node_by_induced()`, `node_by_information()`, `node_by_kcoreness()`, - `node_by_leverage()`, `node_by_multidegree()`, - `node_by_neighbours_degree()`, `node_by_outdegree()`, - `node_by_pagerank()`, `node_by_posneg()`, `node_by_power()`, - `node_by_randomwalk()`, `node_by_reach()`, `node_by_reciprocity()`, - `node_by_recovery()`, `node_by_redundancy()`, `node_by_richness()`, - `node_by_stress()`, `node_by_subgraph()`, `node_by_thresholds()`, + `node_by_adopt_threshold()`, `node_by_adopt_time()`, + `node_by_alpha()`, `node_by_authority()`, `node_by_betweenness()`, + `node_by_bridges()`, `node_by_brokering_activity()`, + `node_by_brokering_exclusivity()`, `node_by_closeness()`, + `node_by_constraint()`, `node_by_coreness()`, `node_by_deg()`, + `node_by_degree()`, `node_by_distance()`, `node_by_diversity()`, + `node_by_eccentricity()`, `node_by_efficiency()`, `node_by_effsize()`, + `node_by_eigenvector()`, `node_by_equivalency()`, + `node_by_exposure()`, `node_by_flow()`, `node_by_harmonic()`, + `node_by_heterophily()`, `node_by_hierarchy()`, `node_by_homophily()`, + `node_by_hub()`, `node_by_indegree()`, `node_by_induced()`, + `node_by_information()`, `node_by_kcoreness()`, `node_by_leverage()`, + `node_by_multidegree()`, `node_by_neighbours_degree()`, + `node_by_outdegree()`, `node_by_pagerank()`, `node_by_posneg()`, + `node_by_power()`, `node_by_randomwalk()`, `node_by_reach()`, + `node_by_reciprocity()`, `node_by_recovery()`, `node_by_redundancy()`, + `node_by_richness()`, `node_by_stress()`, `node_by_subgraph()`, `node_by_transitivity()`, `node_by_vitality()`, `tie_by_betweenness()`, `tie_by_closeness()`, `tie_by_cohesion()`, `tie_by_degree()`, `tie_by_eigenvector()` @@ -166,8 +165,9 @@ component and core-periphery partitioning algorithms. `{netrics}`‘s `*_x_*()` functions tabulate nodes’ and networks’ frequency in various motifs. These include: -- `net_x_brokerage()`, `net_x_dyad()`, `net_x_hazard()`, - `net_x_hierarchy()`, `net_x_mixed()`, `net_x_tetrad()`, +- `net_x_brokerage()`, `net_x_change()`, `net_x_correlation()`, + `net_x_dyad()`, `net_x_hazard()`, `net_x_hierarchy()`, + `net_x_mixed()`, `net_x_stability()`, `net_x_tetrad()`, `net_x_triad()`, `node_x_brokerage()`, `node_x_dyad()`, `node_x_exposure()`, `node_x_path()`, `node_x_tetrad()`, `node_x_tie()`, `node_x_triad()` @@ -193,12 +193,6 @@ about: - *Hierarchy*: `net_by_connectedness()`, `net_by_efficiency()`, `net_by_reciprocity()`, `net_by_upperbound()`, `net_x_hierarchy()`, `node_by_efficiency()`, `node_by_hierarchy()`, `node_by_reciprocity()` -- *Innovation*: `node_by_constraint()`, `node_by_effsize()`, - `node_by_redundancy()` -- *Diversity*: `net_by_assortativity()`, `net_by_diversity()`, - `net_by_heterophily()`, `net_by_homophily()`, `net_by_richness()`, - `node_by_diversity()`, `node_by_heterophily()`, `node_by_homophily()`, - `node_by_richness()` - *Topology*: `net_by_balance()`, `net_by_core()`, `net_by_factions()`, `net_by_modularity()`, `net_by_richclub()`, `net_by_smallworld()`, `node_by_coreness()`, `node_by_kcoreness()`, `node_in_core()`, @@ -207,12 +201,17 @@ about: `node_by_bridges()`, `node_is_cutpoint()`, `tie_by_cohesion()`, `tie_is_bridge()` - *Brokerage*: `net_x_brokerage()`, `node_by_brokering_activity()`, - `node_by_brokering_exclusivity()`, `node_in_brokering()`, + `node_by_brokering_exclusivity()`, `node_by_constraint()`, + `node_by_effsize()`, `node_by_redundancy()`, `node_in_brokering()`, `node_x_brokerage()` +- *Diversity*: `net_by_assortativity()`, `net_by_diversity()`, + `net_by_heterophily()`, `net_by_homophily()`, `net_by_richness()`, + `node_by_diversity()`, `node_by_heterophily()`, `node_by_homophily()`, + `node_by_richness()` - *Diffusion*: `net_by_infection_complete()`, `net_by_infection_peak()`, - `net_by_infection_total()`, `node_by_adoption_time()`, - `node_by_exposure()`, `node_in_adopter()`, `node_is_exposed()`, - `node_is_infected()`, `node_x_exposure()` + `net_by_infection_total()`, `node_by_adopt_threshold()`, + `node_by_adopt_time()`, `node_by_exposure()`, `node_in_adopter()`, + `node_is_exposed()`, `node_is_infected()`, `node_x_exposure()` ## Installation From 980b4b106ff8b97cf5c18f89b0bae880cf092b64 Mon Sep 17 00:00:00 2001 From: James Hollway Date: Sat, 21 Mar 2026 18:31:42 +0100 Subject: [PATCH 26/35] #minor bump --- DESCRIPTION | 4 ++-- cran-comments.md | 9 ++++----- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/DESCRIPTION b/DESCRIPTION index aa64097..8006999 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,7 +1,7 @@ Package: netrics Title: Many Ways to Measure and Classify Membership for Networks, Nodes, and Ties -Version: 0.1.1 -Date: 2026-03-19 +Version: 0.2.0 +Date: 2026-03-21 Description: Many tools for calculating network, node, or tie marks, measures, motifs and memberships of many different types of networks. Marks identify structural positions, measures quantify network properties, diff --git a/cran-comments.md b/cran-comments.md index d90f044..b5e6064 100644 --- a/cran-comments.md +++ b/cran-comments.md @@ -9,8 +9,7 @@ 0 errors | 0 warnings | 0 notes -- This package is ready for submission to CRAN. -The check results are clean, with no errors, warnings, or notes across all tested environments. -Note that there are some conflicts with manynet functions, -but these are not causing any issues with the package itself and -will be resolved by removing them from manynet once netrics is available on CRAN. +- There are no references describing all methods in this package, +but the documentation files for each set of functions are complete and include examples. +- The use of cat() in one function has been avoided. +- All user-facing functions now have return values specified in their documentation. From 26ccde2222238bc4a87046a7bdd3c5f9767eb938 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 21 Mar 2026 17:32:53 +0000 Subject: [PATCH 27/35] Initial plan From 07d49b59e60cf84cde902362b1f8b478b4589e7d Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 21 Mar 2026 17:34:03 +0000 Subject: [PATCH 28/35] Fill in NEWS.md for v0.2.0 Co-authored-by: jhollway <5595229+jhollway@users.noreply.github.com> Agent-Logs-Url: https://github.com/stocnet/netrics/sessions/884854c5-d15b-40c2-9e84-62c1fbba2040 --- NEWS.md | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/NEWS.md b/NEWS.md index 5c38977..2afed8b 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,3 +1,39 @@ +# netrics 0.2.0 + +## Renaming + +- `node_adoption_time()` renamed to `node_by_adopt_time()` and + `node_thresholds()` renamed to `node_by_adopt_threshold()` for naming + consistency. +- Periodwise change functions (`node_x_period()`, etc.) reclassified as motifs + rather than measures. +- `model_k()` renamed to `method_k()` and related cluster-selection utilities + renamed for clarity. + +## New features + +- Added gap method for cluster *k*-selection in `method_k()`. +- `node_in_community()` is now its own function, separated from the hierarchical + and non-hierarchical community-detection algorithms. +- Centralisation scripts split into separate files per measure type + (betweenness, closeness, degree, eigenvector) for easier maintenance. +- New roxygen2 parameter templates added (`param_attr`, `param_data`, + `param_dir`, `param_memb`, `param_motf`, `param_norm`, `param_select`) and + net/node/tie-level templates (`net_measure`, `net_motif`, `node_mark`, + `node_measure`, `node_member`, `node_motif`, `tie_mark`, `tie_measure`) for + consistent function documentation. + +## Documentation + +- Core documentation split into separate mark, measure, and member pages. +- Brokerage, diversity/assortativity, cohesion, closure, cliques, components, + features, and hierarchy documentation updated and separated by level. +- Defunct function documentation updated. + +## Bug fixes + +- Fixed startup messages. + # netrics 0.1.0 ## Release notes From 8b19e208e7b21d81d59789814dabea0dd29950ac Mon Sep 17 00:00:00 2001 From: James Hollway Date: Sat, 21 Mar 2026 20:14:14 +0100 Subject: [PATCH 29/35] Updated NEWS --- NEWS.md | 48 +++++++++++++++++++++++++----------------------- 1 file changed, 25 insertions(+), 23 deletions(-) diff --git a/NEWS.md b/NEWS.md index 2afed8b..a7012f0 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,38 +1,40 @@ # netrics 0.2.0 -## Renaming - -- `node_adoption_time()` renamed to `node_by_adopt_time()` and - `node_thresholds()` renamed to `node_by_adopt_threshold()` for naming - consistency. -- Periodwise change functions (`node_x_period()`, etc.) reclassified as motifs - rather than measures. -- `model_k()` renamed to `method_k()` and related cluster-selection utilities - renamed for clarity. - -## New features +## Package -- Added gap method for cluster *k*-selection in `method_k()`. -- `node_in_community()` is now its own function, separated from the hierarchical - and non-hierarchical community-detection algorithms. -- Centralisation scripts split into separate files per measure type - (betweenness, closeness, degree, eigenvector) for easier maintenance. -- New roxygen2 parameter templates added (`param_attr`, `param_data`, +- Added roxygen2 parameter templates (`param_attr`, `param_data`, `param_dir`, `param_memb`, `param_motf`, `param_norm`, `param_select`) and net/node/tie-level templates (`net_measure`, `net_motif`, `node_mark`, `node_measure`, `node_member`, `node_motif`, `tie_mark`, `tie_measure`) for consistent function documentation. +- Fixed startup messages. + +## Measuring + +- Renamed `node_adoption_time()` to `node_by_adopt_time()` +- Renamed`node_thresholds()` to `node_by_adopt_threshold()` +- Separated centralisation scripts into different files per measure type + (betweenness, closeness, degree, eigenvector) for easier maintenance, + and into different documentation per level (node, tie) for better organization. +- Updated and separated brokerage, diversity/assortativity, cohesion, closure, + cliques, components, features, and hierarchy documentation by level. -## Documentation +## Members +- Separated `node_in_community()` documentation from the hierarchical + and non-hierarchical community-detection algorithms. - Core documentation split into separate mark, measure, and member pages. -- Brokerage, diversity/assortativity, cohesion, closure, cliques, components, - features, and hierarchy documentation updated and separated by level. -- Defunct function documentation updated. -## Bug fixes +## Motifs -- Fixed startup messages. +- Renamed `net_by_change()` to `net_x_change()` and related functions to reflect their motif (subgraph-counting) nature. +- Renamed + +## Methods + +- Added gap method for cluster *k*-selection in `method_k()`. +- Renamed `model_k()` to `method_k()` and related cluster-selection utilities + renamed for clarity. # netrics 0.1.0 From 588991e0360d075121b7cfadeaf7dc5e41f8090f Mon Sep 17 00:00:00 2001 From: James Hollway Date: Sat, 21 Mar 2026 20:14:41 +0100 Subject: [PATCH 30/35] Fixed documentation issues --- R/netrics-defunct.R | 2 +- man-roxygen/net_motif.R | 4 +++- man-roxygen/node_mark.R | 1 - man-roxygen/node_motif.R | 3 ++- man/defunct.Rd | 2 +- man/motif_brokerage_net.Rd | 4 +++- man/motif_brokerage_node.Rd | 3 ++- man/motif_exposure.Rd | 3 ++- man/motif_hazard.Rd | 4 +++- man/motif_hierarchy.Rd | 4 +++- man/motif_net.Rd | 4 +++- man/motif_node.Rd | 3 ++- man/motif_path.Rd | 3 ++- man/motif_periods.Rd | 4 +++- 14 files changed, 30 insertions(+), 14 deletions(-) diff --git a/R/netrics-defunct.R b/R/netrics-defunct.R index aae724b..06566b3 100644 --- a/R/netrics-defunct.R +++ b/R/netrics-defunct.R @@ -10,7 +10,7 @@ #' wherever possible and update your scripts accordingly. #' @name defunct #' @keywords internal -#' @returns Results as expected, +#' @returns Results as expected #' along with a warning to use new function naming in the future. NULL diff --git a/man-roxygen/net_motif.R b/man-roxygen/net_motif.R index acf94b4..7daa161 100644 --- a/man-roxygen/net_motif.R +++ b/man-roxygen/net_motif.R @@ -1,4 +1,6 @@ #' @family motifs #' @returns -#' A `network_motif` tibble with one row and a column for each motif type, +#' A `network_motif` named numeric vector or sometimes a data frame with +#' one row and a column for each motif type, #' giving the count of each motif in the network. +#' This is printed as a tibble to avoid greedy printing of long vectors. diff --git a/man-roxygen/node_mark.R b/man-roxygen/node_mark.R index 5741472..056ac28 100644 --- a/man-roxygen/node_mark.R +++ b/man-roxygen/node_mark.R @@ -1,4 +1,3 @@ -#' @template data #' @family marks #' @family nodal #' @returns diff --git a/man-roxygen/node_motif.R b/man-roxygen/node_motif.R index 9a27941..942f693 100644 --- a/man-roxygen/node_motif.R +++ b/man-roxygen/node_motif.R @@ -1,8 +1,9 @@ #' @family motifs #' @family nodal #' @returns -#' A `node_motif` tibble with one row for each node in the network and +#' A `node_motif` matrix with one row for each node in the network and #' a column for each motif type, #' giving the count of each motif in which each node participates. +#' It is printed as a tibble, however, to avoid greedy printing. #' If the network is labelled, #' then the node names will be in a column named `names`. diff --git a/man/defunct.Rd b/man/defunct.Rd index 72502da..7add876 100644 --- a/man/defunct.Rd +++ b/man/defunct.Rd @@ -4,7 +4,7 @@ \alias{defunct} \title{Functions that have been renamed, superseded, or are no longer working} \value{ -Results as expected, +Results as expected along with a warning to use new function naming in the future. } \description{ diff --git a/man/motif_brokerage_net.Rd b/man/motif_brokerage_net.Rd index 886bc0c..2bc9858 100644 --- a/man/motif_brokerage_net.Rd +++ b/man/motif_brokerage_net.Rd @@ -23,8 +23,10 @@ into a \emph{z}-score indicating how many standard deviations above or below the average the score lies.} } \value{ -A \code{network_motif} tibble with one row and a column for each motif type, +A \code{network_motif} named numeric vector or sometimes a data frame with +one row and a column for each motif type, giving the count of each motif in the network. +This is printed as a tibble to avoid greedy printing of long vectors. } \description{ \code{net_x_brokerage()} returns the Gould-Fernandez brokerage diff --git a/man/motif_brokerage_node.Rd b/man/motif_brokerage_node.Rd index 1de038d..a34a50d 100644 --- a/man/motif_brokerage_node.Rd +++ b/man/motif_brokerage_node.Rd @@ -23,9 +23,10 @@ into a \emph{z}-score indicating how many standard deviations above or below the average the score lies.} } \value{ -A \code{node_motif} tibble with one row for each node in the network and +A \code{node_motif} matrix with one row for each node in the network and a column for each motif type, giving the count of each motif in which each node participates. +It is printed as a tibble, however, to avoid greedy printing. If the network is labelled, then the node names will be in a column named \code{names}. } diff --git a/man/motif_exposure.Rd b/man/motif_exposure.Rd index a753403..57e48f2 100644 --- a/man/motif_exposure.Rd +++ b/man/motif_exposure.Rd @@ -13,9 +13,10 @@ For more information on the standard coercion possible, see \code{\link[manynet:manip_as]{manynet::as_tidygraph()}}.} } \value{ -A \code{node_motif} tibble with one row for each node in the network and +A \code{node_motif} matrix with one row for each node in the network and a column for each motif type, giving the count of each motif in which each node participates. +It is printed as a tibble, however, to avoid greedy printing. If the network is labelled, then the node names will be in a column named \code{names}. } diff --git a/man/motif_hazard.Rd b/man/motif_hazard.Rd index 0981587..f30d7b1 100644 --- a/man/motif_hazard.Rd +++ b/man/motif_hazard.Rd @@ -16,8 +16,10 @@ For more information on the standard coercion possible, see \code{\link[manynet:manip_as]{manynet::as_tidygraph()}}.} } \value{ -A \code{network_motif} tibble with one row and a column for each motif type, +A \code{network_motif} named numeric vector or sometimes a data frame with +one row and a column for each motif type, giving the count of each motif in the network. +This is printed as a tibble to avoid greedy printing of long vectors. } \description{ \code{net_x_hazard()} measures the hazard rate or instantaneous probability that diff --git a/man/motif_hierarchy.Rd b/man/motif_hierarchy.Rd index 0664ca2..a6db1bd 100644 --- a/man/motif_hierarchy.Rd +++ b/man/motif_hierarchy.Rd @@ -13,8 +13,10 @@ For more information on the standard coercion possible, see \code{\link[manynet:manip_as]{manynet::as_tidygraph()}}.} } \value{ -A \code{network_motif} tibble with one row and a column for each motif type, +A \code{network_motif} named numeric vector or sometimes a data frame with +one row and a column for each motif type, giving the count of each motif in the network. +This is printed as a tibble to avoid greedy printing of long vectors. } \description{ \code{net_x_hierarchy()} collects the measures of hierarchy into a single motif, diff --git a/man/motif_net.Rd b/man/motif_net.Rd index 0e3317e..a4a9b90 100644 --- a/man/motif_net.Rd +++ b/man/motif_net.Rd @@ -27,8 +27,10 @@ see \code{\link[manynet:manip_as]{manynet::as_tidygraph()}}.} \item{object2}{A second, two-mode network object.} } \value{ -A \code{network_motif} tibble with one row and a column for each motif type, +A \code{network_motif} named numeric vector or sometimes a data frame with +one row and a column for each motif type, giving the count of each motif in the network. +This is printed as a tibble to avoid greedy printing of long vectors. } \description{ These functions include ways to take a census of the graphlets diff --git a/man/motif_node.Rd b/man/motif_node.Rd index 9633109..f97bf74 100644 --- a/man/motif_node.Rd +++ b/man/motif_node.Rd @@ -19,9 +19,10 @@ For more information on the standard coercion possible, see \code{\link[manynet:manip_as]{manynet::as_tidygraph()}}.} } \value{ -A \code{node_motif} tibble with one row for each node in the network and +A \code{node_motif} matrix with one row for each node in the network and a column for each motif type, giving the count of each motif in which each node participates. +It is printed as a tibble, however, to avoid greedy printing. If the network is labelled, then the node names will be in a column named \code{names}. } diff --git a/man/motif_path.Rd b/man/motif_path.Rd index 3a1ee1b..a73e560 100644 --- a/man/motif_path.Rd +++ b/man/motif_path.Rd @@ -16,9 +16,10 @@ For more information on the standard coercion possible, see \code{\link[manynet:manip_as]{manynet::as_tidygraph()}}.} } \value{ -A \code{node_motif} tibble with one row for each node in the network and +A \code{node_motif} matrix with one row for each node in the network and a column for each motif type, giving the count of each motif in which each node participates. +It is printed as a tibble, however, to avoid greedy printing. If the network is labelled, then the node names will be in a column named \code{names}. } diff --git a/man/motif_periods.Rd b/man/motif_periods.Rd index 16db108..f3e6b01 100644 --- a/man/motif_periods.Rd +++ b/man/motif_periods.Rd @@ -21,8 +21,10 @@ see \code{\link[manynet:manip_as]{manynet::as_tidygraph()}}.} \item{object2}{A network object.} } \value{ -A \code{network_motif} tibble with one row and a column for each motif type, +A \code{network_motif} named numeric vector or sometimes a data frame with +one row and a column for each motif type, giving the count of each motif in the network. +This is printed as a tibble to avoid greedy printing of long vectors. } \description{ These functions measure certain topological features of networks: From 4c28aa94a93b1453133221c1a3d69989f7d911dd Mon Sep 17 00:00:00 2001 From: James Hollway Date: Sat, 21 Mar 2026 20:15:04 +0100 Subject: [PATCH 31/35] Dropped ks test for power law fit --- R/measure_features.R | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/R/measure_features.R b/R/measure_features.R index 608d6fc..0740305 100644 --- a/R/measure_features.R +++ b/R/measure_features.R @@ -342,12 +342,9 @@ net_by_smallworld <- function(.data, net_by_scalefree <- function(.data){ .data <- manynet::expect_nodes(.data) out <- igraph::fit_power_law(node_by_deg(.data)) - if (!"KS.p" %in% names(out)) out$KS.p <- stats::ks.test(seq(0, 1 - out$KS.stat, - length.out = manynet::net_nodes(.data)), - "punif")$p.value - if(out$KS.p < 0.05) - manynet::snet_info("Note: Kolgomorov-Smirnov test that data could have been drawn", - "from a power-law distribution rejected.") + if ("KS.p" %in% names(out) && !is.null(out$KS.p) && !is.na(out$KS.p) && out$KS.p < 0.05) + manynet::snet_info("Note: Kolmogorov-Smirnov test that data could have been drawn", + "from a power-law distribution rejected.") make_network_measure(out$alpha, .data, call = deparse(sys.call())) } From 56fae7991d316542eb04f2d44769949d192f2399 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 21 Mar 2026 19:13:43 +0000 Subject: [PATCH 32/35] Initial plan From 24b367b73caea2889fe1ea5c63a2393767b47bc1 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 21 Mar 2026 19:17:39 +0000 Subject: [PATCH 33/35] Resolve membership to accept string attribute name or categorical vector Co-authored-by: jhollway <5595229+jhollway@users.noreply.github.com> Agent-Logs-Url: https://github.com/stocnet/netrics/sessions/cd56c0c0-bec1-4ac8-97a7-c63ab078b73c --- R/measure_features.R | 2 ++ R/motif_brokerage.R | 20 ++++++++++++-------- R/netrics-utils.R | 12 ++++++++++++ man-roxygen/param_memb.R | 9 +++++---- 4 files changed, 31 insertions(+), 12 deletions(-) diff --git a/R/measure_features.R b/R/measure_features.R index 0740305..e27dd25 100644 --- a/R/measure_features.R +++ b/R/measure_features.R @@ -150,6 +150,7 @@ net_by_richclub <- function(.data){ net_by_factions <- function(.data, membership = NULL){ .data <- manynet::expect_nodes(.data) + membership <- .resolve_membership(.data, membership) if(is.null(membership)){ manynet::snet_info("No membership vector assigned.", "Partitioning the network using {.fn node_in_partition}.") @@ -207,6 +208,7 @@ net_by_modularity <- function(.data, membership = NULL, resolution = 1){ .data <- manynet::expect_nodes(.data) + membership <- .resolve_membership(.data, membership) if(is.null(membership)){ manynet::snet_info("Since no membership argument has been provided,", "a partition of the network into two will be calculated and used.") diff --git a/R/motif_brokerage.R b/R/motif_brokerage.R index 7588b9a..8813b1f 100644 --- a/R/motif_brokerage.R +++ b/R/motif_brokerage.R @@ -33,15 +33,16 @@ NULL node_x_brokerage <- function(.data, membership, standardized = FALSE){ thisRequires("sna") .data <- manynet::expect_nodes(.data) + membership <- .resolve_membership(.data, membership) if(!manynet::is_twomode(.data)){ out <- sna::brokerage(manynet::as_network(.data), - manynet::node_attribute(.data, membership)) + membership) out <- if(standardized) out$z.nli else out$raw.nli colnames(out) <- c("Coordinator", "Itinerant", "Gatekeeper", "Representative", "Liaison", "Total") } else { out <- suppressWarnings(sna::brokerage(manynet::as_network(manynet::to_mode1(.data)), - manynet::node_attribute(.data, membership))) + membership)) out <- if(standardized) out$z.nli else out$raw.nli out <- out[,-4] colnames(out) <- c("Coordinator", "Itinerant", "Gatekeeper", @@ -72,15 +73,16 @@ NULL net_x_brokerage <- function(.data, membership, standardized = FALSE){ thisRequires("sna") .data <- manynet::expect_nodes(.data) + membership <- .resolve_membership(.data, membership) if(!manynet::is_twomode(.data)){ out <- sna::brokerage(manynet::as_network(.data), - manynet::node_attribute(.data, membership)) + membership) out <- if(standardized) out$z.gli else out$raw.gli names(out) <- c("Coordinator", "Itinerant", "Gatekeeper", "Representative", "Liaison", "Total") } else { out <- suppressWarnings(sna::brokerage(manynet::as_network(manynet::to_mode1(.data)), - manynet::node_attribute(.data, membership))) + membership)) out <- if(standardized) out$z.gli else out$raw.gli names(out) <- c("Coordinator", "Itinerant", "Gatekeeper", "Representative", "Liaison", "Total") @@ -118,10 +120,11 @@ node_by_brokering_activity <- function(.data, membership){ .data <- manynet::expect_nodes(.data) twopaths <- .to_twopaths(.data) if(!missing(membership)){ - twopaths$from_memb <- manynet::node_attribute(.data, membership)[`if`(manynet::is_labelled(.data), + membership <- .resolve_membership(.data, membership) + twopaths$from_memb <- membership[`if`(manynet::is_labelled(.data), match(twopaths$from, manynet::node_names(.data)), twopaths$from)] - twopaths$to_memb <- manynet::node_attribute(.data, membership)[`if`(manynet::is_labelled(.data), + twopaths$to_memb <- membership[`if`(manynet::is_labelled(.data), match(twopaths$to.y, manynet::node_names(.data)), twopaths$to.y)] twopaths <- dplyr::filter(twopaths, from_memb != to_memb) @@ -147,10 +150,11 @@ node_by_brokering_exclusivity <- function(.data, membership){ .data <- manynet::expect_nodes(.data) twopaths <- .to_twopaths(.data) if(!missing(membership)){ - twopaths$from_memb <- manynet::node_attribute(.data, membership)[`if`(manynet::is_labelled(.data), + membership <- .resolve_membership(.data, membership) + twopaths$from_memb <- membership[`if`(manynet::is_labelled(.data), match(twopaths$from, manynet::node_names(.data)), twopaths$from)] - twopaths$to_memb <- manynet::node_attribute(.data, membership)[`if`(manynet::is_labelled(.data), + twopaths$to_memb <- membership[`if`(manynet::is_labelled(.data), match(twopaths$to.y, manynet::node_names(.data)), twopaths$to.y)] twopaths <- dplyr::filter(twopaths, from_memb != to_memb) diff --git a/R/netrics-utils.R b/R/netrics-utils.R index a97ab23..55057ff 100644 --- a/R/netrics-utils.R +++ b/R/netrics-utils.R @@ -40,4 +40,16 @@ seq_nodes <- function(.data){ seq.int(manynet::net_nodes(.data)) } +# Resolve membership to a vector: +# if a single character string naming a network attribute is provided, +# retrieve that attribute as a vector; otherwise return the value as-is. +.resolve_membership <- function(.data, membership) { + if (is.character(membership) && length(membership) == 1 && + membership %in% manynet::node_attribute_names(.data)) { + manynet::node_attribute(.data, membership) + } else { + membership + } +} + # nocov end \ No newline at end of file diff --git a/man-roxygen/param_memb.R b/man-roxygen/param_memb.R index 991f2d7..37f307c 100644 --- a/man-roxygen/param_memb.R +++ b/man-roxygen/param_memb.R @@ -1,5 +1,6 @@ -#' @param membership A character vector of categorical membership. -#' This is a vector of the same length as the number of nodes in the network, -#' where each element is a character string indicating the membership of the corresponding node. -#' While this may often be a vector created using `node_in_*()` functions, +#' @param membership A character string naming an existing node attribute in +#' the network, or a categorical vector of the same length as the number of +#' nodes in the network where each element indicates the group membership of +#' the corresponding node. +#' While this may often be a vector created using `node_in_*()` functions, #' it can be any character vector that assigns nodes to groups or categories. From 06c38c61dc6efa6b055f4f40b27bf926c6f2fc45 Mon Sep 17 00:00:00 2001 From: James Hollway Date: Sat, 21 Mar 2026 20:26:37 +0100 Subject: [PATCH 34/35] Fixed .resolve_membership() --- R/netrics-utils.R | 2 +- man/measure_brokerage.Rd | 7 ++++--- man/measure_features.Rd | 7 ++++--- man/member_brokerage.Rd | 7 ++++--- man/motif_brokerage_net.Rd | 7 ++++--- man/motif_brokerage_node.Rd | 7 ++++--- 6 files changed, 21 insertions(+), 16 deletions(-) diff --git a/R/netrics-utils.R b/R/netrics-utils.R index 55057ff..dd51796 100644 --- a/R/netrics-utils.R +++ b/R/netrics-utils.R @@ -45,7 +45,7 @@ seq_nodes <- function(.data){ # retrieve that attribute as a vector; otherwise return the value as-is. .resolve_membership <- function(.data, membership) { if (is.character(membership) && length(membership) == 1 && - membership %in% manynet::node_attribute_names(.data)) { + membership %in% manynet::net_node_attributes(.data)) { manynet::node_attribute(.data, membership) } else { membership diff --git a/man/measure_brokerage.Rd b/man/measure_brokerage.Rd index 5af7e02..f425ae7 100644 --- a/man/measure_brokerage.Rd +++ b/man/measure_brokerage.Rd @@ -15,9 +15,10 @@ node_by_brokering_exclusivity(.data, membership) For more information on the standard coercion possible, see \code{\link[manynet:manip_as]{manynet::as_tidygraph()}}.} -\item{membership}{A character vector of categorical membership. -This is a vector of the same length as the number of nodes in the network, -where each element is a character string indicating the membership of the corresponding node. +\item{membership}{A character string naming an existing node attribute in +the network, or a categorical vector of the same length as the number of +nodes in the network where each element indicates the group membership of +the corresponding node. While this may often be a vector created using \verb{node_in_*()} functions, it can be any character vector that assigns nodes to groups or categories.} } diff --git a/man/measure_features.Rd b/man/measure_features.Rd index d5006fd..7ced2ab 100644 --- a/man/measure_features.Rd +++ b/man/measure_features.Rd @@ -63,9 +63,10 @@ with the same dimensions. but where there may not be a network for which \eqn{SWI = 1}. }} -\item{membership}{A character vector of categorical membership. -This is a vector of the same length as the number of nodes in the network, -where each element is a character string indicating the membership of the corresponding node. +\item{membership}{A character string naming an existing node attribute in +the network, or a categorical vector of the same length as the number of +nodes in the network where each element indicates the group membership of +the corresponding node. While this may often be a vector created using \verb{node_in_*()} functions, it can be any character vector that assigns nodes to groups or categories.} diff --git a/man/member_brokerage.Rd b/man/member_brokerage.Rd index 1670625..d4a4227 100644 --- a/man/member_brokerage.Rd +++ b/man/member_brokerage.Rd @@ -12,9 +12,10 @@ node_in_brokering(.data, membership) For more information on the standard coercion possible, see \code{\link[manynet:manip_as]{manynet::as_tidygraph()}}.} -\item{membership}{A character vector of categorical membership. -This is a vector of the same length as the number of nodes in the network, -where each element is a character string indicating the membership of the corresponding node. +\item{membership}{A character string naming an existing node attribute in +the network, or a categorical vector of the same length as the number of +nodes in the network where each element indicates the group membership of +the corresponding node. While this may often be a vector created using \verb{node_in_*()} functions, it can be any character vector that assigns nodes to groups or categories.} } diff --git a/man/motif_brokerage_net.Rd b/man/motif_brokerage_net.Rd index 2bc9858..94611e2 100644 --- a/man/motif_brokerage_net.Rd +++ b/man/motif_brokerage_net.Rd @@ -12,9 +12,10 @@ net_x_brokerage(.data, membership, standardized = FALSE) For more information on the standard coercion possible, see \code{\link[manynet:manip_as]{manynet::as_tidygraph()}}.} -\item{membership}{A character vector of categorical membership. -This is a vector of the same length as the number of nodes in the network, -where each element is a character string indicating the membership of the corresponding node. +\item{membership}{A character string naming an existing node attribute in +the network, or a categorical vector of the same length as the number of +nodes in the network where each element indicates the group membership of +the corresponding node. While this may often be a vector created using \verb{node_in_*()} functions, it can be any character vector that assigns nodes to groups or categories.} diff --git a/man/motif_brokerage_node.Rd b/man/motif_brokerage_node.Rd index a34a50d..214a255 100644 --- a/man/motif_brokerage_node.Rd +++ b/man/motif_brokerage_node.Rd @@ -12,9 +12,10 @@ node_x_brokerage(.data, membership, standardized = FALSE) For more information on the standard coercion possible, see \code{\link[manynet:manip_as]{manynet::as_tidygraph()}}.} -\item{membership}{A character vector of categorical membership. -This is a vector of the same length as the number of nodes in the network, -where each element is a character string indicating the membership of the corresponding node. +\item{membership}{A character string naming an existing node attribute in +the network, or a categorical vector of the same length as the number of +nodes in the network where each element indicates the group membership of +the corresponding node. While this may often be a vector created using \verb{node_in_*()} functions, it can be any character vector that assigns nodes to groups or categories.} From aa158878ea4e0eda21864a74181e8b06fe8f99c3 Mon Sep 17 00:00:00 2001 From: James Hollway Date: Sat, 21 Mar 2026 20:41:16 +0100 Subject: [PATCH 35/35] Renamed `node_exposure()` to `node_by_adopt_exposure()` --- NAMESPACE | 4 ++-- NEWS.md | 10 +++++++--- R/mark_nodes.R | 2 +- R/measure_diffusion.R | 22 +++++++++++----------- man/measure_diffusion_node.Rd | 20 ++++++++++---------- 5 files changed, 31 insertions(+), 27 deletions(-) diff --git a/NAMESPACE b/NAMESPACE index 8f0fc30..8aa1531 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -63,6 +63,8 @@ export(net_x_mixed) export(net_x_stability) export(net_x_tetrad) export(net_x_triad) +export(node_by_adopt_exposure) +export(node_by_adopt_recovery) export(node_by_adopt_threshold) export(node_by_adopt_time) export(node_by_alpha) @@ -83,7 +85,6 @@ export(node_by_efficiency) export(node_by_effsize) export(node_by_eigenvector) export(node_by_equivalency) -export(node_by_exposure) export(node_by_flow) export(node_by_harmonic) export(node_by_heterophily) @@ -104,7 +105,6 @@ export(node_by_power) export(node_by_randomwalk) export(node_by_reach) export(node_by_reciprocity) -export(node_by_recovery) export(node_by_redundancy) export(node_by_richness) export(node_by_stress) diff --git a/NEWS.md b/NEWS.md index a7012f0..f2363a6 100644 --- a/NEWS.md +++ b/NEWS.md @@ -12,7 +12,9 @@ ## Measuring - Renamed `node_adoption_time()` to `node_by_adopt_time()` -- Renamed`node_thresholds()` to `node_by_adopt_threshold()` +- Renamed `node_thresholds()` to `node_by_adopt_threshold()` +- Renamed `node_exposure()` to `node_by_adopt_exposure()` +- Renamed `node_recovery()` to `node_by_adopt_recovery()` - Separated centralisation scripts into different files per measure type (betweenness, closeness, degree, eigenvector) for easier maintenance, and into different documentation per level (node, tie) for better organization. @@ -24,11 +26,13 @@ - Separated `node_in_community()` documentation from the hierarchical and non-hierarchical community-detection algorithms. - Core documentation split into separate mark, measure, and member pages. +- Improved various functions that rely on a membership argument to accept + both a membership vector and a string identifier of a network attribute. ## Motifs -- Renamed `net_by_change()` to `net_x_change()` and related functions to reflect their motif (subgraph-counting) nature. -- Renamed +- Renamed `net_by_change()` to `net_x_change()` and related functions to + reflect their motif (subgraph-counting) nature. ## Methods diff --git a/R/mark_nodes.R b/R/mark_nodes.R index 9abb04a..439477d 100644 --- a/R/mark_nodes.R +++ b/R/mark_nodes.R @@ -382,7 +382,7 @@ node_is_exposed <- function(.data, mark, time = 0){ if (missing(mark)){ if(manynet::is_changing(.data)){ t <- time - return(make_node_mark(node_by_exposure(.data, time = t)>0, .data)) + return(make_node_mark(node_by_adopt_exposure(.data, time = t)>0, .data)) } else if(inherits(.data, "diff_model")){ mark <- summary(.data) %>% dplyr::filter(t == 0 & event == "I") %>% diff --git a/R/measure_diffusion.R b/R/measure_diffusion.R index 775a846..5e0d60d 100644 --- a/R/measure_diffusion.R +++ b/R/measure_diffusion.R @@ -84,7 +84,7 @@ net_by_transmissibility <- function(.data){ #' @export net_by_recovery <- function(.data, censor = TRUE){ diff_model <- manynet::as_diffusion(.data) - recovs <- node_by_recovery(.data) + recovs <- node_by_adopt_recovery(.data) if(censor && any(!is.infinite(recovs) & !is.na(recovs))) recovs[is.infinite(recovs)] <- nrow(diff_model) if(inherits(.data, "diff_model")) @@ -274,9 +274,9 @@ net_by_infection_peak <- function(.data){ #' nodes adopt/become infected #' - `node_by_adopt_threshold()`: Measures nodes' thresholds from the amount #' of exposure they had when they became infected -#' - `node_by_infection_length()`: Measures the average length nodes that become +#' - `node_by_adopt_recovery()`: Measures the average length nodes that become #' infected remain infected in a compartmental model with recovery -#' - `node_by_exposure()`: Measures how many exposures nodes have to +#' - `node_by_adopt_exposure()`: Measures how many exposures nodes have to #' a given mark #' #' @template param_data @@ -374,7 +374,7 @@ node_by_adopt_threshold <- function(.data, normalized = TRUE, lag = 1){ if(!"exposure" %in% names(out)){ out[,'exposure'] <- NA_integer_ for(v in unique(out$t)){ - out$exposure[out$t == v] <- node_by_exposure(diff_model, + out$exposure[out$t == v] <- node_by_adopt_exposure(diff_model, time = v-lag)[out$nodes[out$t == v]] } } @@ -393,7 +393,7 @@ node_by_adopt_threshold <- function(.data, normalized = TRUE, lag = 1){ if(!"exposure" %in% names(out)){ out[,'exposure'] <- NA_integer_ for(v in unique(out$time)){ - out$exposure[out$time == v] <- node_by_exposure(.data, + out$exposure[out$time == v] <- node_by_adopt_exposure(.data, time = v-lag)[out$node[out$time == v]] } } @@ -427,15 +427,15 @@ node_by_adopt_threshold <- function(.data, normalized = TRUE, lag = 1){ #' @rdname measure_diffusion_node #' @section Recovery: -#' `node_recovery()` measures the average length of time that nodes +#' `node_by_adopt_recovery()` measures the average length of time that nodes #' that become infected remain infected in a compartmental model with recovery. #' Infections that are not concluded by the end of the study period are #' calculated as infinite. #' @examples #' # To measure how long each node remains infected for -#' node_by_recovery(smeg_diff) +#' node_by_adopt_recovery(smeg_diff) #' @export -node_by_recovery <- function(.data){ +node_by_adopt_recovery <- function(.data){ if(inherits(.data, "diff_model")){ net <- attr(.data, "network") events <- attr(.data, "events") @@ -475,10 +475,10 @@ node_by_recovery <- function(.data){ #' nodes exposure at \eqn{t = 0}. #' @examples #' # To measure how much exposure nodes have to a given mark -#' node_by_exposure(smeg, mark = c(1,3)) -#' node_by_exposure(smeg_diff) +#' node_by_adopt_exposure(smeg, mark = c(1,3)) +#' node_by_adopt_exposure(smeg_diff) #' @export -node_by_exposure <- function(.data, mark, time = 0){ +node_by_adopt_exposure <- function(.data, mark, time = 0){ .data <- manynet::expect_nodes(.data) if(missing(mark)){ if(inherits(.data, "diff_model")){ diff --git a/man/measure_diffusion_node.Rd b/man/measure_diffusion_node.Rd index cc0d9a7..c9e65df 100644 --- a/man/measure_diffusion_node.Rd +++ b/man/measure_diffusion_node.Rd @@ -4,17 +4,17 @@ \alias{measure_diffusion_node} \alias{node_by_adopt_time} \alias{node_by_adopt_threshold} -\alias{node_by_recovery} -\alias{node_by_exposure} +\alias{node_by_adopt_recovery} +\alias{node_by_adopt_exposure} \title{Measures of nodes in a diffusion} \usage{ node_by_adopt_time(.data) node_by_adopt_threshold(.data, normalized = TRUE, lag = 1) -node_by_recovery(.data) +node_by_adopt_recovery(.data) -node_by_exposure(.data, mark, time = 0) +node_by_adopt_exposure(.data, mark, time = 0) } \arguments{ \item{.data}{A network object of class \code{mnet}, \code{igraph}, \code{tbl_graph}, \code{network}, or similar. @@ -50,9 +50,9 @@ a diffusion process: nodes adopt/become infected \item \code{node_by_adopt_threshold()}: Measures nodes' thresholds from the amount of exposure they had when they became infected -\item \code{node_by_infection_length()}: Measures the average length nodes that become +\item \code{node_by_adopt_recovery()}: Measures the average length nodes that become infected remain infected in a compartmental model with recovery -\item \code{node_by_exposure()}: Measures how many exposures nodes have to +\item \code{node_by_adopt_exposure()}: Measures how many exposures nodes have to a given mark } } @@ -83,7 +83,7 @@ and works regardless of whether \eqn{w} is weighted or not. \section{Recovery}{ -\code{node_recovery()} measures the average length of time that nodes +\code{node_by_adopt_recovery()} measures the average length of time that nodes that become infected remain infected in a compartmental model with recovery. Infections that are not concluded by the end of the study period are calculated as infinite. @@ -108,10 +108,10 @@ nodes exposure at \eqn{t = 0}. # To infer nodes' thresholds node_by_adopt_threshold(smeg_diff) # To measure how long each node remains infected for - node_by_recovery(smeg_diff) + node_by_adopt_recovery(smeg_diff) # To measure how much exposure nodes have to a given mark - node_by_exposure(smeg, mark = c(1,3)) - node_by_exposure(smeg_diff) + node_by_adopt_exposure(smeg, mark = c(1,3)) + node_by_adopt_exposure(smeg_diff) } \references{ \subsection{On diffusion measures}{