在圖形資料函式庫中,資料的複雜度往往很高,直接分析相當困難。圖投影技術提供一種簡化圖形結構的方法,方便提取關鍵資訊。本文將介紹如何利用 Neo4j 和 Python 的 igraph 函式庫建立和分析圖投影,並探討一些常見的錯誤和除錯技巧。首先,我們會在 Neo4j 中建立電影和共同演員的投影,接著使用 igraph 和 Cypher 進行分析,包含度分佈、連通分量和派系等。同時,我們也會探討一些常見的 igraph 和 Neo4j 使用錯誤,例如節點不存在、邊緣新增錯誤以及 Cypher 查詢的效能問題,並提供解決方案。透過這些例項,讀者可以更深入地理解圖投影的應用和分析技巧,並提升在圖形資料函式庫上的實作能力。
在Neo4j中建立投影以進行複雜分析
在上一節中,我們成功地在Python中使用igraph函式庫對Neo4j中的複雜知識圖譜進行了投影,提取了共同演員的關係。本文將繼續深入,展示如何在Neo4j資料函式庫中直接建立投影,以便長期儲存和重複使用。
為什麼在Neo4j中建立投影?
雖然在Python中進行投影允許進行高階資料分析,但這種投影是儲存在記憶體中的,因此不是永續性的。如果需要重複存取投影或長期儲存,使用像Neo4j這樣的圖資料函式庫來儲存投影會更合適。
在Neo4j中建立投影的步驟
建立索引:首先,為新的
Film節點建立索引,以加速根據電影名稱的查詢。使用以下Cypher查詢:CREATE INDEX film FOR (f:Film) ON f.name這將為
Film節點的name屬性建立索引,大大加快相關查詢的速度。使用APOC外掛建立投影:接下來,利用APOC外掛中的
apoc.periodic.iterate()函式來建立投影。這個函式可以將查詢操作分成批次執行,避免一次性載入過多資料到記憶體中。CALL apoc.periodic.iterate( "MATCH (film1:Entity)-[:STARRING]->(actor:Entity)<-[:STARRING]-(film2:Entity) RETURN film1, film2", "MERGE (f1:Film {name:film1.name}) MERGE (f2:Film {name:film2.name}) MERGE (f1)-[:HAS_COMMON_ACTORS]->(f2)", {batchSize:1000, parallel:false} )內容解密:
- 第一個Cypher查詢匹配具有共同演員的電影對,並傳回這些電影節點。
- 第二個Cypher查詢為每對匹配的電影建立新的
Film節點(如果尚未存在),並在它們之間建立HAS_COMMON_ACTORS關係。 batchSize:1000表示每批次處理1000條記錄,parallel:false關閉平行處理,以避免因節點鎖定導致的錯誤。
新增額外屬性:投影建立後,可以為節點新增額外屬性。例如,將電影的拍攝國家資訊從原始圖譜轉移到投影中的
Film節點上。
實施細節與注意事項
- 批次大小與平行處理:選擇適當的批次大小和是否啟用平行處理取決於具體資料量和系統資源。過大的批次可能導致記憶體問題,而平行處理則可能因節點鎖定而失敗。
- 索引的重要性:在進行大規模資料操作前建立適當的索引,可以顯著提高查詢和更新效率。
- 資料一致性:在進行資料遷移或更新時,確保資料的一致性和完整性是非常重要的。
完美投影的實務應用
在前面的章節中,我們已經成功地在 Neo4j 中建立了一個以共同演員和國家為基礎的電影投影。現在,是時候利用這個投影來進行一些實際的分析,以獲得對電影和演員的深入洞察。
分析 igraph 演員投影
首先,讓我們回到 Python 和我們的共同演員圖表。我們使用 Python 和 Neo4j API 查詢知識圖譜,並傳回在同一部電影中共同演出的演員。然後,我們將結果轉換為邊緣列表,並匯入 igraph 以進行圖表分析。
- 檢查圖表的基本屬性:首先,我們來瞭解一下我們的共同演員圖表的基本屬性。我們可以透過存取 igraph 圖表物件
g的vs和es屬性來取得節點和邊緣的數量。
print(len(g.vs)) print(len(g.es))
從結果中,我們可以看到我們的圖表大約有 82,000 個節點和超過 140 萬條邊緣,使其成為一個相當密集的連線圖。
2. **計算度分佈**:接下來,讓我們計算演員節點的度分佈。這在原始知識圖譜中是很難做到的,但是在我們的投影中卻很簡單。我們可以使用 `degree()` 方法來計算每個節點的邊緣數量。
```python
degree = g.degree(igraph_ids.values())
- 繪制度分佈直方圖:為了更好地瞭解圖表的結構,我們可以繪製度分佈的直方圖。使用
matplotlib.pyplot的hist()方法,我們可以建立一個直方圖,並使用對數尺度來顯示 y 軸。
import matplotlib.pyplot as plt plt.hist(g.degree(), bins=20, edgecolor=’#1260CC’, color=’#3A9BDC’) plt.xlabel(‘節點度’) plt.ylabel(‘頻率’) plt.yscale(’log’) plt.show()
這張圖表顯示了節點度的頻率分佈,直觀地展示了我們的共同演員圖表的結構。
#### 程式碼解析:
```python
import matplotlib.pyplot as plt
# 取得節點度
degree = g.degree()
# 繪製直方圖
plt.hist(degree, bins=20, edgecolor='#1260CC', color='#3A9BDC')
# 設定標籤
plt.xlabel('節點度')
plt.ylabel('頻率')
# 使用對數尺度
plt.yscale('log')
# 顯示圖表
plt.show()
內容解密:
- 匯入必要的函式庫:我們匯入了
matplotlib.pyplot來繪製圖表。 - 取得節點度:使用
g.degree()取得每個節點的度。 - 繪製直方圖:使用
plt.hist()繪製節點度的直方圖,並設定了邊緣顏色和填充顏色。 - 設定標籤:使用
plt.xlabel()和plt.ylabel()設定 x 軸和 y 軸的標籤。 - 使用對數尺度:使用
plt.yscale('log')將 y 軸設定為對數尺度,以便更好地顯示頻率分佈。 - 顯示圖表:最後,使用
plt.show()顯示繪製好的圖表。
透過這些步驟,我們成功地分析和視覺化了我們的共同演員圖表,為進一步的研究和分析奠定了基礎。
投影的實際應用
分析共同演員關係圖的特徵
在建立了共同演員(co-star)投影後,我們可以進一步分析其圖結構特徵。首先觀察的是該圖的度分佈(degree distribution),如圖8.6所示:
圖8.6:共同演員投影的度分佈
此圖示呈現了共同演員關係圖中節點的度分佈,顯示出長尾特徵。這意味著大多數演員僅與少數其他演員合作,而少數演員則與數千名演員有合作關係。
進一步檢視度分佈的長尾部分,我們發現三位演員節點具有不成比例的大量合作關係。接下來,我們將識別這些演員。
程式碼範例:計算並排序演員的度
degree = g.degree()
actor_degree = list(zip(degree, g.vs['actor']))
actor_degree = sorted(actor_degree, key=lambda x: x[0], reverse=True)
print(actor_degree[:3])
內容解密:
g.degree()用於計算圖中每個節點的度,即每個演員的合作人數。zip(degree, g.vs['actor'])將每個節點的度和對應的演員名稱配對,形成列表。- 使用
sorted()函式對列表進行排序,依據度大小進行降序排列。 - 輸出前三名具有最多合作關係的演員及其度數。
結果顯示,Moe Howard、Larry Fine和Mithun Chakraborty是資料集中合作最廣泛的演員,每人約有3,000個合作關係。
探索連通分量
另一個值得探討的圖特徵是連通分量(connected components)的數量。執行弱連通分量演算法可以揭示圖是否整體連線或是分裂為多個獨立部分。
程式碼範例:計算弱連通分量
cc = g.components(mode='weak')
print(len(cc))
內容解密:
g.components(mode='weak')計算圖的弱連通分量。mode='weak'引數確保無向邊被視為連線,無論其原始方向如何。- 輸出連通分量的數量。
結果表明,該圖包含超過3,000個連通分量,表明存在許多獨立的演員群體。
進一步分析最大連通分量的大小:
程式碼範例:計算並排序連通分量的大小
cc_size = [len(component) for component in cc]
cc_size.sort(reverse=True)
print(cc_size[:10])
內容解密:
- 使用列表推導式計算每個連通分量的節點數量。
- 對分量大小進行降序排序。
- 輸出前10個最大連通分量的大小。
結果顯示,最大的連通分量包含71,115個節點,佔據了圖的大部分,而其他分量則相對較小。
分析派系(Cliques)
在圖論中,派系是指一個完全連線的子圖。在共同演員關係圖中,派系代表了一組彼此合作過的演員群體。
尋找派系可以幫助我們識別經常一起合作的演員群體。未來可進一步分析這些派系的特徵和意義。
此圖示呈現瞭如何使用投影來分析原本在知識圖譜中難以計算或解讀的特徵,展現了投影在實際應用中的價值。
圖投影分析的深度探討
在知識圖譜的分析過程中,圖投影(Graph Projection)是一種強大的工具,能夠幫助我們簡化複雜的圖結構並提取有價值的資訊。本章中,我們將探討如何使用Python和Neo4j來建立、儲存和分析圖投影,並展示它們在效率和結果解釋性方面的強大能力。
使用igraph分析共同演員投影
首先,我們使用igraph函式庫來分析共同演員(co-stars)的投影。這個投影將演員之間的合作關係簡化為一個無向圖,其中節點代表演員,邊代表他們曾經在同一部電影中合作過。
尋找最大的派系
在這個投影中,我們可以使用igraph的largest_cliques()方法來尋找最大的完全連線子圖,也就是所謂的派系(clique)。這個方法傳回一個包含派系中節點的列表。
largest_clique = g.largest_cliques()[0]
print(len(largest_clique))
print(largest_clique)
解讀最大派系的結果
透過上述程式碼,我們發現最大的派系包含了65個節點。進一步地,我們可以透過g.vs[largest_clique]['actor']來取得這些節點所對應的演員名稱。
clique_actors = g.vs[largest_clique]['actor']
print(clique_actors)
內容解密:
g.largest_cliques()[0]:這行程式碼用於取得圖中最大的派系。largest_cliques()傳回一個列表,包含所有最大的派系,而[0]則用於選取第一個(也是最大的)派系。g.vs[largest_clique]['actor']:這行程式碼用於取得最大派系中節點所對應的演員名稱。g.vs用於存取圖的節點屬性,而['actor']則指定了我們要存取的屬性名稱。
分析Neo4j中的電影投影
接下來,我們將分析Neo4j中的電影投影。這個投影包含僅Film節點,如果兩部電影有共同演員,則它們之間存在一條邊。
基本資訊統計
首先,我們透過Cypher查詢來統計圖中的節點和邊的數量。
MATCH (f:Film) RETURN count(f)
MATCH (:Film)-[r:HAS_COMMON_ACTORS]->(:Film) RETURN count(r)
分析結果解讀
透過上述查詢,我們發現圖中有79,478個Film節點和5,774,715條HAS_COMMON_ACTORS關係。如此大量的邊使得我們的圖投影具有很高的連線度。
尋找具有共同演員但拍攝地不同的電影
我們進一步分析了具有共同演員但拍攝地不同的電影對。
MATCH (f1:Film)-[:HAS_COMMON_ACTORS]->(f2:Film)
WITH f1.country as c1, f2.country as c2
WHERE c1 <> c2
WITH [c1, c2] as country_pair
RETURN country_pair, count(country_pair)
ORDER BY count(country_pair) DESC
內容解密:
MATCH (f1:Film)-[:HAS_COMMON_ACTORS]->(f2:Film):這行Cypher查詢用於匹配具有共同演員的電影對。WITH f1.country as c1, f2.country as c2:這行程式碼用於存取匹配到的電影對的拍攝地,並將它們別名為c1和c2。WHERE c1 <> c2:這行程式碼用於篩選出拍攝地不同的電影對。WITH [c1, c2] as country_pair:這行程式碼用於將拍攝地對組合成一個列表,方便後續統計。RETURN country_pair, count(country_pair):這行程式碼用於傳回拍攝地對及其出現次數。ORDER BY count(country_pair) DESC:這行程式碼用於按出現次數降序排列結果。
常見錯誤與除錯技術
在本章中,我們將探討作為一名新晉的圖形資料科學家或工程師(當你完成本文閱讀後就會具備這樣的資格)可能會遇到的常見錯誤。重點將放在如何除錯圖形相關問題上。這將引導我們探討在使用 igraph 時常見的問題和解決方法。接著,我們將研究常見的 Neo4j 問題,因為本文的大部分內容都在使用 igraph、Python 和 Neo4j;因此,瞭解如何解決圖形資料函式庫問題也是非常有用的。我們還將討論如何修改 igraph 和 Neo4j 指令碼以獲得最佳效能。
本章涵蓋的主題
- 除錯圖形問題
- 常見的 igraph 問題
- 常見的 Neo4j 問題
技術需求
我們將使用 Jupyter 筆記本執行我們的程式設計練習,這需要 python>=3.8.0,以及以下需要使用 pip install 命令安裝的套件:
- neo4j==5.5.0
- igraph==0.9.8
本章還需要安裝 Neo4j Desktop。如果尚未安裝 Neo4j,請參閱第 5 章「使用圖形資料函式庫」中的技術需求部分,因為本章的教學需要它。
除錯圖形問題
隨著圖形資料模型和分析在業界的廣泛應用,圖形資料函式庫解決方案和軟體日益受到歡迎,你很可能會遇到可以用圖形方式解決的資料問題。同時,圖形解決方案對於許多企業來說仍然是相對較新的事物,作為一名圖形資料從業者,你幾乎肯定會遇到錯誤和問題。
在這裡,我們將介紹在使用 igraph Python 函式庫時可能會遇到的一些最常見問題,以及在使用 Neo4j 時可能會遇到的一些標準錯誤和問題。每個問題都將透過一個簡短的範例來示範,以幫助你除錯自己的問題。
每個錯誤或問題都將與一個真實的範例一起展示,你可以跟著範例一起操作並解決問題。我們需要一些資料來示範在使用 Neo4j 和 Cypher 時可能會遇到的一些問題。
在本章中,我們的範例將使用從 GitHub 收集的社交網路資料。這將包括 GitHub 開發者之間的資料關係。我們的邊緣列表 musae_git_target.csv 中的每條邊代表兩個互相跟隨對方的開發者。
我們還有開發者的名字,這將是我們的節點,儲存在 musae_git_target.csv 中。我們的資料代表了一個相當大的圖形,擁有大約 38,000 個節點和近 290,000 條邊。當然,你可能會遇到各種各樣的圖形問題,就像我們迄今為止處理的所有範例資料一樣,但為了示範圍繞 igraph 和 Neo4j 中的錯誤和擴充套件性問題的一些問題,我們將使用 GitHub 社交網路。
常見的 igraph 問題
雖然 igraph 是用於圖形資料及其分析的強大函式庫,但它的許多功能來自於 Python 作為 igraph 在幕後實作的介面,而 igraph 的實作是在 C 語言中。因此,igraph 有一些需要注意的怪癖。在下面的小節中,我們將帶你瞭解在使用 Python 中的 igraph 時使用者常遇到的一些常見問題。
圖形中沒有節點
一些 Python 中的圖形和網路科學函式庫可以直接從元組列表(edgelist)建立。在 igraph 中,由於 C 語言中節點索引的實作方式,必須先將節點新增到 Graph 物件中,然後才能透過邊緣將它們連線起來。在接下來的步驟中,我們將示範這個問題以及隨後出現的錯誤:
- 首先,我們可以使用內建的 csv 模組讀取 musae_git_edges.csv 中的邊緣資料作為範例圖形載入到 igraph 中。這個檔案有標頭,所以我們在列表理解的結尾使用列表切片來移除它們:
import csv
with open('./data/musae_git_edges.csv', 'r') as c:
reader = csv.reader(c)
edges = [row for row in reader][1:]
- 此時,在許多函式庫中,你可能會直接從邊緣列表建立圖形。但是,如果我們嘗試這樣做,我們將遇到一個錯誤:
import igraph
g = igraph.Graph()
g.add_edges(edges)
這會產生以下錯誤:
ValueError: no such vertex: '0'
內容解密:
程式碼首先讀取 CSV 檔案中的邊緣資料,並將其儲存為列表。由於 CSV 檔案有標頭,因此使用列表切片
[1:]來移除第一行(標頭)。接著,程式碼嘗試直接使用
add_edges方法將邊緣新增到 igraph 圖形物件中。然而,這會導致ValueError,因為節點尚未被新增到圖形中。add_edges方法需要整數型別的節點 ID,而原始的邊緣資料是字串型別。因此,需要先將邊緣資料轉換為整數。即使轉換為整數後,直接新增邊緣仍然會導致錯誤,因為 igraph 需要先新增節點才能新增邊緣。
其實這裡有兩個問題。首先,由於我們尚未新增任何節點,因此不存在名稱為 0 的頂點。此外,我們正嘗試將字串傳遞給
add_edges(),而 igraph 與此不相容。我們可以先透過int()和列表理解將 edgelist 中的值轉換為整數來解決這個問題。然後,我們可以再次嘗試新增邊緣:
edges = [[int(edge[0]), int(edge[1])] for edge in edges]
g.add_edges(edges)
這仍然無法正常運作,並會出現新的錯誤:
igraph._igraph.InternalError: Error at src/graph/type_indexedgelist.c:261: Out-of-range vertex IDs when adding edges. -- Invalid vertex ID
現在,當我們的邊緣列表中有一個節點 ID 在圖形中尚不存在時,就會出現這個錯誤。在 igraph 中,我們必須始終在新增邊緣之前先將節點新增到圖形中。
內容解密:
- 程式碼嘗試將轉換為整數後的邊緣資料新增到圖形中,但仍然遇到錯誤。
- 錯誤訊息指出頂點 ID 超出範圍,這意味著圖形中不存在某些節點 ID。
- 這是因為 igraph 需要先建立節點,才能新增與這些節點相關的邊緣。
- 因此,在新增邊緣之前,需要先建立包含所有必要節點的圖形。