5大必知的圖演算法,附Python程式碼實現

2019-09-16 11:27:21


作者 | Rahul Agarwal
譯者 | Monanfei
編輯 | Jane
出品 | AI科技大本營(ID:rgznai100)


作為資料科學家,我們已經對 Pandas 或 SQL 等其他關係資料庫非常熟悉了。我們習慣於將行中的使用者視為列。但現實世界的表現真的如此嗎?
 
在互聯世界中,使用者不能被視為獨立實體。他們之間具有一定的關係,在構建機器學習模型時,有時也希望包含這樣的關係。
 
在關係型資料庫中,我們無法在不同的行(使用者)之間使用這種關係,但在圖形資料庫中,這樣做是相當簡單的。在這篇文章中將為大家介紹一些重要的圖演算法,以及Python 的程式碼實現。


1、連通分量

 
具有三個連通分量的圖
 
將上圖中的連通分量演算法近似看作一種硬聚類演算法,該演算法旨在尋找相關資料的簇類。舉一個具體的例子:假設擁有連線世界上任意城市的路網資料,我們需要找出世界上所有的大陸,以及它們所包含的城市。我們該如何實現這一目標呢?
 
基於BFS / DFS的連通分量演算法能夠達成這一目的,接下來,我們將用 Networkx 實現這一演算法。
 

程式碼

使用 Python 中的 Networkx 模組來建立和分析圖資料庫。如下面的示意圖所示,圖中包含了各個城市和它們之間的距離資訊。
 
示意圖
 
首先建立邊的列表,列表中每個元素包含兩個城市的名稱,以及它們之間的距離。
 
edgelist = [['Mannheim', 'Frankfurt', 85], ['Mannheim', 'Karlsruhe', 80], ['Erfurt', 'Wurzburg', 186], ['Munchen', 'Numberg', 167], ['Munchen', 'Augsburg', 84], ['Munchen', 'Kassel', 502], ['Numberg', 'Stuttgart', 183], ['Numberg', 'Wurzburg', 103], ['Numberg', 'Munchen', 167], ['Stuttgart', 'Numberg', 183], ['Augsburg', 'Munchen', 84], ['Augsburg', 'Karlsruhe', 250], ['Kassel', 'Munchen', 502], ['Kassel', 'Frankfurt', 173], ['Frankfurt', 'Mannheim', 85], ['Frankfurt', 'Wurzburg', 217], ['Frankfurt', 'Kassel', 173], ['Wurzburg', 'Numberg', 103], ['Wurzburg', 'Erfurt', 186], ['Wurzburg', 'Frankfurt', 217], ['Karlsruhe', 'Mannheim', 80], ['Karlsruhe', 'Augsburg', 250],["Mumbai", "Delhi",400],["Delhi", "Kolkata",500],["Kolkata", "Bangalore",600],["TX", "NY",1200],["ALB", "NY",800]]
 
然後,使用 Networkx 建立圖:
g = nx.Graph()for edge in edgelist:    g.add_edge(edge[0],edge[1], weight = edge[2])
 
現在,我們想從這張圖中找出不同的大陸及其包含的城市。我們可以使用使用連通分量演算法來執行此操作:
 
for i, x in enumerate(nx.connected_components(g)):    print("cc"+str(i)+":",x)------------------------------------------------------------cc0: {'Frankfurt', 'Kassel', 'Munchen', 'Numberg', 'Erfurt', 'Stuttgart', 'Karlsruhe', 'Wurzburg', 'Mannheim', 'Augsburg'}cc1: {'Kolkata', 'Bangalore', 'Mumbai', 'Delhi'}cc2: {'ALB', 'NY', 'TX'}

從結果中可以看出,只需使用邊緣和頂點,我們就能在資料中找到不同的連通分量。 該演算法可以在不同的資料上執行,以滿足前文提到的兩種其他運用。
 

應用

 
  • 零售:很多客戶使用大量賬戶,可以利用連通分量演算法尋找資料集中的不同簇類。假設使用相同信用卡的客戶 ID 存在連邊(edges),或者將該條件替換為相同的住址,或者相同的電話等。一旦我們有了這些連線的邊,就可以使用連通分量演算法來對客戶 ID 進行聚類,並對每個簇類分配一個家庭 ID。然後,通過使用這些家庭 ID,我們可以根據家庭需求提供個性化建議。此外,通過建立基於家庭的分組功能,我們還能夠提高分類演算法的效能。

 
  • 財務:我們可以利用這些家庭 ID 來識別金融欺詐。如果某個賬戶曾經有過欺詐行為,那麼它的關聯帳戶很可能發生欺詐行為。

 

2、最短路徑

 
繼續第一節中的例子,我們擁有了德國的城市群及其相互距離的圖表。為了計算從法蘭克福前往慕尼黑的最短路徑,我們需要用到 Dijkstra 演算法。Dijkstra 是這樣描述他的演算法的:
 
從鹿特丹到格羅寧根的最短途徑是什麼?或者換句話說:從特定城市到特定城市的最短路徑是什麼?這便是最短路徑演算法,而我只用了二十分鐘就完成了該演算法的設計。 一天早上,我和未婚妻在阿姆斯特丹購物,我們逛累了,便在咖啡館的露臺上喝了一杯咖啡。而我,就想著我能夠做到這一點,於是我就設計了這個最短路徑演算法。正如我所說,這是一個二十分鐘的發明。事實上,它發表於1959年,也就是三年後。它之所以如此美妙,其中一個原因在於我沒有用鉛筆和紙張就設計了它。後來我才知道,沒有鉛筆和紙的設計的一個優點就是,你幾乎被迫避免所有可避免的複雜性。最終,這個演算法讓我感到非常驚訝,而且也成為了我名聲的基石之一。

——Edsger Dijkstra
於2001年接受ACM通訊公司 Philip L. Frana 的採訪時的回答
 

程式碼

print(nx.shortest_path(g, 'Stuttgart','Frankfurt',weight='weight'))print(nx.shortest_path_length(g, 'Stuttgart','Frankfurt',weight='weight'))--------------------------------------------------------['Stuttgart', 'Numberg', 'Wurzburg', 'Frankfurt']503

使用以下命令可以找到所有對之間的最短路徑: 
for x in nx.all_pairs_dijkstra_path(g,weight='weight'):    print(x)--------------------------------------------------------('Mannheim', {'Mannheim': ['Mannheim'], 'Frankfurt': ['Mannheim', 'Frankfurt'], 'Karlsruhe': ['Mannheim', 'Karlsruhe'], 'Augsburg': ['Mannheim', 'Karlsruhe', 'Augsburg'], 'Kassel': ['Mannheim', 'Frankfurt', 'Kassel'], 'Wurzburg': ['Mannheim', 'Frankfurt', 'Wurzburg'], 'Munchen': ['Mannheim', 'Karlsruhe', 'Augsburg', 'Munchen'], 'Erfurt': ['Mannheim', 'Frankfurt', 'Wurzburg', 'Erfurt'], 'Numberg': ['Mannheim', 'Frankfurt', 'Wurzburg', 'Numberg'], 'Stuttgart': ['Mannheim', 'Frankfurt', 'Wurzburg', 'Numberg', 'Stuttgart']})('Frankfurt', {'Frankfurt': ['Frankfurt'], 'Mannheim': ['Frankfurt', 'Mannheim'], 'Kassel': ['Frankfurt', 'Kassel'], 'Wurzburg': ['Frankfurt', 'Wurzburg'], 'Karlsruhe': ['Frankfurt', 'Mannheim', 'Karlsruhe'], 'Augsburg': ['Frankfurt', 'Mannheim', 'Karlsruhe', 'Augsburg'], 'Munchen': ['Frankfurt', 'Wurzburg', 'Numberg', 'Munchen'], 'Erfurt': ['Frankfurt', 'Wurzburg', 'Erfurt'], 'Numberg': ['Frankfurt', 'Wurzburg', 'Numberg'], 'Stuttgart': ['Frankfurt', 'Wurzburg', 'Numberg', 'Stuttgart']})....

應用

  • Dijkstra 演算法的變體在 Google 地圖中廣泛使用,用於計算最短的路線。
  • 想象身處在沃爾瑪商店,我們知道了各個過道之間的距離,我們希望為從過道 A 到過道 D 的客戶提供最短路徑。


  • 如下圖所示,當我們知道了領英中使用者的一級連線、二級連線時,如何得知幕後的資訊呢?Dijkstra 演算法可以幫到我們。
 

 

3、最小生成樹

 
假設我們在水管工程公司或網際網路光纖公司工作,我們需要使用最少的電線(或者管道)連線圖表中的所有城市。我們如何做到這一點?
 
無向圖和它的最小生成樹
 

程式碼

# nx.minimum_spanning_tree(g) returns a instance of type graphnx.draw_networkx(nx.minimum_spanning_tree(g))

使用最小生成樹演算法鋪設電線
 

應用

  • 最小生成樹在網路設計中有著最直接的應用,包括計算機網路,電信網路,運輸網路,供水網路和電網。(最小生成樹最初就是為此發明的)
  • 最小生成樹可用於求解旅行商問題的近似解
  • 聚類——首先構造最小生成樹,然後使用類間距離和類內距離來設定閾值,從而破壞最小生成樹中的某些連邊,最終完成聚類的目的
  • 影象分割——首先在圖形上構建最小生成樹,其中畫素是節點,畫素之間的距離基於某種相似性度量(例如顏色,強度等),然後進行圖的分割。
 

4、網頁排序(Pagerank)


 
Pagerank 是為谷歌提供長期支援的頁面排序演算法。根據輸入和輸出連結的數量和質量,該演算法對每個頁面進行打分。
 

程式碼

在本節中,我們將使用 Facebook 資料。首先,利用 Facebook 使用者之間的連線,我們使用以下方法建立圖:
# reading the datasetfb = nx.read_edgelist('../input/facebook-combined.txt', create_using = nx.Graph(), nodetype = int)

將圖進行視覺化:
pos = nx.spring_layout(fb)import warningswarnings.filterwarnings('ignore')plt.style.use('fivethirtyeight')plt.rcParams['figure.figsize'] = (20, 15)plt.axis('off')nx.draw_networkx(fb, pos, with_labels = False, node_size = 35)plt.show()

 
現在,我們想要找到具有高影響力的使用者。直觀上來講,Pagerank 會給擁有很多朋友的使用者提供更高的分數,而這些使用者的朋友反過來會擁有很多朋友。
pageranks = nx.pagerank(fb)print(pageranks)------------------------------------------------------{0: 0.006289602618466542, 1: 0.00023590202311540972, 2: 0.00020310565091694562, 3: 0.00022552359869430617, 4: 0.00023849264701222462,........}
 
使用如下程式碼,我們可以獲取排序後 PageRank 值,或者最具有影響力的使用者:
import operatorsorted_pagerank = sorted(pagerank.items(), key=operator.itemgetter(1),reverse = True)print(sorted_pagerank)------------------------------------------------------[(3437, 0.007614586844749603), (107, 0.006936420955866114), (1684, 0.0063671621383068295), (0, 0.006289602618466542), (1912, 0.0038769716008844974), (348, 0.0023480969727805783), (686, 0.0022193592598000193), (3980, 0.002170323579009993), (414, 0.0018002990470702262), (698, 0.0013171153138368807), (483, 0.0012974283300616082), (3830, 0.0011844348977671688), (376, 0.0009014073664792464), (2047, 0.000841029154597401), (56, 0.0008039024292749443), (25, 0.000800412660519768), (828, 0.0007886905420662135), (322, 0.0007867992190291396),......]
 
將含有最具影響力使用者的子圖進行視覺化:
first_degree_connected_nodes = list(fb.neighbors(3437))second_degree_connected_nodes = []for x in first_degree_connected_nodes:    second_degree_connected_nodes+=list(fb.neighbors(x))second_degree_connected_nodes.remove(3437)second_degree_connected_nodes = list(set(second_degree_connected_nodes))subgraph_3437 = nx.subgraph(fb,first_degree_connected_nodes+second_degree_connected_nodes)pos = nx.spring_layout(subgraph_3437)node_color = ['yellow' if v == 3437 else 'red' for v in subgraph_3437]node_size =  [1000 if v == 3437 else 35 for v in subgraph_3437]plt.style.use('fivethirtyeight')plt.rcParams['figure.figsize'] = (20, 15)plt.axis('off')nx.draw_networkx(subgraph_3437, pos, with_labels = False, node_color=node_color,node_size=node_size )plt.show()

黃色的節點代表最具影響力的使用者
 

應用

Pagerank 可以估算任何網路中節點的重要性。
 
  • 已被用於根據引文尋找最具影響力的論文
  • 已被谷歌用於網頁排名
  • 它可以對推文進行排名,其中,使用者和推文作為網路的節點。如果使用者 A 跟隨使用者 B,則在使用者之間建立連邊;如果使用者推文或者轉發推文,則在使用者和推文之間建立連邊。
  • 用於推薦系統
 

5、中心性度量

一些中心性度量的指標可以作為機器學習模型的特徵,我們主要介紹其中的兩個指標,其餘的指標可以參考這個連結。 
https://networkx.github.io/documentation/networkx-1.10/reference/algorithms.centrality.html#current-flow-closeness
 
  • 介數中心性:擁有最多朋友的使用者很重要,而起到橋樑作用、將一個領域和另一個領域進行連線的使用者也很重要,因為這樣可以讓更多的使用者看到不同領域的內容。介數中心性衡量了特定節點出現在兩個其他節點之間最短路徑集的次數。

 
  • 度中心性:即節點的連線數。

 

程式碼

使用下面的程式碼可以計運算元圖的介數中心性:
pos = nx.spring_layout(subgraph_3437)betweennessCentrality = nx.betweenness_centrality(subgraph_3437,normalized=True, endpoints=True)node_size =  [v * 10000 for v in betweennessCentrality.values()]plt.figure(figsize=(20,20))nx.draw_networkx(subgraph_3437, pos=pos, with_labels=False,                 node_size=node_size )plt.axis('off')

 
如上圖所示,節點的尺寸大小和介數中心性的大小成正比。具有較高介數中心性的節點被認為是資訊的傳遞者,移除任意高介數中心性的節點將會撕裂網路,將完整的圖打碎成幾個互不連通的子圖。
 

應用

中心性度量的指標可以作為機器學習模型的特徵。
 

總結

在這篇文章中,我們介紹了了一些最有影響力的圖演算法。隨著社交資料的出現,圖網路分析可以幫助我們改進模型和創造價值,甚至更多地瞭解這個世界。最後,貼上本文程式碼地址。
 
程式碼地址:
https://www.kaggle.com/mlwhiz/top-graph-algorithms


原文連結:
https://towardsdatascience.com/data-scientists-the-five-graph-algorithms-that-you-should-know-30f454fa5513
 

(*本文為AI科技大本營編譯文章,轉載請聯絡微信 1092722531)


推薦閱讀

  • 谷歌NIPS論文Transformer模型解讀:只要Attention就夠了

  • 阿里雲彈性計算負責人蔣林泉:億級場景驅動的技術自研之路

  • 開源sk-dist,超引數調優僅需3.4秒,sk-learn訓練速度提升100倍

  • 你在北邊的西二旗被水淹沒,我在東邊的八通線不知所措

  • 為什麼說邊緣計算的發展比5G更重要?

  • C/C++ 最易受攻擊、70% 漏洞無效,揭祕全球開源元件安全現狀

  • 首批共享單車死於2019

  • 公鑰加密、加密Hash雜湊、Merkle樹……區塊鏈的密碼學你知多少?


你點的每個“在看”,我都認真當成了喜歡

已同步到看一看



熱點新聞