Source code for networkx.algorithms.centrality.voterank_alg

"""Algorithm to select influential nodes in a graph using VoteRank."""

import networkx as nx

__all__ = ["voterank"]


[docs] @nx._dispatchable def voterank(G, number_of_nodes=None): """Select a list of influential nodes in a graph using VoteRank algorithm VoteRank [1]_ computes a ranking of the nodes in a graph G based on a voting scheme. With VoteRank, all nodes vote for each of its in-neighbors and the node with the highest votes is elected iteratively. The voting ability of out-neighbors of elected nodes is decreased in subsequent turns. Parameters ---------- G : graph A NetworkX graph. number_of_nodes : integer, optional Number of ranked nodes to extract (default all nodes). Returns ------- voterank : list Ordered list of computed seeds. Only nodes with positive number of votes are returned. Examples -------- >>> G = nx.Graph([(0, 1), (0, 2), (0, 3), (1, 4)]) >>> nx.voterank(G) [0, 1] The algorithm can be used both for undirected and directed graphs. However, the directed version is different in two ways: (i) nodes only vote for their in-neighbors and (ii) only the voting ability of elected node and its out-neighbors are updated: >>> G = nx.DiGraph([(0, 1), (2, 1), (2, 3), (3, 4)]) >>> nx.voterank(G) [2, 3] Notes ----- Each edge is treated independently in case of multigraphs. References ---------- .. [1] Zhang, J.-X. et al. (2016). Identifying a set of influential spreaders in complex networks. Sci. Rep. 6, 27823; doi: 10.1038/srep27823. """ influential_nodes = [] vote_rank = {} if len(G) == 0: return influential_nodes if number_of_nodes is None or number_of_nodes > len(G): number_of_nodes = len(G) if G.is_directed(): # For directed graphs compute average out-degree avgDegree = sum(deg for _, deg in G.out_degree()) / len(G) else: # For undirected graphs compute average degree avgDegree = sum(deg for _, deg in G.degree()) / len(G) # step 1 - initiate all nodes to (0,1) (score, voting ability) for n in G.nodes(): vote_rank[n] = [0, 1] # Repeat steps 1b to 4 until num_seeds are elected. for _ in range(number_of_nodes): # step 1b - reset rank for n in G.nodes(): vote_rank[n][0] = 0 # step 2 - vote for n, nbr in G.edges(): # In directed graphs nodes only vote for their in-neighbors vote_rank[n][0] += vote_rank[nbr][1] if not G.is_directed(): vote_rank[nbr][0] += vote_rank[n][1] for n in influential_nodes: vote_rank[n][0] = 0 # step 3 - select top node n = max(G.nodes, key=lambda x: vote_rank[x][0]) if vote_rank[n][0] == 0: return influential_nodes influential_nodes.append(n) # weaken the selected node vote_rank[n] = [0, 0] # step 4 - update voterank properties for _, nbr in G.edges(n): vote_rank[nbr][1] -= 1 / avgDegree vote_rank[nbr][1] = max(vote_rank[nbr][1], 0) return influential_nodes