| | """Functions for computing reaching centrality of a node or a graph.""" |
| |
|
| | import networkx as nx |
| | from networkx.utils import pairwise |
| |
|
| | __all__ = ["global_reaching_centrality", "local_reaching_centrality"] |
| |
|
| |
|
| | def _average_weight(G, path, weight=None): |
| | """Returns the average weight of an edge in a weighted path. |
| | |
| | Parameters |
| | ---------- |
| | G : graph |
| | A networkx graph. |
| | |
| | path: list |
| | A list of vertices that define the path. |
| | |
| | weight : None or string, optional (default=None) |
| | If None, edge weights are ignored. Then the average weight of an edge |
| | is assumed to be the multiplicative inverse of the length of the path. |
| | Otherwise holds the name of the edge attribute used as weight. |
| | """ |
| | path_length = len(path) - 1 |
| | if path_length <= 0: |
| | return 0 |
| | if weight is None: |
| | return 1 / path_length |
| | total_weight = sum(G.edges[i, j][weight] for i, j in pairwise(path)) |
| | return total_weight / path_length |
| |
|
| |
|
| | @nx._dispatchable(edge_attrs="weight") |
| | def global_reaching_centrality(G, weight=None, normalized=True): |
| | """Returns the global reaching centrality of a directed graph. |
| | |
| | The *global reaching centrality* of a weighted directed graph is the |
| | average over all nodes of the difference between the local reaching |
| | centrality of the node and the greatest local reaching centrality of |
| | any node in the graph [1]_. For more information on the local |
| | reaching centrality, see :func:`local_reaching_centrality`. |
| | Informally, the local reaching centrality is the proportion of the |
| | graph that is reachable from the neighbors of the node. |
| | |
| | Parameters |
| | ---------- |
| | G : DiGraph |
| | A networkx DiGraph. |
| | |
| | weight : None or string, optional (default=None) |
| | Attribute to use for edge weights. If ``None``, each edge weight |
| | is assumed to be one. A higher weight implies a stronger |
| | connection between nodes and a *shorter* path length. |
| | |
| | normalized : bool, optional (default=True) |
| | Whether to normalize the edge weights by the total sum of edge |
| | weights. |
| | |
| | Returns |
| | ------- |
| | h : float |
| | The global reaching centrality of the graph. |
| | |
| | Examples |
| | -------- |
| | >>> G = nx.DiGraph() |
| | >>> G.add_edge(1, 2) |
| | >>> G.add_edge(1, 3) |
| | >>> nx.global_reaching_centrality(G) |
| | 1.0 |
| | >>> G.add_edge(3, 2) |
| | >>> nx.global_reaching_centrality(G) |
| | 0.75 |
| | |
| | See also |
| | -------- |
| | local_reaching_centrality |
| | |
| | References |
| | ---------- |
| | .. [1] Mones, Enys, Lilla Vicsek, and Tamás Vicsek. |
| | "Hierarchy Measure for Complex Networks." |
| | *PLoS ONE* 7.3 (2012): e33799. |
| | https://doi.org/10.1371/journal.pone.0033799 |
| | """ |
| | if nx.is_negatively_weighted(G, weight=weight): |
| | raise nx.NetworkXError("edge weights must be positive") |
| | total_weight = G.size(weight=weight) |
| | if total_weight <= 0: |
| | raise nx.NetworkXError("Size of G must be positive") |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | if weight is not None: |
| |
|
| | def as_distance(u, v, d): |
| | return total_weight / d.get(weight, 1) |
| |
|
| | shortest_paths = nx.shortest_path(G, weight=as_distance) |
| | else: |
| | shortest_paths = nx.shortest_path(G) |
| |
|
| | centrality = local_reaching_centrality |
| | |
| | lrc = [ |
| | centrality(G, node, paths=paths, weight=weight, normalized=normalized) |
| | for node, paths in shortest_paths.items() |
| | ] |
| |
|
| | max_lrc = max(lrc) |
| | return sum(max_lrc - c for c in lrc) / (len(G) - 1) |
| |
|
| |
|
| | @nx._dispatchable(edge_attrs="weight") |
| | def local_reaching_centrality(G, v, paths=None, weight=None, normalized=True): |
| | """Returns the local reaching centrality of a node in a directed |
| | graph. |
| | |
| | The *local reaching centrality* of a node in a directed graph is the |
| | proportion of other nodes reachable from that node [1]_. |
| | |
| | Parameters |
| | ---------- |
| | G : DiGraph |
| | A NetworkX DiGraph. |
| | |
| | v : node |
| | A node in the directed graph `G`. |
| | |
| | paths : dictionary (default=None) |
| | If this is not `None` it must be a dictionary representation |
| | of single-source shortest paths, as computed by, for example, |
| | :func:`networkx.shortest_path` with source node `v`. Use this |
| | keyword argument if you intend to invoke this function many |
| | times but don't want the paths to be recomputed each time. |
| | |
| | weight : None or string, optional (default=None) |
| | Attribute to use for edge weights. If `None`, each edge weight |
| | is assumed to be one. A higher weight implies a stronger |
| | connection between nodes and a *shorter* path length. |
| | |
| | normalized : bool, optional (default=True) |
| | Whether to normalize the edge weights by the total sum of edge |
| | weights. |
| | |
| | Returns |
| | ------- |
| | h : float |
| | The local reaching centrality of the node ``v`` in the graph |
| | ``G``. |
| | |
| | Examples |
| | -------- |
| | >>> G = nx.DiGraph() |
| | >>> G.add_edges_from([(1, 2), (1, 3)]) |
| | >>> nx.local_reaching_centrality(G, 3) |
| | 0.0 |
| | >>> G.add_edge(3, 2) |
| | >>> nx.local_reaching_centrality(G, 3) |
| | 0.5 |
| | |
| | See also |
| | -------- |
| | global_reaching_centrality |
| | |
| | References |
| | ---------- |
| | .. [1] Mones, Enys, Lilla Vicsek, and Tamás Vicsek. |
| | "Hierarchy Measure for Complex Networks." |
| | *PLoS ONE* 7.3 (2012): e33799. |
| | https://doi.org/10.1371/journal.pone.0033799 |
| | """ |
| | if paths is None: |
| | if nx.is_negatively_weighted(G, weight=weight): |
| | raise nx.NetworkXError("edge weights must be positive") |
| | total_weight = G.size(weight=weight) |
| | if total_weight <= 0: |
| | raise nx.NetworkXError("Size of G must be positive") |
| | if weight is not None: |
| | |
| | def as_distance(u, v, d): |
| | return total_weight / d.get(weight, 1) |
| |
|
| | paths = nx.shortest_path(G, source=v, weight=as_distance) |
| | else: |
| | paths = nx.shortest_path(G, source=v) |
| | |
| | |
| | if weight is None and G.is_directed(): |
| | return (len(paths) - 1) / (len(G) - 1) |
| | if normalized and weight is not None: |
| | norm = G.size(weight=weight) / G.size() |
| | else: |
| | norm = 1 |
| | |
| | avgw = (_average_weight(G, path, weight=weight) for path in paths.values()) |
| | sum_avg_weight = sum(avgw) / norm |
| | return sum_avg_weight / (len(G) - 1) |
| |
|