84 lines
2.8 KiB
Python
84 lines
2.8 KiB
Python
|
# Copyright (C) 2017 by
|
||
|
# Fredrik Erlandsson <fredrik.e@gmail.com>
|
||
|
# All rights reserved.
|
||
|
# BSD license.
|
||
|
#
|
||
|
"""Algorithm to compute influential seeds in a graph using voterank."""
|
||
|
from networkx.utils.decorators import not_implemented_for
|
||
|
|
||
|
__all__ = ['voterank']
|
||
|
__author__ = """\n""".join(['Fredrik Erlandsson <fredrik.e@gmail.com>',
|
||
|
'Piotr Brodka (piotr.brodka@pwr.edu.pl'])
|
||
|
|
||
|
|
||
|
@not_implemented_for('directed')
|
||
|
def voterank(G, number_of_nodes=None, max_iter=10000):
|
||
|
"""Compute a list of seeds for the nodes in the graph using VoteRank
|
||
|
|
||
|
VoteRank [1]_ computes a ranking of the nodes in the graph G based on a voting
|
||
|
scheme. With VoteRank, all nodes vote for each neighbours and the node with
|
||
|
the highest score is elected iteratively. The voting ability of neighbors of
|
||
|
elected nodes will be decreased in subsequent turn.
|
||
|
|
||
|
Parameters
|
||
|
----------
|
||
|
G : graph
|
||
|
A NetworkX graph.
|
||
|
|
||
|
number_of_nodes : integer, optional
|
||
|
Number of ranked nodes to extract (default all nodes).
|
||
|
|
||
|
max_iter : integer, optional
|
||
|
Maximum number of iterations to rank nodes.
|
||
|
|
||
|
Returns
|
||
|
-------
|
||
|
voterank : list
|
||
|
Ordered list of computed seeds.
|
||
|
|
||
|
Raises
|
||
|
------
|
||
|
NetworkXNotImplemented:
|
||
|
If G is digraph.
|
||
|
|
||
|
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.
|
||
|
"""
|
||
|
voterank = []
|
||
|
if len(G) == 0:
|
||
|
return voterank
|
||
|
if number_of_nodes is None or number_of_nodes > len(G):
|
||
|
number_of_nodes = len(G)
|
||
|
avgDegree = sum(deg for _, deg in G.degree()) / float(len(G))
|
||
|
# step 1 - initiate all nodes to (0,1) (score, voting ability)
|
||
|
for _, v in G.nodes(data=True):
|
||
|
v['voterank'] = [0, 1]
|
||
|
# Repeat steps 1b to 4 until num_seeds are elected.
|
||
|
for _ in range(max_iter):
|
||
|
# step 1b - reset rank
|
||
|
for _, v in G.nodes(data=True):
|
||
|
v['voterank'][0] = 0
|
||
|
# step 2 - vote
|
||
|
for n, nbr in G.edges():
|
||
|
G.nodes[n]['voterank'][0] += G.nodes[nbr]['voterank'][1]
|
||
|
G.nodes[nbr]['voterank'][0] += G.nodes[n]['voterank'][1]
|
||
|
for n in voterank:
|
||
|
G.nodes[n]['voterank'][0] = 0
|
||
|
# step 3 - select top node
|
||
|
n, value = max(G.nodes(data=True),
|
||
|
key=lambda x: x[1]['voterank'][0])
|
||
|
if value['voterank'][0] == 0:
|
||
|
return voterank
|
||
|
voterank.append(n)
|
||
|
if len(voterank) >= number_of_nodes:
|
||
|
return voterank
|
||
|
# weaken the selected node
|
||
|
G.nodes[n]['voterank'] = [0, 0]
|
||
|
# step 4 - update voterank properties
|
||
|
for nbr in G.neighbors(n):
|
||
|
G.nodes[nbr]['voterank'][1] -= 1 / avgDegree
|
||
|
return voterank
|