2021-09-18

将Networkx中的voterank算法改写为igraph形式

尝试将networkx中的voterank算法用igraph自定义函数调用

首先,需要贴出networkx中的voterank源码:

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-neighbours
    and the node with the highest votes is elected iteratively. The voting
    ability of out-neighbors of elected nodes is decreased in subsequent turns.

    Note: We treat each edge independently in case of multigraphs.

    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.

    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 = []
    voterank = {}
    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():
        voterank[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():
            voterank[n][0] = 0
        # step 2 - vote
        for n, nbr in G.edges():
            # In directed graphs nodes only vote for their in-neighbors
            voterank[n][0] += voterank[nbr][1]
            if not G.is_directed():
                voterank[nbr][0] += voterank[n][1]
        for n in influential_nodes:
            voterank[n][0] = 0
        # step 3 - select top node
        n = max(G.nodes, key=lambda x: voterank[x][0])
        if voterank[n][0] == 0:
            return influential_nodes
        influential_nodes.append(n)
        # weaken the selected node
        voterank[n] = [0, 0]
        # step 4 - update voterank properties
        for _, nbr in G.edges(n):
            voterank[nbr][1] -= 1 / avgDegree
            voterank[nbr][1] = max(voterank[nbr][1], 0)
    return influential_nodes

改为igraph的voterank算法

def votrank_ig(G,number_of_nodes = None):
    '''
    using igraph to rewrite voterank
    '''
    influential_nodes = []
    voterank = {}

    if number_of_nodes is None or number_of_nodes > len(G.vs()):
        number_of_nodes = len(G.vs())
    if G.is_directed():
        # For directed graphs compute average out-degree
        avgDegree = sum(deg.outdegree() for deg in G.vs()) / len(G.vs())
    else:
        # For undirected graphs compute average degree
        avgDegree = sum(deg.outdegree() for deg in G.vs()) / len(G.vs())

    # step1
    for n in range(len(G.vs())):
        voterank[n] = [0, 1]
    for _ in range(number_of_nodes):
        # step 1b - reset rank
        for n in G.vs():
            voterank[n["id"]][0] = 0

        # step 2 - vote
        for e in G.es:
            # In directed graphs nodes only vote for their in-neighbors
            v1, v2 = e.source, e.target
            voterank[v1][0] += voterank[v2][1]
            if not G.is_directed():
                voterank[v2][0] += voterank[v1][1]
        for n in influential_nodes:
            voterank[n][0] = 0
        # step 3 - select top node
        n = max(G.vs["id"], key=lambda x: voterank[x][0])

        if voterank[n][0] == 0:
            return influential_nodes
        influential_nodes.append(n)
         # weaken the selected node
        voterank[n] = [0, 0]

        # step 4 - update voterank properties
        for e in (G.vs[n]).incident():
            nbr = e.target
            voterank[nbr][1] -= 1 / avgDegree
            voterank[nbr][1] = max(voterank[nbr][1], 0)
    return influential_nodes

跑实验对比:

(1)Networkx 写法

import networkx as nx
import numpy as np
import matplotlib.pyplot as plt
G = nx.DiGraph()

Matrix = np.array([
    [0,1,1,1,1,1,1,1,1,1],
    [0,0,1,1,1,1,1,1,0,1],
    [0,0,0,1,1,1,1,0,1,1],
    [0,0,0,0,0,0,1,1,1,1],
    [0,0,0,0,0,0,1,1,1,1],
    [0,0,0,0,0,0,1,1,1,1],
    [0,0,0,0,0,0,0,0,0,0],
    [0,0,0,0,0,0,0,0,1,0],
    [0,0,0,0,0,0,0,0,0,0],
    [0,0,0,0,0,0,0,0,0,0]
])
for i in range(len(Matrix)):
    for j in range(len(Matrix)):
        if Matrix[i][j]:
            G.add_edge(i,j)
pos = nx.circular_layout(G)
nx.draw(G,pos,with_labels=True)
print(voterank(G))

结果为: [0, 1, 2, 3, 4]

(2)igraph写法

from igraph import *
g = Graph(directed=True)
g.add_vertices(10)
# add ids and labels to vertices
for i in range(len(g.vs)):
    g.vs[i]['id'] = i
    g.vs[i]['label'] = str(i)
g.add_edges([(0,1),(0,2),(0,3),(0,4),(0,5),(0,6),(0,7),(0,8),(0,9),(1,2),(1,3),
             (1,4),(1,5),(1,6),(1,7),(1,9),(2,3),(2,4),(2,5),(2,6),(2,8),(2,9),
             (3,6),(3,7),(3,8),(3,9),(4,6),(4,7),(4,8),(4,9),(5,6),(5,7),(5,8),
             (5,9),(7,8)])
# 设置可视化类型,并使用可视化类型
visual_style = {}
visual_style['vertex_size'] = 45
visual_style['vertex_color'] = 'white'
visual_style['vertex_label_size'] = 22
visual_style['layout'] = g.layout_circle()
visual_style['bbox'] = (400,400)
visual_style['margin'] = 27
plot(g, 'graph.png',**visual_style)```
print(votrank_ig(g))

结果仍是: [0, 1, 2, 3, 4]

因此,该函数改写成功!可以直接复制调用了。
[1]: https://networkx.org/documentation/stable/_modules/networkx/algorithms/centrality/voterank_alg.html#voterank
[2]: https://www.centiserver.org/centrality/VoteRank/

上一篇:剑指offer-从头到尾打印链表


下一篇:ABAP-CL_GUI_ALV_TREE 选择框