[譯] 基於 Python 的圖論和網路分析

Yuqi發表於2019-03-19

引論

“一張照片包含了萬千資訊”,這句話常常被人們引用。但是一張圖能表達的資訊要更多。以圖的形式視覺化資料,幫助我們獲得了更可行的見解,並基於此作出更好的資料驅動的決策。

但是,為了真正理解圖到底是什麼,以及為什麼我們要使用它,我們還需要知道圖論的概念。知道了這個,可以幫助我們更好的程式設計。

[譯] 基於 Python 的圖論和網路分析

如果你之前曾經學習過圖論,你一定知道你需要學習成千上萬的公式和枯燥的理論概念。所以我們決定寫這篇部落格。我們會首先解釋概念然後提供說明示例,方便你跟上我們的進度,並直觀的理解函式是如何運作的。本篇部落格會寫的很詳細,因為我們相信,提供正確的解釋,是一種比只給出簡單定義更受歡迎的選擇。

在本篇文章中,我們會了解圖是什麼,它的應用,以及一些圖的歷史。同時文章中也會涵蓋一些圖論概念,然後我們會學習一個基於 Python 的示例,來鞏固理解。

準備好了嗎?那我們開始進入學習吧!

目錄

  • 圖及圖的應用
  • 圖的歷史以及我們為什麼選擇圖?
  • 你需要知道的術語
  • 圖論基礎概念
  • 熟悉 Python 中的圖
  • 基於資料集的分析

圖及圖的應用

讓我們先來觀察一個如下所示的簡單的圖,從而幫助理解概念:

[譯] 基於 Python 的圖論和網路分析

設想這個圖代表了城市中人們經常會光顧的不同地點,然後一位城市遊客按照這個路徑行進。我們設定 V 表示地點,E 表示地點之間的路徑

V = {v1, v2, v3, v4, v5}

E = {(v1,v2), (v2,v5), (v5, v5), (v4,v5), (v4,v4)}
複製程式碼

邊 (u,v) 和邊 (v,u) 是一樣的 —— 它們是無序數對。

具體來講 —— 圖是一種用來學習物件間和實體間配對關係的數學結構。它是離散數學的一個分支,並且在電腦科學、化學、語言學、運籌學、社會學等多個領域有廣泛的應用。

資料科學和分析領域也同樣使用圖來模擬不同的結構和問題。作為一個資料學的科學家,你應該能夠以高效的方法來解決問題,而在很多場景下,圖就可以提供這樣高效的機制,因為資料被以一種特別的方式組織了起來。

正式來講:

  • 由兩個集合組成。G = (V,E)。V 是一個頂點集合。E 是一個邊的集合。E 是 V 中元素對組合而來的(無序對)。
  • 有向圖也是集合的配對。D = (V,A)。V 是頂點的集合。A 是弧的集合。A 是 V 中元素配對組合(有序對)。

如果是有向圖,那麼 (u,v)(v,u) 就是有區別的。這時,邊被稱為弧,來表明方向的概念。

R 和 Python 中有很多用圖論來分析資料的庫。在本篇文章中,我們將會使用 Networkx Python 包來簡單的學習一些這方面的概念,並做一些資料分析。

from IPython.display import Image
Image('images/network.PNG')
複製程式碼

[譯] 基於 Python 的圖論和網路分析

Image('images/usecase.PNG')
複製程式碼

[譯] 基於 Python 的圖論和網路分析

在上面的例子中可以很清晰的看出,圖在資料分析中的應用非常廣泛。我們來看幾個案例:

  • 市場分析 —— 圖能夠用於找出社交網中最具有影響力的人。廣告商和營銷人員能夠通過將資訊引導至社交網路中最有影響力的人那裡,來試圖獲取最大的營銷效益。
  • 銀行交易 —— 圖能夠用於找出不同尋常的交易者,幫助減少欺詐交易。曾經在很多案例中,恐怖分子的活動都被國際銀行網路中貨幣流分析監測到了。
  • 供給鏈 —— 圖能幫助找出運送貨物的最優路線,還能幫助選定倉庫和運送中心的位置。
  • 製藥 —— 製藥公司可以使用圖論來優化推銷員的路線。這樣可以幫助推銷員降低成本,並縮短旅途時間。
  • 電信 —— 電信公司通常會使用圖(Voronoi 圖)來計算出訊號塔的數量和位置,並且還能夠保證最大覆蓋面積。

圖的歷史以及我們為什麼選擇圖?

圖的歷史

如果你想知道圖的理論是如何被建立起來的 —— 繼續讀下去吧!

圖論的起源可以追溯到七橋(Konigsberg bridge)問題(大約在 1730 年左右)。這個問題提出,哥尼斯堡城裡的七座橋是否能夠在滿足以下條件的前提下全部被走過一遍:

  • 路徑無重複
  • 路徑結束的地方恰好就是你開始的位置

這個問題等同於,有四節點和七邊的圖是否能擁有一個尤拉圓(尤拉圓指的是,一個開始點和終止點相同的尤拉路徑。而尤拉路徑指的是,在圖中恰好通過每一條邊一次的路徑。更多的術語將在下文介紹)。這個問題引出了尤拉圖的概念。而關於哥尼斯堡橋問題,答案是不能,第一個回答出這個問題的人正是尤拉,你一定已經猜到了。

在 1840 年,A.F Mobius 給出了完全圖和二分圖的概念,同時 Kuratowski 通過 recreational 問題證明了它們都是平面圖。樹的概念(無環全連線圖)則在 1845 被 Gustav Kirchhoff 提出,並且他在計算電網或電路中的電流時使用了圖論的思想。

在 1852 年,Thomas Gutherie 建立了著名的四色問題。而後在 1856 年,Thomas. P. Kirkman 和 William R.Hamilton 共同在多面體上研究圓環,並通過研究如何找出通過指定的每個點僅一次的路徑,建立了哈密頓圖的概念。1913 年,H.Dudeney 也提到了一個難題。儘管四色問題很早就被提出,而在一個世紀後才被 Kenneth Appel 和 Wolfgang Haken 解答。這個時間才被認為是圖論的誕生時間。

Caley 研究了微分學的特定分析形式,從而研究樹結構。這在理論化學上已經有了很多應用。這也激發了列舉圖論的建立。而在 1878 年,Sylvester 在“量子不變數”與代數和分子圖的協變數之間進行了類比時,使用了“圖”這個術語。

在 1941 年,Ramsey 研究了著色問題,從而引出了圖論另一個分支的定義,即極值圖論。在 1969 年,四色問題被 Heinrich 通過計算機解決。漸進圖的學習也連帶著激發了隨機圖論的發展。圖論和拓撲學的歷史同樣緊密相關,它們之間有很多共同的概念和理論。

Image('images/Konigsberg.PNG', width = 800)
複製程式碼

[譯] 基於 Python 的圖論和網路分析

為什麼選擇圖?

以下幾點可以激勵你在日常資料科學問題中使用圖論:

  1. 在處理抽象概念,例如關係和互動問題時,圖是更好的方法。同時,在你思考這些概念時,它也提供了更直觀且可視的方法。而在分析社會關係時,圖也自然成了基礎。
  2. 圖行資料庫已經成為了很常見的計算機工具,它是 SQL 和 NoSQL 資料庫的替代。
  3. 圖的一種:DAGs(有向無環圖),能夠被應用於模型化分析流。
  4. 一些神經網路框架也使用 DAGs 來對不同層的各個操作建模。
  5. 圖論被用來學習和模型化社交網路、欺詐模型、功率模型、社交媒體中的病毒性和影響力。社交網路分析(SNA)也許是圖論在資料科學中最有名的應用。
  6. 它被用於聚類演算法 —— 最知名的是 K-Means 演算法。
  7. 系統動力學也會應用一些圖論的概念 —— 最知名的是迴圈。
  8. 路徑優化是優化問題的一個子集,它也使用了圖的概念。
  9. 從電腦科學的角度來看 —— 圖讓計算更加高效。和表格資料相比,如果資料以圖的方式排列,一些演算法的複雜度能夠更低。

你需要知道的術語

在繼續深入之前,我們建議你熟悉下面這些術語。

  1. 頂點 uv 被稱為邊 (u,v)端點end vertices
  2. 如果兩條邊有相同的端點,那麼它們被稱為平行的
  3. 形如 (v,v) 的邊是一個
  4. 如果一個圖沒有平行邊也沒有環,則它被稱為簡單圖
  5. 如果一個圖沒有邊,那麼稱這個圖為Empty)。也就是 E 是空的
  6. 一個圖如果沒有頂點,那麼稱之為空圖Null Graph)。也就是 VE 全都是空的
  7. 只有一個頂點的圖稱為平凡圖Trivial graph)
  8. 如果兩條邊有一個公共頂點,則它們是相鄰Adjacent)邊。如果兩個頂點有一條公共邊,則它們是相鄰頂點
  9. 頂點的,寫作d(v),表示以該頂點作為端點的的數量。按照慣例,環對應端點的度為邊的兩倍,平行邊分別對應的兩個端點的度都要加
  10. 度為 1 的頂點稱為孤立頂點(Isolated Vertices)。d(1) 的頂點是孤立的。
  11. 如果一個圖的邊集包含了所有端點可能組合成的邊,則稱這個圖為完全圖(Complete)
  12. 圖中點和邊是有限的,可替換的序列 ViEiViEi 稱為圖 G = (V,E) 的一個路徑Walk
  13. 如果路徑的開始頂點和結束頂點是不同的,那麼稱這個路徑是開放的(Open)。而如果開始頂點和結束頂點相同,則稱為閉合的(Closed
  14. 每個邊最多通過一次的跡(Trail)稱為路徑
  15. 每個頂點最多通過一次的路徑(Path)稱為跡(除了閉路)
  16. 閉合的路徑是閉環(Circuit)—— 類似於一個電路

圖論基礎概念

在這個章節中,我們將會學習一些資料分析相關的有用的概念(內容不分先後)。記住,本文章涉及的內容之外還有很多需要深度學習的概念。現在讓我們開始吧。

平均路徑長度

所有可能的配對點的平均最短路徑長度。它給圖了一個“緊密”程度的度量,可以被用於描述網路中流的快慢/是否易於通過。

BFS 和 DFS

寬度優先搜尋深度優先搜尋是兩個用於搜尋圖中節點的不同的演算法。它們通常用於檢視從已知節點出發,是否能找到某個節點。也被稱為圖的遍歷

BFS 的目標是依次搜尋距離根節點最近的節點以遍歷圖,而 DFS 的目標是依次搜尋距離根節點儘可能遠的節點,從而遍歷圖。

中心性

它的用途最廣泛,並且是網路分析最重要的概念工具。中心性的目標是找到網路中最重要的節點。如何定義“重要”可以多種方式,所以就有很多中心的度量方法。中心性的度量方法本身就有分類(或者說中心度量方法的類別)。有的是通過邊的流量來度量,而有的則通過圖的路徑結構。

一些最常見的應用如下:

  1. 度中心性 —— 第一個也是概念上最簡單的中心性定義。它表示一個點連線的邊的數量。在一個有向圖的例子中,我們則可以有兩種度中心性的衡量方式。出度和入度的中心性。
  2. 臨近中心性 —— 從該節點出發,到所有節點的平均路徑長度最短。
  3. 中介中心性 —— 該節點出現在另外兩個節點之間最短路徑中的次數。

這些中心性度量各有不同,它們的定義可以應用於不同的演算法中。總而言之,這意味著會引出大量的定義和演算法。

網路密度

圖中有多少邊的度量。定義會隨著圖的種類以及問題所處的情景而變化。對於一個完全無向圖,則網路密度為 1,而對於一個空圖,度則為 0。圖的網路密度在一些場景下也可以大於一(比如圖中包含環的時候)。

圖形隨機化

一些圖的指標定義也許很容易計算,但是想要弄清楚它們的相關重要性卻並不容易。這時我們就會用到網路/圖形隨機化。我們同時計算當前圖和另一個隨機生成的相似圖的某個指標。相似性可以是圖的度和節點數量相等。通常情況下,我們會生成 1000 個相似的隨機圖,並計算每個圖的指標,然後將結果與手頭上的圖的相同指標進行對比,以得出基準概念。

在資料科學領域中,當你嘗試對圖作出某個宣告的時候,將它與隨機生成的圖做對比將會很有幫助。

熟悉 Python 中的圖

我們將會使用 Python 的 networkx 工具包。如果你使用的是 Python 的 Anaconda 發行版,則它可以被安裝在 Anaconda 的根環境下。你也可以使用 pip install 來安裝。

下面我們來看看使用 Networkx 包能做的一些事情。包括引入和建立圖,以及圖的視覺化。

建立圖

import networkx as nx

# 建立一個圖
G = nx.Graph() # 現在 G 是空的

# 新增一個節點
G.add_node(1)
G.add_nodes_from([2,3]) # 你也能通過傳入一個列表來新增一系列的節點

# 新增邊
G.add_edge(1,2)

e = (2,3)
G.add_edge(*e) # * 表示解包元組
G.add_edges_from([(1,2), (1,3)]) # 正如節點的新增,我們也可以這樣新增邊
複製程式碼

點和邊屬性可以隨著它們的建立被新增,方法是傳入一個包含了點和屬性的字典。

除了一個一個點或者一條一條邊的來建立圖,還可以通過應用經典的圖操作來建立,例如:

subgraph(G, nbunch)      - 生成由節點集合 nbunch 組成的 G 的子圖
union(G1,G2)             - 求圖的並集
disjoint_union(G1,G2)    - 圖中所有不同節點組成的單元
cartesian_product(G1,G2) - 返回笛卡爾積圖(Cartesian product graph)
compose(G1,G2)           - 兩圖中都有的點所組成的圖
complement(G)            - 補圖
create_empty_copy(G)     - 返回同一個圖的空副本
convert_to_undirected(G) - 返回圖的無向形式
convert_to_directed(G)   - 返回圖的有向形式
複製程式碼

對於不同類別的圖,有單獨的類。例如類 nx.DiGraph() 支援新建有向圖。包含特定路徑的圖也可以使用某一個方法直接建立出來。如果想了解所有的建立圖的方法,可以參見文件。參考列表在文末給出。

Image('images/graphclasses.PNG', width = 400)
複製程式碼

[譯] 基於 Python 的圖論和網路分析

獲取邊和節點

圖的所有邊和節點可以使用方法 G.nodes()G.edges() 獲取。單獨的邊和節點可以使用括號/下標的方式獲取。

G.nodes()
複製程式碼

NodeView((1, 2, 3))

G.edges()
複製程式碼

EdgeView([(1, 2), (1, 3), (2, 3)])

G[1] # 與 G.adj[1] 相同
複製程式碼

AtlasView({2: {}, 3: {}})

G[1][2]
複製程式碼

{}

G.edges[1, 2]
複製程式碼

{}

圖形視覺化

Networkx 提供了基礎的圖的視覺化功能,但是它的主要目標是分析圖而不是圖的視覺化。圖的視覺化比較難,我們將會使用專門針對它的特殊工具。Matplotlib 提供了很多方便的函式。但是 GraphViz 則可能是最好的工具,因為它以 PyGraphViz 的形式提供了 Python 介面(下面給出了它的文件連結)。

%matplotlib inline
import matplotlib.pyplot as plt
nx.draw(G)
複製程式碼

[譯] 基於 Python 的圖論和網路分析

首先你需要從網站安裝 Graphviz(如下是下載連結)。然後執行 pip install pygraphviz --install-option=" <>。在安裝選項中你需要提供 Graphviz 的庫和依賴的資料夾地址。

import pygraphviz as pgv
d={'1': {'2': None}, '2': {'1': None, '3': None}, '3': {'1': None}}
A = pgv.AGraph(data=d)
print(A) # 這是圖的字串形式或者簡單展示形式
複製程式碼

Output:

strict graph "" {
	1 -- 2;
	2 -- 3;
	3 -- 1;
}
複製程式碼

PyGraphviz 提供了對邊和節點的每個屬性的強大掌控能力。我們可以用它得到非常美觀的視覺化圖形。

# 讓我們建立另一個圖,我們可以控制它每個節點的顏色
B = pgv.AGraph()

# 設定所有節點的共同屬性
B.node_attr['style']='filled'
B.node_attr['shape']='circle'
B.node_attr['fixedsize']='true'
B.node_attr['fontcolor']='#FFFFFF'

# 建立並設定每個節點不同的屬性(使用迴圈)
for i in range(16):
	B.add_edge(0,i)
	n=B.get_node(i)
	n.attr['fillcolor']="#%2x0000"%(i*16)
	n.attr['height']="%s"%(i/16.0+0.5)
	n.attr['width']="%s"%(i/16.0+0.5)
B.draw('star.png',prog="circo") # 這行程式碼會在本地建立一個 .png 格式的檔案。如下所示。

Image('images/star.png', width=650) # 我們所建立的圖的視覺化圖片
複製程式碼

[譯] 基於 Python 的圖論和網路分析

通常情況下,視覺化被認為是圖分析的一個獨立任務。分析後的圖形會匯出為點檔案。然後這個點檔案被另做視覺化處理,來展示我們試圖證明的觀點。

基於資料集的分析

我們將會學習一個通用資料集(並不是專門用於圖分析的),然後做一些操作(使用 panda 庫),這樣資料才能以邊列表的形式被插入到圖中。邊列表是一個元組的列表,包含了定義每一條邊的頂點對。

這個資料集來自於航空業。它包含了航線的一些基本資訊,以及旅程和目的地的資源,對於每個旅程還包含了幾欄到達和起飛時間的說明。你能夠想象,這個資料集本身就非常適合作為圖來分析。想象一下航線(邊)連線城市(節點)。如果你在運營航空公司,接下來你可以問如下這幾個問題

  1. 從 A 到 B 的最近路程是什麼?路程最短的是哪條?時間最短的是哪條?
  2. 從 C 到 D 有路徑可以通過嗎?
  3. 哪些機場的交通壓力最大?
  4. 處於最多機場之間的是哪個機場?那麼它就可以作為當地樞紐
import pandas as pd
import numpy as np

data = pd.read_csv('data/Airlines.csv')
複製程式碼
data.shape
(100, 16)
複製程式碼
data.dtypes

year                int64
month               int64
day                 int64
dep_time          float64
sched_dep_time      int64
dep_delay         float64
arr_time          float64
sched_arr_time      int64
arr_delay         float64
carrier            object
flight              int64
tailnum            object
origin             object
dest               object
air_time          float64
distance            int64
dtype: object
複製程式碼
  1. 我們注意到,將起始點和終點作為節點是一個很好的選擇。這樣所有的資訊都可以作為節點或者邊的屬性了。一條邊可以被認為是一段旅程。這段旅程將會和不同的時間、航班號、飛機尾號等等相關聯。
  2. 我們注意到,年月日和其他時間資訊被分散在好幾欄中。我們希望建立一個能包含所有這些資訊時間欄,我們也需要分別儲存預計和實際的到達和出發時間。最終,我們應該有 4 個時間欄(預計和實際的到達和出發時間)
  3. 另外,時間欄的格式並不合適。下午的 4:30 被表示為 1630 而不是 16:30。該欄中並沒有分隔符來分割資訊。其中一個方法是使用 pandas 庫的字串方法和正規表示式。
  4. 我們也要注意,sched_dep_time 和 sched_arr_time 是 int64 資料型別的,而 dep_time 和 arr_time 是 float64 資料型別的
  5. 另一個複雜的因素是 NaN 值
# 將 sched_dep_time 轉化為 'std' —— 預計起飛時間
data['std'] = data.sched_dep_time.astype(str).str.replace('(\d{2}$)', '') + ':' + data.sched_dep_time.astype(str).str.extract('(\d{2}$)', expand=False) + ':00'

# 將 sched_arr_time 轉化為 'sta' —— 預計抵達時間
data['sta'] = data.sched_arr_time.astype(str).str.replace('(\d{2}$)', '') + ':' + data.sched_arr_time.astype(str).str.extract('(\d{2}$)', expand=False) + ':00'

# 將 dep_time 轉化為 'atd' —— 實際起飛時間
data['atd'] = data.dep_time.fillna(0).astype(np.int64).astype(str).str.replace('(\d{2}$)', '') + ':' + data.dep_time.fillna(0).astype(np.int64).astype(str).str.extract('(\d{2}$)', expand=False) + ':00'

# 將 arr_time 轉化為 'ata' —— 實際抵達時間
data['ata'] = data.arr_time.fillna(0).astype(np.int64).astype(str).str.replace('(\d{2}$)', '') + ':' + data.arr_time.fillna(0).astype(np.int64).astype(str).str.extract('(\d{2}$)', expand=False) + ':00'
複製程式碼

現在我們有了我們期望的格式時間欄。最後,我們期望將yearmonthday 合併為一個時間欄。這一步並不是必需的,但是一旦時間被轉化為 datetime 的格式,我們可以很容易的獲取到年月日以及其他資訊。

data['date'] = pd.to_datetime(data[['year', 'month', 'day']])

# 最後,我們刪除掉不需要的欄
data = data.drop(columns = ['year', 'month', 'day'])
複製程式碼

現在使用 networkx 函式匯入資料,該函式可以直接獲取 pandas 的資料幀。正如圖的建立,這裡也有很多將不同格式的資料插入圖的方法。

import networkx as nx
FG = nx.from_pandas_edgelist(data, source='origin', target='dest', edge_attr=True,)
複製程式碼
FG.nodes()
複製程式碼

輸出:

NodeView(('EWR', 'MEM', 'LGA', 'FLL', 'SEA', 'JFK', 'DEN', 'ORD', 'MIA', 'PBI', 'MCO', 'CMH', 'MSP', 'IAD', 'CLT', 'TPA', 'DCA', 'SJU', 'ATL', 'BHM', 'SRQ', 'MSY', 'DTW', 'LAX', 'JAX', 'RDU', 'MDW', 'DFW', 'IAH', 'SFO', 'STL', 'CVG', 'IND', 'RSW', 'BOS', 'CLE'))
複製程式碼
FG.edges()
複製程式碼

輸出:

EdgeView([('EWR', 'MEM'), ('EWR', 'SEA'), ('EWR', 'MIA'), ('EWR', 'ORD'), ('EWR', 'MSP'), ('EWR', 'TPA'), ('EWR', 'MSY'), ('EWR', 'DFW'), ('EWR', 'IAH'), ('EWR', 'SFO'), ('EWR', 'CVG'), ('EWR', 'IND'), ('EWR', 'RDU'), ('EWR', 'IAD'), ('EWR', 'RSW'), ('EWR', 'BOS'), ('EWR', 'PBI'), ('EWR', 'LAX'), ('EWR', 'MCO'), ('EWR', 'SJU'), ('LGA', 'FLL'), ('LGA', 'ORD'), ('LGA', 'PBI'), ('LGA', 'CMH'), ('LGA', 'IAD'), ('LGA', 'CLT'), ('LGA', 'MIA'), ('LGA', 'DCA'), ('LGA', 'BHM'), ('LGA', 'RDU'), ('LGA', 'ATL'), ('LGA', 'TPA'), ('LGA', 'MDW'), ('LGA', 'DEN'), ('LGA', 'MSP'), ('LGA', 'DTW'), ('LGA', 'STL'), ('LGA', 'MCO'), ('LGA', 'CVG'), ('LGA', 'IAH'), ('FLL', 'JFK'), ('SEA', 'JFK'), ('JFK', 'DEN'), ('JFK', 'MCO'), ('JFK', 'TPA'), ('JFK', 'SJU'), ('JFK', 'ATL'), ('JFK', 'SRQ'), ('JFK', 'DCA'), ('JFK', 'DTW'), ('JFK', 'LAX'), ('JFK', 'JAX'), ('JFK', 'CLT'), ('JFK', 'PBI'), ('JFK', 'CLE'), ('JFK', 'IAD'), ('JFK', 'BOS')])
複製程式碼
nx.draw_networkx(FG, with_labels=True) # 圖的快照。正如我們期望的,我們看到了三個很繁忙的機場
複製程式碼

[譯] 基於 Python 的圖論和網路分析

nx.algorithms.degree_centrality(FG) # Notice the 3 airports from which all of our 100 rows of data originates
nx.algorithms.degree_centrality(FG) # 從一百多行的所有源資料中標註出這三個機場
nx.density(FG) # 圖的平均邊度
複製程式碼

輸出:

0.09047619047619047
複製程式碼
nx.average_shortest_path_length(FG) # 圖中所有路徑中的最短平均路徑
複製程式碼

輸出:

2.36984126984127
複製程式碼
nx.average_degree_connectivity(FG) # 對於一個度為 k 的節點 —— 它的鄰居節點的平均值是什麼?
複製程式碼

輸出:

{1: 19.307692307692307, 2: 19.0625, 3: 19.0, 17: 2.0588235294117645, 20: 1.95}
複製程式碼

很明顯的可以從上文的圖的視覺化看出 —— 一些機場之間有很多路徑。加入我們希望計算兩個機場之間可能的最短路徑。我們可以想到這幾種方法

  1. 距離最短路徑
  2. 時間最短路徑

我們能做的是,通過對比距離或者時間路徑,計算最短路徑的演算法。注意,這是一個近似的答案 —— 實際需要解決的問題是,當你到達轉機機場時可選擇的航班 + 等待轉機的時間共同決定的最短方法。這是一個更加複雜的方法,而也是人們通常用於計劃旅行的方法。鑑於本篇文章的目標,我們僅僅假設當你到達機場的時候航班恰好可以搭乘,並在計算最短路徑的時候以時間作為計算物件。

我們以 JAX 和 DFW 機場為例:

# 找到所有可用路徑
for path in nx.all_simple_paths(FG, source='JAX', target='DFW'):
	print(path)

# 站到從 JAX 到 DFW 的 dijkstra 路徑
# 你可以在這裡閱讀更多更深入關於 dijkstra 是如何計算的資訊 —— https://courses.csail.mit.edu/6.006/fall11/lectures/lecture16.pdf
dijpath = nx.dijkstra_path(FG, source='JAX', target='DFW')
dijpath
複製程式碼

輸出:

['JAX', 'JFK', 'SEA', 'EWR', 'DFW']
複製程式碼
# 我們來試著找出飛行時間的 dijkstra 路徑(近似情況)
shortpath = nx.dijkstra_path(FG, source='JAX', target='DFW', weight='air_time')
shortpath
複製程式碼

輸出:

['JAX', 'JFK', 'BOS', 'EWR', 'DFW']
複製程式碼

總結

本文只是對圖論與網路分析這一非常有趣的領域進行了很簡單的介紹。圖論的知識和 Python 包能作為任何一個資料科學家非常有價值的工具。關於上文使用的資料集,還有一系列可以提出的問題,例如:

  1. 已知費用、飛行時間和可搭乘的航班,找到兩個機場間的最短距離?
  2. 如果你正管理一家航空公司,並且你有一批飛機。你可以知道人們對航班的需求。你有權再操作兩駕飛機(或者在你的機隊中增加兩架),你將使用那兩條線路來獲取最大盈利?
  3. 你能不能重新安排航班和時間表,來優化某個特定的引數(例如時間合理性或者盈利能力)

如果你真的解決了這些問題,請在評論區評論,好讓我們知道!

網路分析將會幫助我們解決一些常見的資料科學問題,並以更大規模和抽象的方式進行視覺化。如果你想在某個特定方面瞭解更多,請留言給我們。

參考書目和引用

  1. History of Graph Theory || S.G. Shrinivas et. al
  2. Big O Notation cheatsheet
  3. Networkx reference documentation
  4. Graphviz download
  5. Pygraphvix
  6. Star visualization
  7. Dijkstra Algorithm

如果發現譯文存在錯誤或其他需要改進的地方,歡迎到 掘金翻譯計劃 對譯文進行修改並 PR,也可獲得相應獎勵積分。文章開頭的 本文永久連結 即為本文在 GitHub 上的 MarkDown 連結。


掘金翻譯計劃 是一個翻譯優質網際網路技術文章的社群,文章來源為 掘金 上的英文分享文章。內容覆蓋 AndroidiOS前端後端區塊鏈產品設計人工智慧等領域,想要檢視更多優質譯文請持續關注 掘金翻譯計劃官方微博知乎專欄

相關文章