天天看點

手把手:一張圖看清程式設計語言發展史,你也能用Python畫出來!

今天文摘菌要教大家制作一張程式設計語言的關系網絡圖。如果不知道什麼是關系網絡圖,可以點選下方連結先來看一下最終成果:

http://programming-languages.herokuapp.com/#,

我們可以在這裡看到從過去到現在的250多種程式設計語言之間的“設計影響”的關系,下面是該示範的截圖:

手把手:一張圖看清程式設計語言發展史,你也能用Python畫出來!

接下來,就讓我們一起來學做這個關系網絡圖吧!

在當今的超連接配接世界,網絡在現代生活中無處不在。舉個栗子,文摘菌的周末這樣開啟——通過北京的交通網絡進城,然後去最喜歡的咖啡店的一家分店,并将筆記本連上他們的Wi-Fi。接下來,登入各種常用的社交網站。

衆所周知,在過去幾十年來最有影響力的公司中,有一部分是因為網絡的力量而獲得成功。

Facebook、Twitter、Instagram、LinkedIn以及一些其他的社交媒體平台都依賴社交網絡的小世界特性。這使他們能有效地将使用者彼此(以及和廣告商)之間連接配接起來。

谷歌目前的成功主要歸因于他們早期在搜尋引擎市場上的主導地位——部分原因是他們有能力通過他們的Page Rank網絡算法來傳回相關的結果。

亞馬遜的高效配送網絡使他們能夠在一些主要城市提供當天發貨。

網絡算法在人工智能和機器學習等領域也是非常重要的。神經網絡領域的研究非常熱門。計算機視覺中許多必不可少的特征檢測算法,在很大程度上也是依賴于使用網絡來對圖像的不同部分進行模組化。

網絡模型也可以解釋大量的科學現象,包括有量子力學、生化途徑以及生态和社會經濟系統等。

那麼,鑒于它們不可否認的重要性,我們應該如何更好地了解網絡及其屬性呢?

網絡的數學研究被稱為“圖論”,是數學中較易了解的分支之一。 本文會介紹簡單的網絡知識,即便你沒有相關背景知識也能輕松學會。

此外,我們将使用Python 3.x和一款非常棒的開源軟體Gephi,通過關系網絡将過去和現在的一系列程式設計語言的網絡可視化聯系起來。

首先,究竟什麼是網絡呢?

其實上面文摘菌舉的栗子已經給了一些線索。交通網絡由目的和路徑的連接配接組成。社交網絡通過個人和個人之間的關系進行連接配接。Google的搜尋引擎算法通過檢視有哪些頁面連結到其他頁面,來評估不同網頁的“順序”。

更一般地說,網絡是可以用節點和邊描述的任何系統,或者通俗來講,就是我們所說的“點和線”。

手把手:一張圖看清程式設計語言發展史,你也能用Python畫出來!

邊連接配接節點(語言)的例子(該網絡表示了程式設計語言互相影響的關系)

有些系統以這種方式建立網絡比較容易。社交網絡也許是最明顯的例子。計算機檔案系統則是另一種方式——檔案夾和檔案通過其“父”和“子”關系建立連接配接。

但是,網絡的真正威力其實在于,許多系統都可以從網絡的角度來模組化,即使這起初并不明顯。

代表網絡

我們應該如何将點和線的圖檔轉換成我們可以壓縮的數字信号呢?

其中有一個解決方案是繪制一個鄰接矩陣來表示我們的網絡。

如果你不熟悉矩陣這個概念,這聽起來可能有點吓人,但不要害怕。 把它們想象成可以一次執行許多計算的數字網格就好。下面是一個簡單的例子:

手把手:一張圖看清程式設計語言發展史,你也能用Python畫出來!

在這個矩陣中,每個行和列的交集都是0或1,這取決于各個語言是否被連結。你也可以根據上面的插圖觀察到!

對于要解決的大多數問題而言,矩陣是以數學方式表示網絡的好方法。然而從計算的角度來看,它有時可能會有點麻煩。

例如,即使節點數量相對較少(比如說有1000個),矩陣中的元素數目也會大得多(例如,1000^2 = 1,000,000)。

許多現實世界的系統會産生稀疏網絡,在這些網絡中,大多數節點隻能連接配接其他所有節點中的一小部分。

如果我們将計算機記憶體中1000個節點的稀疏網絡表示為鄰接矩陣,那麼我們将在RAM中存儲1,000,000個位元組的資料。大多數将會是零。這裡有一個更為有效的方法可以解決這個問題。

這種方法是使用邊清單來代替鄰接矩陣。這些正是他們所說的,它們隻是一個節點對互相連結的清單。

表示網絡的另一種手段是鄰接表,它列出了每個節點後面與它進行連結的節點。例如:

手把手:一張圖看清程式設計語言發展史,你也能用Python畫出來!

收集資料,建立連接配接

任何網絡模型以及可視化的表現都取決于建構網絡本身所用的資料品質好壞。除了確定資料是準确和完整的同時,我們也需要一種推斷節點之間邊的合理方法。

這是相當關鍵的一步,随後對網絡進行的任何分析和推斷都取決于“關聯标準”的合理性。

例如,在社交網絡分析中,你可能會根據人們是否在社交媒體上互相關聯來建立人與人之間的聯系。在分子生物學中,你可能會基于基因的共同表達建立連接配接。

通常,我們還可以給邊配置設定權重,進而展現關系的“強度”。

例如,對于網上零售的情況,可以根據産品被同時購買的頻率來計算權重。用高權重的邊連接配接經常被同時購買的産品,用低權重的邊連接配接偶爾被同時購買的産品。和偶爾被同時購買的産品相比,那些不會被同時購買的産品根本就不會被網絡連接配接。

正如你想的那樣,将節點彼此連接配接的方法有可能很複雜。

但是對于本教程,我們将使用更簡單的方式連接配接程式設計語言。我們要依靠維基百科。

維基百科所取得的的成功證明了它的可靠性。文章寫作的開源合作方法也應該保證一定程度的客觀性。

而且,它的頁面結構相對一緻,使其成為試用網頁抓取技術的便利場所。

另一個便利工具是覆寫面廣泛的、有據可查的維基百科API,這使得資訊檢索更容易。接下來讓我們一起開始吧。

第一步:安裝Gephi

Gephi可在Linux、Mac和Windows的環境下進行安裝。

對于這個項目,我使用了Lubuntu。如果你使用的是Ubuntu / Debian,那麼你可以按照下面的步驟來啟動和運作Gephi。如果不是,那麼安裝過程也不會差太多。

下載下傳最新版本的Gephi到你的系統(在撰寫本文時是v.0.9.1)。準備就緒後,你需要提取檔案。

手把手:一張圖看清程式設計語言發展史,你也能用Python畫出來!

你可能需要檢查你的Java JRE版本。Gephi需要最新版本。在我剛剛安裝的Lubuntu上,我隻安裝了default-jre,下面的一切将建立在此基礎上。

手把手:一張圖看清程式設計語言發展史,你也能用Python畫出來!

在你準備好進行安裝之前還有一步。為了将圖表導出到Web,你可以使用Gephi的Sigma.js插件。

從Gephi的菜單欄中選擇“工具”選項,然後選擇“插件”。

點選“可用插件”标簽并選擇“SigmaExporter”(我也安裝了JSON導出器,因為它是另一個有用的插件)。

點選“安裝”按鈕,你将完成整個安裝過程。安裝結束後,你需要重新啟動Gephi。

第二步:編寫Python腳本

本教程将使用python 3.x以及一些子產品來進行簡化。使用pip子產品安裝程式,需運作一下指令:

手把手:一張圖看清程式設計語言發展史,你也能用Python畫出來!

現在,在一個新的目錄中,建立一個名為script.py的檔案,并在你最喜歡的代碼編輯器/ IDE中打開它。以下是主要邏輯的大綱:

首先,你需要有一個程式設計語言的清單。

接下來,通過該清單并檢索維基百科相關文章的HTML。

從中提取出每種語言所影響的程式設計語言清單。這是我們連接配接節點的粗略标準。

同時,我們可以抓取一些關于每種語言的中繼資料。

最後,将收集的所有資料寫入一個.csv檔案。

完整的腳本在這裡:

(https://gist.github.com/anonymous/2a6c841fe04ebc6d55acc259b4ac4f72)。

導入子產品

在script.py中,首先導入一些子產品。

手把手:一張圖看清程式設計語言發展史,你也能用Python畫出來!

準備好後——從建立一個節點的清單開始。這是Wikipedia子產品派上用場的地方。它使得通路維基百科API非常容易。

添加下面的代碼:

手把手:一張圖看清程式設計語言發展史,你也能用Python畫出來!

儲存并運作上面的腳本,将看到列印出“List of programming languages”維基百科文章中的所有連結。

另外,還需要手動檢查自動收集的資料。快速浏覽後我們可以發現,除了許多實際的程式設計語言之外,該腳本還提供了一些額外的連結。

如:可能會看到“List of markup languages”,“Comparison of programming languages”等。

雖然Gephi允許你移除不想包含的節點,但為了節省時間,還是讓我們先進行一輪資料清洗。

手把手:一張圖看清程式設計語言發展史,你也能用Python畫出來!

這些代碼定義了要從資料中移除的子字元串清單。運作該腳本時周遊資料,移除所有包含不需要的子字元串的元素。

在Python語言中,完成這些隻需要一行代碼!

其他輔助函數

現在我們可以開始從wikipedia抓取資料并建立一個邊清單(并收集所有中繼資料)。為了更簡便,讓我們首先定義一些函數。

抓取HTML

第一個函數使用BeautifulSoup子產品來擷取每種語言的Wikipedia頁面的HTML。

手把手:一張圖看清程式設計語言發展史,你也能用Python畫出來!

這個函數使用urllib.request子產品來擷取“https://en.wikipedia.org/wiki/”+“程式設計語言”頁面的HTML。

然後傳給BeautifulSoup,它将讀取HTML并解析為一個可以用來搜尋資訊的對象。

接下來,使用find_all()方法抓取感興趣的HTML元素。

下面,是每種程式設計語言文章頂部的彙總表。該如何識别呢?

最簡單的方法是通路其中一個程式設計語言頁面。在這裡,可以簡單地使用浏覽器的開發工具來檢查感興趣的元素。彙總表有HTML标記<table>和CSS類“infobox”和“vevent”,是以可以使用這些來辨別HTML中的表格。

用參數指定它:

手把手:一張圖看清程式設計語言發展史,你也能用Python畫出來!

find_all()傳回符合标準的所有元素清單。為了指定感興趣的元素,需要添加索引[0]。如果函數執行成功,則傳回table對象,否則,傳回None。

手把手:一張圖看清程式設計語言發展史,你也能用Python畫出來!

在使用了自動資料收集程式的情況下,全面的異常處理是非常重要的。如果沒有,那麼在最好的情況下如果腳本崩潰了,資料抓取程式需要重新開始執行。

在最壞的情況下,你獲得資料集将包含不一緻性和錯誤,這将為你後續的工作買下隐患。

檢索中繼資料

下一個函數使用table對象來查找一些中繼資料。下面給出在表格中搜尋語言第一次出現的年份的代碼。

手把手:一張圖看清程式設計語言發展史,你也能用Python畫出來!

這個簡短的函數以table對象作為參數,并調用BeautifulSoup的get_text()函數生成一個字元串。

下一步是建立一個名為year的子字元串。該字元串存儲了在“appear”這個詞首次出現之後的30個字元。這個字元串應該包含語言第一次出現的年份。

為了僅提取年份,使用正規表達式(通過re子產品)來比對任何以1到3之間的數字開頭、并緊鄰三個數字的字元串。

手把手:一張圖看清程式設計語言發展史,你也能用Python畫出來!

如果執行成功,函數将傳回一個整數的year。否則,我們會得到“Could not determine”。你可能還想進一步挖掘中繼資料,例如範例,設計者或打字規律。

收集連結

我們還需要一個函數–該函數讀入給定語言的table對象,輸出一個包含其他程式設計語言的清單。

手把手:一張圖看清程式設計語言發展史,你也能用Python畫出來!

仔細觀察上面代碼中嵌套部分,到底是怎麼回事呢?

這個函數利用了table對象具有結構一緻性的事實。表中的資訊存儲在行中(相關的HTML标簽是<tr>)。其中一行包含文字“\ nInfluenced \ n”。函數的第一部分查找這是哪一行。

一旦找到這一行,就可以确定下一行包含了被目前行影響的每種程式設計語言的連結。使用find_all(“a”)便可查找這些連結 - 其中參數“a”對應于HTML标簽<a>。

對于每個連結j,将其[“title”]屬性添加到名為out的清單。對[“title”]屬性感興趣的原因是因為它将完全比對存儲在節點中的語言名稱。

例如,Java作為“Java(程式設計語言)”存儲在節點中,是以需要在整個資料集中使用這個确切的名稱。

如果執行成功,getLinks()将傳回一組程式設計語言。該函數的其餘部分進行了異常處理,以防程式在某一階段出現問題。

收集資料

最後,在一切準備就緒後執行腳本,收集資料并将其存儲在兩個清單對象中。

手把手:一張圖看清程式設計語言發展史,你也能用Python畫出來!

現在編寫一個循環,将先前定義的函數應用于nodes中的每個詞條,并将輸出存儲在edgeList和meta中。

手把手:一張圖看清程式設計語言發展史,你也能用Python畫出來!

該函數使用節點中的每種語言,并嘗試從維基百科頁面檢索彙總表。

然後,該函數将檢索表中列出的與目智語言所關聯的全部語言。

對于同時出現在節點清單中的每種語言,将一個元素以[“source,target”]的形式添加到edgeList。通過這種方式,建立一個邊的清單傳給Gephi。

出于調試的目的,列印添加到edgeList的每個元素——這樣做僅僅為了確定一切都工作。如果想要更徹底地調試,也可以添加列印語句到except語句中。

接下來,擷取語言的名稱和年份,并将其添加到元清單中。

寫進CSV檔案

一旦循環運作,最後一步是将edgeList和meta的内容寫入到CSV檔案。通過使用前面導入的csv子產品,完成上一步驟就容易多了。

手把手:一張圖看清程式設計語言發展史,你也能用Python畫出來!

完成了!儲存腳本,并從終端運作:

$ python3 script.py

當建構邊清單時,你可以看到腳本輸出了source-target對。確定網絡連接配接的穩定性後,你就可以坐等結果了,此時腳本将發揮其魔力。

第三步:用Gephi建立圖形

希望你已經安裝并運作了Gephi。現在你可以建立一個新項目,并使用你收集的資料來建構有向圖。有向圖将顯示不同的程式設計語言是如何互相影響的!

首先在Gephi中建立一個新項目,然後切換到“資料實驗室”視窗。Gephi中提供了一個擴充式的接口來處理資料。首先要導入清單。

點選“導入電子表格”。

選擇由Python腳本生成的edge_list.csv檔案。確定Gephi中使用逗号作為分隔符。

從清單類型中選擇“邊清單”

點選“下一步”,導入源和目标列作為字元串,并檢查。

用一個節點清單來更新資料實驗室。現在,導入 metadata.csv檔案。這一次,從清單類型中選擇“節點清單”。

切換到“Preview”頁籤,檢視網絡的外觀。

這時的圖形看起來顔色十分單一,而且雜亂無章,就像一盤意大利面。是以我們接下來要進行圖像美化。

圖像美化

我們可以通過各種方式來示範圖像,也可以盡情發揮自己的創意。另外,關于網絡可視化還要考慮以下三件事情:

節點定位:生成網絡布局模式的算法有很多,比較流行的是fruchterman - reingold算法,而且Gephi支援該算法。

節點大小:圖中節點的大小可以用來表示一些有趣的屬性。通常,這是一個中心性度量。度量中心性的方法有很多,但它們都反映了給定節點的“重要性”,即它與網絡的其他部分關聯的緊密程度。

節點着色:我們還可以使用顔色來顯示節點的某些屬性。通常,顔色用來表示群落結構,廣泛定義為“與圖的其餘部分相比關聯更緊密的一組節點”。在社交網絡中,群落結構可以揭示個人的友情、家庭或專業團體之間的關聯。有幾種算法可以檢測群落結構,Gephi自帶的檢測算法是Louvain方法。

要執行上述步驟,還需要計算一些統計資料。切換到“Overview”視窗。在這裡你可以看到右側的一個面闆。它包含一個“Statistics”頁籤。打開它,你将看到一系列選項。

Gephi具有許多内置的統計功能。對于每種功能,點選“Run”将生成一個報告,該報告揭示了關于網絡的一些洞見。

如果要修改網絡的外觀,我們可以轉向左邊的面闆。

在“Layout”頁籤中,可以選擇要使用的布局算法。點選“運作”,實時觀看圖表的變化!看看你認為哪種布局算法效果最好。

在Layout頁籤之上是“Appearance”頁籤。在這裡,你可以為節點和各條邊的顔色、大小和标簽進行設定,也可以根據資料的屬性來配置(包括你要計算的資料)。

一個建議:

根據子產品化屬性将節點着色。着色的根據是節點的群落成員關系。

根據節點的平均程度來确定節點的大小。關聯緊密的節點會比關聯稀疏的節點顯得大。

不過,也可以嘗試設計一個最喜歡的布局。一旦對圖形外觀感到滿意,就可以進入最後一個步驟——将圖形導出至網頁!

第四步:使用Sigma.js插件

既然已經建構了一個可以在Gephi中檢視的網絡可視化,接下來可以選擇使用螢幕截圖,或者以SVG、PDF或PNG格式儲存圖形。

如果已經安裝了Sigma.js插件,也可以把圖形導出到HTML,這将會建立一個互動式可視化,不僅可以線上上釋出,也可以上傳到GitHub,與他人分享。

可從Gephi的菜單欄選擇“Export >Sigma.js模闆…”。

按要求填寫詳細資訊。確定選擇導出項目所在的目錄。你也可以更改圖形的标題、圖例、描述、懸停和許多其他細節。當你準備好了,點選“确定”。

現在,如果你打開導出項目所在的目錄,你将看到一個檔案夾,其中包含Sigma.js生成的所有檔案。

在你最喜歡的浏覽器打開index.html檔案。哈!你的網絡!如果你知道一些CSS和JavaScript,可以載入各種生成的檔案到你的網絡中,以便按照你的意願調整輸出的網絡。

腦洞開一開,網絡畫起來

許多系統可以作為網絡進行模組化和可視化。圖論是數學的一個分支,它提供了幫助了解網絡結構和屬性的工具。

使用Python從Wikipedia擷取資料,建構程式設計語言影響圖。關聯标準是一種給定的語言是否能被列為對設計另一種語言的影響。

Gephi和Sigma.js是分析和可視化網絡的開源工具。它們可以讓你以圖像、PDF或Web格式導出網絡。

模仿本文的方法,你還可以為很多其他的關系模組化并做出可視化。腦洞開一開,網絡畫起來。

原文釋出時間為:2018-01-12

本文作者:文摘菌