教學課程
在這個學習筆記中,我們將概覽 scikit-network,一個開源的 Python 套件,可協助您在圖形上進行機器學習。
1. 安裝
安裝 scikit-network
最簡單的方法就是透過 pip
。
[1]:
# uncomment to install
# !pip install scikit-network
2. 數據
鄰接矩陣
每個包含 \(n\) 個節點的圖形都使用一個大小為 \(n \times n\) 的方形鄰接矩陣 \(A\) 表示。最簡單的形式下,矩陣 \(A\) 是二元的,且只有在節點 \(i\) 與節點 \(j\) 之間有連結時,\(A_{ij} =1\)。如果圖形無導向,矩陣 \(A\) 是對稱的。
[2]:
import numpy as np
[3]:
adjacency = np.array([[0, 1, 1, 1, 0], [1, 0, 0, 0, 1], [1, 0, 0, 1, 0], [1, 0, 1, 0, 1], [0, 1, 0, 1, 0]])
[4]:
adjacency
[4]:
array([[0, 1, 1, 1, 0],
[1, 0, 0, 0, 1],
[1, 0, 0, 1, 0],
[1, 0, 1, 0, 1],
[0, 1, 0, 1, 0]])
稀疏矩陣
在 scikit-network 中,鄰接矩陣使用 scipy 的 稀疏 CSR 格式 表示。
[5]:
from scipy import sparse
[6]:
adjacency = sparse.csr_matrix(adjacency)
[7]:
adjacency
[7]:
<5x5 sparse matrix of type '<class 'numpy.int64'>'
with 12 stored elements in Compressed Sparse Row format>
視覺化
以下是上述圖形的視覺化。
[8]:
from IPython.display import SVG
from sknetwork.visualization import visualize_graph
[9]:
# name nodes by indices
n_nodes, _ = adjacency.shape
names = np.arange(n_nodes)
[10]:
# visualization
SVG(visualize_graph(adjacency, names=names))
[10]:
有向圖
鄰接矩陣不一定對稱。可能從節點 \(i\) 到節點 \(j\) 有連線,但從節點 \(j\) 到節點 \(i\) 沒有連線。
[11]:
adjacency = np.array([[0, 1, 1, 1, 0], [0, 0, 0, 1, 1], [0, 1, 0, 0, 0], [1, 0, 0, 0, 1], [0, 1, 0, 0, 0]])
[12]:
adjacency
[12]:
array([[0, 1, 1, 1, 0],
[0, 0, 0, 1, 1],
[0, 1, 0, 0, 0],
[1, 0, 0, 0, 1],
[0, 1, 0, 0, 0]])
[13]:
adjacency = sparse.csr_matrix(adjacency)
[14]:
# visualization
SVG(visualize_graph(adjacency, names=names))
[14]:
二部圖
二部圖是在兩組節點間有邊緣的特殊圖形。二部圖可以用其雙鄰接矩陣 \(B\) 來表示,\(B\) 是連結兩組節點的矩形矩陣。當且僅當第一組的節點 \(i\) (\(B\) 的行列表示) 和第二組的節點 \(j\) (\(B\) 的欄位表示) 之間有邊緣時,\(B_{ij}=1\)。
[15]:
biadjacency = np.array([[1, 1, 0, 1, 0], [0, 0, 1, 0, 1], [1, 1, 1, 1, 0], [0, 0, 0, 1, 1]])
[16]:
biadjacency
[16]:
array([[1, 1, 0, 1, 0],
[0, 0, 1, 0, 1],
[1, 1, 1, 1, 0],
[0, 0, 0, 1, 1]])
[17]:
biadjacency = sparse.csr_matrix(biadjacency)
[18]:
biadjacency
[18]:
<4x5 sparse matrix of type '<class 'numpy.int64'>'
with 11 stored elements in Compressed Sparse Row format>
[19]:
from sknetwork.visualization import visualize_bigraph
[20]:
# name nodes by indices
n_row, n_col = biadjacency.shape
names_row = np.arange(n_row)
names_col = np.arange(n_col)
[21]:
# visualization
SVG(visualize_bigraph(biadjacency, names_row=names_row, names_col=names_col, reorder=False))
[21]:
加權圖形
邊緣的權重可以用具有非負輸入項目的鄰接矩陣 (或二部圖的雙鄰接矩陣) 來表示。
[22]:
adjacency = np.array([[0, 2, 1, 3, 0], [2, 0, 0, 0, 3], [1, 0, 0, 2, 0], [3, 0, 2, 0, 1], [0, 3, 0, 1, 0]])
[23]:
adjacency
[23]:
array([[0, 2, 1, 3, 0],
[2, 0, 0, 0, 3],
[1, 0, 0, 2, 0],
[3, 0, 2, 0, 1],
[0, 3, 0, 1, 0]])
[24]:
adjacency = sparse.csr_matrix(adjacency)
[25]:
# visualization
SVG(visualize_graph(adjacency, names=names))
[25]:
子圖形
子圖形可以透過切割鄰接矩陣輕鬆取得。
[26]:
index = [0, 2, 3, 4]
sub_adjacency = adjacency[index][:, index]
[27]:
# visualization
SVG(visualize_graph(sub_adjacency, names=names[index]))
[27]:
3. 算算法
基本工具
一些用於讀取、處理和視覺化圖形的工具可用作函式。
模組 |
說明 |
函式 |
---|---|---|
數據 |
讀取和儲存圖形 |
|
拓撲 |
連線性和結構 |
|
路徑 |
最短路徑和距離 |
|
線性代數 |
矩陣運算 |
|
公用程式 |
有用工具 |
|
視覺化 |
視覺化工具 |
|
[28]:
from sknetwork.data import karate_club
from sknetwork.utils import get_degrees
[29]:
adjacency = karate_club()
[30]:
get_degrees(adjacency)
[30]:
array([16, 9, 10, 6, 3, 4, 4, 4, 5, 2, 3, 1, 2, 5, 2, 2, 2,
2, 2, 3, 2, 2, 2, 5, 3, 3, 2, 4, 3, 4, 4, 6, 12, 17],
dtype=int32)
機器學習
Scikit-network 適用於圖形的機器學習。
每種演算法可用作具有下列方法之一的物件
fit
:根據圖形調整演算法。此方法為強制選項。predict
:預測輸出(例如:節點的標籤)。predict_proba
:預測帶有機率的輸出(例如:標籤上的機率分布)。transform
:轉換圖形。fit_predict
:套用 fit + predict。fit_predict_proba
:套用 fit + predict_proba。fit_transform
:套用 fit + transform。
輸出是物件的屬性,並帶了下底線(例如:labels_
)。
模組 |
說明 |
演算法 |
輸出 |
---|---|---|---|
分群 |
建立節點叢集 |
|
|
分類 |
對節點分類 |
|
|
GNN |
圖形神經網路 |
|
|
迴歸 |
將值指派給節點 |
|
|
階層 |
取得節點的階層表示 |
|
|
嵌入 |
取得節點的向量表示 |
|
|
排名 |
針對節點賦予重要性分數 |
|
|
連結預測 |
預測節點之間的連結 |
|
|
[31]:
from sknetwork.data import karate_club
from sknetwork.classification import DiffusionClassifier
[32]:
dataset = karate_club(metadata=True)
adjacency = dataset.adjacency
position = dataset.position
labels = dataset.labels
[33]:
classifier = DiffusionClassifier()
classifier.fit(adjacency, {node: labels[node] for node in [0, 1, 33]})
[33]:
DiffusionClassifier(n_iter=10, centering=True, scale=5)
[34]:
labels_pred = classifier.predict()
[35]:
SVG(visualize_graph(adjacency, position, labels=labels_pred))
[35]:
[36]:
probs = classifier.predict_proba()
[37]:
scores = probs[:, 1]
[38]:
SVG(visualize_graph(adjacency, position, scores=scores))
[38]:
4. 範例
在此,我們示範如何使用 scikit-network 為圖形進行分群,這張圖形最初儲存在純文字檔案中,並呈邊緣清單的形式。
資料
[39]:
# show first lines
with open('miserables.tsv', 'r') as f:
data = f.readlines()
print(''.join(data[:5]))
Myriel Napoleon
Myriel Mlle Baptistine
Myriel Mme Magloire
Myriel Countess de Lo
Myriel Geborand
載入
[40]:
from sknetwork.data import from_csv
[41]:
graph = from_csv('miserables.tsv')
[42]:
adjacency = graph.adjacency
names = graph.names
[43]:
adjacency
[43]:
<77x77 sparse matrix of type '<class 'numpy.int64'>'
with 508 stored elements in Compressed Sparse Row format>
內嵌
在此,我們計算一個 2D 內嵌以供視覺化。
[44]:
from sknetwork.embedding import Spring
[45]:
algorithm = Spring()
[46]:
position = algorithm.fit_transform(adjacency)
[47]:
SVG(visualize_graph(adjacency, position, names=names))
[47]:
分群
最後,我們使用 Louvain 演算法為該圖形進行分群。
[48]:
from sknetwork.clustering import Louvain
[49]:
algorithm = Louvain()
labels = algorithm.fit_predict(adjacency)
[50]:
SVG(visualize_graph(adjacency, position, names=names, labels=labels))
[50]:
二部圖
請注意,大多數演算法都適用於二部圖,並使用 fit
函式套用至二鄰接矩陣。我們展示電影和演員之間二部圖範例。
[51]:
# show first lines
with open('movie_actor.tsv', 'r') as f:
data = f.readlines()
print(''.join(data[:5]))
Inception Leonardo DiCaprio
Inception Marion Cotillard
Inception Joseph Gordon Lewitt
The Dark Knight Rises Marion Cotillard
The Dark Knight Rises Joseph Gordon Lewitt
[52]:
graph = from_csv('movie_actor.tsv', bipartite=True)
[53]:
biadjacency = graph.biadjacency
movies = graph.names_row
actors = graph.names_col
[54]:
algorithm = Louvain()
algorithm.fit(biadjacency)
labels_row = algorithm.labels_row_
labels_col = algorithm.labels_col_
[55]:
SVG(visualize_bigraph(biadjacency, names_row=movies, names_col=actors, labels_row=labels_row, labels_col=labels_col))
[55]: