import numpy as np
import random
import networkx as nx
from IPython.display import Image
import matplotlib.pyplot as plt
實時欺詐檢測
實時推薦
精簡法規遵從性
複雜網絡的管理和監控
身份和訪問管理
社交應用/功能
…
目前大多數框架(比如 Python 的 networkx 或 Neo4J)支持的圖算法類別主要有三個:Pathfinding(尋路):根據可用性和質量等條件確定最優路徑。我們也將搜索算法包含在這一類別中。這可用於確定最快路由或流量路由。
Centrality(中心性):確定網絡中節點的重要性。這可用於識別社交網絡中有影響力的人或識別網絡中潛在的攻擊目標。
Community detection(社群檢測):評估群體聚類的方式。這可用於劃分客戶或檢測欺詐等。
networkx 中的所有算法都可在這裡找到:https://networkx.github.io/documentation/stable/reference/algorithms/index.html我們只會介紹 networkx 中實現的最常見的基本算法。最短路徑計算的是一對節點之間的最短的加權(如果圖有加權的話)路徑。這可用於確定最優的駕駛方向或社交網絡上兩個人之間的分離程度。計算圖中的最短路徑的方法有很多,包括 Dijkstra 算法,這是 networkx 中的默認算法。將圖中所有節點標記為未訪問。創建一個所有未訪問節點的集合,稱為未訪問集。
為每個節點分配一個暫定的距離值:將我們的初始節點的該值設置為零,將其它所有節點的該值設置為無窮。將初始起始節點設置為當前節點。
對於當前節點,考察其所有未被訪問過的相鄰節點並計算通過當前節點的暫定距離。比較新計算出的暫定距離與當前分配的值,配之以其中更小的值。舉個例子,如果當前節點 A 標記的距離為 6,將其與相鄰節點 B 連接的邊的長度為 2,則通過 A 到達 B 的距離為 6+2=8。如果 B 之前被標記的距離大於 8,則將其改為 8。否則,保持其當前的值。
當我們考察完當前節點的所有未訪問節點時,將當前節點標記為已訪問,並將其移出未訪問集。已訪問節點不會再次進行檢查。
如果目標節點已被標記為已訪問(當規劃兩個特定節點之間的路由時)或未訪問集中節點之間的最小暫定距離為無窮時(當規劃一次完整的遍歷時;當初始節點與剩餘的未訪問節點之間沒有連接時才會出現這種情況),那麼就停止操作。算法結束。
否則,選擇標記有最小暫定距離的未訪問節點,將其設置為新的「當前節點」,然後回到步驟 3。
更多有關最短路徑問題的介紹請參閱:https://en.wikipedia.org/wiki/Shortest_path_problem# Returns shortest path between each node
nx.shortest_path(G_karate)
{0: {0: [0],
1: [0, 1],
2: [0, 2],
...
# Returns shortest path length between each node
list(nx.all_pairs_shortest_path_length(G_karate))
[(0,
{0: 0,
1: 1,
2: 1,
3: 1,
4: 1,
...
from networkx.algorithms import tree
mst = tree.minimum_spanning_edges(G_karate, algorithm='prim', data=False)
edgelist = list(mst)
sorted(edgelist)
[(0, 1),
(0, 2),
(0, 3),
(0, 4),
(0, 5),
(0, 6),
...
計算網絡中所有已有邊的居間性。
移除居間性最高的邊。
移除該邊後,重新計算所有邊的居間性。
重複步驟 2 和 3,直到不再剩餘邊。
from networkx.algorithms import communityk = 1
comp = community.girvan_newman(G_karate)for communities in itertools.islice(comp, k):
print(tuple(sorted(c) for c in communities))
([0, 1, 3, 4, 5, 6, 7, 10, 11, 12, 13, 16, 17, 19, 21], [2, 8, 9, 14, 15, 18, 20, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33])
如上給出的那樣,這個方法實在沒法擴展。由於這個原因,Louvain 等方法已被開發出來。但是,如果要運行大規模的圖,這些方法需要很長的時間。在定義 Louvain 方法之前,需要介紹一下模塊性(modularity)的概念。模塊性是一個度量,衡量的是分組被劃分為聚類的程度:這個現在可能看起來有些讓人迷惑。事實上,我們現在唯一做的事情是將最近的節點劃分為分組,以便我們優化模塊性指標。注意,Louvain 方法沒有理論上的保證,但實踐效果很好。Louvain 方法是 networkx 的一個子項目,參閱:https://python-louvain.readthedocs.io/en/latest/pip install python-louvain
然後,計算最佳的劃分方式(基於 Louvain 方法):import community
partition = community.best_partition(G_karate)pos = nx.spring_layout(G_karate)
plt.figure(figsize=(8, 8))
plt.axis('off')
nx.draw_networkx_nodes(G_karate, pos, node_size=600, cmap=plt.cm.RdYlBu, node_color=list(partition.values()))
nx.draw_networkx_edges(G_karate, pos, alpha=0.3)
plt.show(G_karate)
nx.is_weakly_connected(G)
nx.is_strongly_connected(G)
nx.is_connected(G_karate)
一定要看看 networkx 文檔中有關連接性實現的問題:https://networkx.github.io/documentation/stable/reference/algorithms/component.html在分層聚類(hierarchical clustering)中,我們構建聚類的層次結構。我們用樹狀圖的形式表示聚類。其思想是以不同的規模分析社群結構。我們通常自下而上構建樹狀圖。我們從每個節點一個聚類開始,然後合併兩個「最近」的節點。但我們如何衡量聚類是否相近呢?我們使用相似度距離。令 d(i,j) 為 i 和 j 之間的最短路徑的長度。要得到最大連接,在每個步驟,被最短距離分開的兩個聚類被組合到一起。相似度距離可用以下示意圖闡釋:回到我們的空手道示例。在應用分層聚類之前,我們需要定義每個節點之間的距離矩陣。pcc_longueurs=list(nx.all_pairs_shortest_path_length(G_karate))
distances=np.zeros((n,n))# distances[i, j] is the length of the shortest path between i and j
for i in range(n):
for j in range(n):
distances[i, j] = pcc_longueurs[i][1][j]
from sklearn.cluster import AgglomerativeClusteringclustering = AgglomerativeClustering(n_clusters=2,linkage='average',affinity='precomputed').fit_predict(distances)
nx.draw(G_karate, node_color = clustering)
局部聚類係數是以節點 i 為中心的三角形的數量與以節點 i 為中心的三節點的數量的比。某種程度而言,這衡量的是節點 i 與其相鄰節點接近完備圖(complete graph)的程度。全局聚類係數衡量的是圖中三角形(局部聚類)的密度:對於 Erdos-Rényi 隨機圖,E[Clustering Coefficient]=E[Ci]=p,其中 p 是前一篇文章中定義的概率。對於 Baràbasi-Albert 隨機圖,全局聚類係數根據節點的數量遵循冪律。度為 k 的節點的平均聚類係數正比於 k 的倒數:度較低的節點連接的是它們社群中的其它節點。度較高的節點連接的是其它社群的節點。對於一個給定的圖,在 networkx 中,聚類係數很容易算出。首先,我們來計算局部聚類係數:# List of local clustering coefficients
list(nx.clustering(G_barabasi).values())
0.13636363636363635,
0.2,
0.07602339181286549,
0.04843304843304843,
0.09,
0.055384615384615386,
0.07017543859649122,
...
# Global clustering coefficient
np.mean(list(nx.clustering(G_barabasi).values()))
nx.pagerank(G_karate, alpha=0.9)
其中 alpha 是阻尼參數(默認為 0.85)。這應該能返回一個排名列表:{0: 0.09923208031303203,
1: 0.0543403155825792,
2: 0.05919704684187155,
3: 0.036612460562853694,
...
c_degree = nx.degree_centrality(G_karate)
c_degree = list(c_degree.values())
c_eigenvector = nx.eigenvector_centrality(G_karate)
c_eigenvector = list(c_eigenvector.values())
c_closeness = nx.closeness_centrality(G_karate)
c_closeness = list(c_closeness.values())
c_betweenness = nx.betweenness_centrality(G_karate)
c_betweenness = list(c_betweenness.values())
# Plot the centrality of the nodes
plt.figure(figsize=(18, 12))# Degree Centrality
f, axarr = plt.subplots(2, 2, num=1)
plt.sca(axarr[0,0])
nx.draw(G_karate, cmap = plt.get_cmap('inferno'), node_color = c_degree, node_size=300, pos=pos, with_labels=True)
axarr[0,0].set_title('Degree Centrality', size=16)# Eigenvalue Centrality
plt.sca(axarr[0,1])
nx.draw(G_karate, cmap = plt.get_cmap('inferno'), node_color = c_eigenvector, node_size=300, pos=pos, with_labels=True)
axarr[0,1].set_title('Eigenvalue Centrality', size=16)# Proximity Centrality
plt.sca(axarr[1,0])
nx.draw(G_karate, cmap = plt.get_cmap('inferno'), node_color = c_closeness, node_size=300, pos=pos, with_labels=True)
axarr[1,0].set_title('Proximity Centrality', size=16)# Betweenness Centrality
plt.sca(axarr[1,1])
nx.draw(G_karate, cmap = plt.get_cmap('inferno'), node_color = c_betweenness, node_size=300, pos=pos, with_labels=True)
axarr[1,1].set_title('Betweenness Centrality', size=16)
Neo4j 的圖算法全面指南,Mark Needham & Amy E. Hodler:https://go.neo4j.com/rs/710-RRC-335/images/Comprehensive-Guide-to-Graph-Algorithms-in-Neo4j-ebook-EN-US.pdf
Networkx 文檔:https://networkx.github.io/documentation/stable/
原文連結:https://towardsdatascience.com/graph-algorithms-part-2-dce0b2734a1d