voterank_alg.py 3.1 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192
  1. """Algorithm to select influential nodes in a graph using VoteRank."""
  2. __all__ = ["voterank"]
  3. def voterank(G, number_of_nodes=None):
  4. """Select a list of influential nodes in a graph using VoteRank algorithm
  5. VoteRank [1]_ computes a ranking of the nodes in a graph G based on a
  6. voting scheme. With VoteRank, all nodes vote for each of its in-neighbours
  7. and the node with the highest votes is elected iteratively. The voting
  8. ability of out-neighbors of elected nodes is decreased in subsequent turns.
  9. Parameters
  10. ----------
  11. G : graph
  12. A NetworkX graph.
  13. number_of_nodes : integer, optional
  14. Number of ranked nodes to extract (default all nodes).
  15. Returns
  16. -------
  17. voterank : list
  18. Ordered list of computed seeds.
  19. Only nodes with positive number of votes are returned.
  20. Examples
  21. --------
  22. >>> G = nx.Graph([(0, 1), (0, 2), (0, 3), (1, 4)])
  23. >>> nx.voterank(G)
  24. [0, 1]
  25. The algorithm can be used both for undirected and directed graphs.
  26. However, the directed version is different in two ways:
  27. (i) nodes only vote for their in-neighbors and
  28. (ii) only the voting ability of elected node and its out-neighbors are updated:
  29. >>> G = nx.DiGraph([(0, 1), (2, 1), (2, 3), (3, 4)])
  30. >>> nx.voterank(G)
  31. [2, 3]
  32. Notes
  33. -----
  34. Each edge is treated independently in case of multigraphs.
  35. References
  36. ----------
  37. .. [1] Zhang, J.-X. et al. (2016).
  38. Identifying a set of influential spreaders in complex networks.
  39. Sci. Rep. 6, 27823; doi: 10.1038/srep27823.
  40. """
  41. influential_nodes = []
  42. vote_rank = {}
  43. if len(G) == 0:
  44. return influential_nodes
  45. if number_of_nodes is None or number_of_nodes > len(G):
  46. number_of_nodes = len(G)
  47. if G.is_directed():
  48. # For directed graphs compute average out-degree
  49. avgDegree = sum(deg for _, deg in G.out_degree()) / len(G)
  50. else:
  51. # For undirected graphs compute average degree
  52. avgDegree = sum(deg for _, deg in G.degree()) / len(G)
  53. # step 1 - initiate all nodes to (0,1) (score, voting ability)
  54. for n in G.nodes():
  55. vote_rank[n] = [0, 1]
  56. # Repeat steps 1b to 4 until num_seeds are elected.
  57. for _ in range(number_of_nodes):
  58. # step 1b - reset rank
  59. for n in G.nodes():
  60. vote_rank[n][0] = 0
  61. # step 2 - vote
  62. for n, nbr in G.edges():
  63. # In directed graphs nodes only vote for their in-neighbors
  64. vote_rank[n][0] += vote_rank[nbr][1]
  65. if not G.is_directed():
  66. vote_rank[nbr][0] += vote_rank[n][1]
  67. for n in influential_nodes:
  68. vote_rank[n][0] = 0
  69. # step 3 - select top node
  70. n = max(G.nodes, key=lambda x: vote_rank[x][0])
  71. if vote_rank[n][0] == 0:
  72. return influential_nodes
  73. influential_nodes.append(n)
  74. # weaken the selected node
  75. vote_rank[n] = [0, 0]
  76. # step 4 - update voterank properties
  77. for _, nbr in G.edges(n):
  78. vote_rank[nbr][1] -= 1 / avgDegree
  79. vote_rank[nbr][1] = max(vote_rank[nbr][1], 0)
  80. return influential_nodes