簡體   English   中英

使用NetworkX計算SimRank?

[英]Calculating SimRank using NetworkX?

我想知道如何使用python模塊networkX實現SimRank來比較2個節點的相似性? 我知道networkX提供了查看鄰居的方法,以及鏈接分析算法,如PageRank和HITS,但有一個用於SimRank嗎?

示例,教程也受到歡迎!

更新我實現了networkx_addon庫。 SimRank包含在庫中。 有關詳細信息,請訪問: https//github.com/hhchen1105/networkx_addon

樣品用法:

    >>> import networkx
    >>> import networkx_addon
    >>> G = networkx.Graph()
    >>> G.add_edges_from([('a','b'), ('b','c'), ('a','c'), ('c','d')])
    >>> s = networkx_addon.similarity.simrank(G)

您可以通過獲得兩個節點(例如,節點“a”和節點“b”)之間的相似性得分

    >>> print s['a']['b']

SimRank是一種頂點相似性度量。 它基於拓撲(即,圖的節點和鏈接)計算圖上兩個節點之間的相似性。 為了說明SimRank,讓我們考慮下面的圖, 其中 ,B,C相互連接,並且d被連接到d。 一個節點如何類似於節點d,是基於一個怎樣的鄰居節點,bc,類似於d的鄰國,C。

    +-------+
    |       |
    a---b---c---d

如圖所示,這是一個遞歸定義。 因此,遞歸地計算SimRank直到相似度值收斂。 請注意,SimRank引入了一個常量r來表示直接鄰居和直接鄰居之間的相對重要性。 可以在這里找到SimRank的形式方程。

以下函數將networkx圖$ G $和相對imporance參數r作為輸入,並返回G中任意兩個節點之間的simrank相似值sim 返回值sim是float字典的字典。 為了訪問圖G中節點a和節點b之間的相似性,可以簡單地訪問sim [a] [b]。

    def simrank(G, r=0.9, max_iter=100):
      # init. vars
      sim_old = defaultdict(list)
      sim = defaultdict(list)
      for n in G.nodes():
        sim[n] = defaultdict(int)
        sim[n][n] = 1
        sim_old[n] = defaultdict(int)
        sim_old[n][n] = 0

      # recursively calculate simrank
      for iter_ctr in range(max_iter):
        if _is_converge(sim, sim_old):
          break
        sim_old = copy.deepcopy(sim)
        for u in G.nodes():
          for v in G.nodes():
            if u == v:
              continue
            s_uv = 0.0
            for n_u in G.neighbors(u):
              for n_v in G.neighbors(v):
                s_uv += sim_old[n_u][n_v]
            sim[u][v] = (r * s_uv / (len(G.neighbors(u)) * len(G.neighbors(v))))
      return sim

    def _is_converge(s1, s2, eps=1e-4):
      for i in s1.keys():
        for j in s1[i].keys():
          if abs(s1[i][j] - s2[i][j]) >= eps:
            return False
      return True

要計算上圖中節點之間的相似度值,您可以嘗試這樣做。

    >> G = networkx.Graph()
    >> G.add_edges_from([('a','b'), ('b', 'c'), ('c','a'), ('c','d')])
    >> simrank(G)

你會得到

    defaultdict(<type 'list'>, {'a': defaultdict(<type 'int'>, {'a': 0, 'c': 0.62607626807407868, 'b': 0.65379221101693585, 'd': 0.7317028881451203}), 'c': defaultdict(<type 'int'>, {'a': 0.62607626807407868, 'c': 0, 'b': 0.62607626807407868, 'd': 0.53653543888775579}), 'b': defaultdict(<type 'int'>, {'a': 0.65379221101693585, 'c': 0.62607626807407868, 'b': 0, 'd': 0.73170288814512019}), 'd': defaultdict(<type 'int'>, {'a': 0.73170288814512019, 'c': 0.53653543888775579, 'b': 0.73170288814512019, 'd': 0})})

讓我們通過計算節點a和節點b之間的相似性來驗證結果,用S(a,b)表示

S(a,b)= r *(S(b,a)+ S(b,c)+ S(c,a)+ S(c,c))/(2 * 2)= 0.9 *(0.6538+ 0.6261 + 0.6261 + 1)/ 4 = 0.6538,

這與我們上面計算的S(a,b)相同

有關詳細信息,您可能需要查看以下文章:

G. Jeh和J. Widom。 SimRank:結構 - 背景相似性的度量。 在KDD'02第538-543頁。 ACM出版社,2002年。

不,simrank沒有在networkx中實現。

如果你要將它添加到networkx,你可以使用numpyitertools縮短user1036719給出的代碼:

def simrank(G, r=0.8, max_iter=100, eps=1e-4):

    nodes = G.nodes()
    nodes_i = {k: v for(k, v) in [(nodes[i], i) for i in range(0, len(nodes))]}

    sim_prev = numpy.zeros(len(nodes))
    sim = numpy.identity(len(nodes))

    for i in range(max_iter):
        if numpy.allclose(sim, sim_prev, atol=eps):
            break
        sim_prev = numpy.copy(sim)
        for u, v in itertools.product(nodes, nodes):
            if u is v:
                continue
            u_ns, v_ns = G.predecessors(u), G.predecessors(v)

            # evaluating the similarity of current iteration nodes pair
            if len(u_ns) == 0 or len(v_ns) == 0: 
                # if a node has no predecessors then setting similarity to zero
                sim[nodes_i[u]][nodes_i[v]] = 0
            else:                    
                s_uv = sum([sim_prev[nodes_i[u_n]][nodes_i[v_n]] for u_n, v_n in itertools.product(u_ns, v_ns)])
                sim[nodes_i[u]][nodes_i[v]] = (r * s_uv) / (len(u_ns) * len(v_ns))


    return sim

然后,從SimRank論文(大學圖)中取出玩具示例,再現紙張結果:

G = networkx.DiGraph()
G.add_edges_from([('1','2'), ('1', '4'), ('2','3'), ('3','1'), ('4', '5'), ('5', '4')])
pprint(simrank(G).round(3))

哪個輸出:

array([[ 1.   ,  0.   ,  0.   ,  0.034,  0.132],
       [ 0.   ,  1.   ,  0.   ,  0.331,  0.042],
       [ 0.   ,  0.   ,  1.   ,  0.106,  0.414],
       [ 0.034,  0.331,  0.106,  1.   ,  0.088],
       [ 0.132,  0.042,  0.414,  0.088,  1.   ]])

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM