%pip install -q torch torch-geometric networkx scikit-learn
import numpy as np
import torch
from sklearn.ensemble import RandomForestClassifier
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import cross_val_score, KFold, GroupKFold
device = 'cuda' if torch.cuda.is_available() else 'cpu'
rng = np.random.default_rng(42)
print('Device:', device)Notebook Bab 13 - Data Spasial & Graf
Notebook Bab 13 ini punya dua bagian. Bagian Demo tinggal Anda jalankan lalu amati keluarannya; bagian Mini Project berisi soal dan data yang Anda kerjakan sendiri.
Karena memakai model pretrained dan GNN, notebook ini paling praktis dijalankan di Google Colab. Isinya dua bagian: fitur spasial dengan validasi berbasis blok, lalu klasifikasi node graf yang membandingkan fitur rancangan tangan dengan GNN.
Persiapan
Section 1 - Demo
Spasial: validasi acak vs validasi berbasis blok
Target berkorelasi secara spasial (nilai di lokasi berdekatan mirip). Split acak menaruh tetangga di latih dan uji sekaligus sehingga terlalu optimistis.
n = 1500
coords = rng.uniform(0, 10, size=(n, 2))
field = np.sin(coords[:, 0]) + np.cos(coords[:, 1]) + 0.3 * rng.normal(size=n)
y = (field > np.median(field)).astype(int)
X = coords
blok = (np.floor(coords[:, 0] / 2) * 5 + np.floor(coords[:, 1] / 2)).astype(int)
rf = RandomForestClassifier(n_estimators=200, random_state=42)
acc_random = cross_val_score(rf, X, y, cv=KFold(5, shuffle=True, random_state=42)).mean()
acc_spatial = cross_val_score(rf, X, y, cv=GroupKFold(5), groups=blok).mean()
print('Random CV :', round(acc_random, 3))
print('Spatial-block CV :', round(acc_spatial, 3))Graf: fitur rancangan tangan vs GNN pada Cora
Cora adalah graf sitasi. Kita bandingkan fitur struktur rancangan tangan (derajat, clustering, core number) + regresi logistik melawan Graph Convolutional Network.
import networkx as nx
from torch_geometric.datasets import Planetoid
from torch_geometric.utils import to_networkx
ds = Planetoid(root='./cora', name='Cora')
d = ds[0]
G = to_networkx(d, to_undirected=True)
deg = dict(G.degree())
clust = nx.clustering(G)
core = nx.core_number(G)
Xg = np.array([[deg[i], clust[i], core[i]] for i in range(d.num_nodes)])
yg = d.y.numpy()
tr, te = d.train_mask.numpy(), d.test_mask.numpy()
clf = LogisticRegression(max_iter=2000).fit(Xg[tr], yg[tr])
acc_hand = float((clf.predict(Xg[te]) == yg[te]).mean())
print('Fitur graf rancangan tangan + LR:', round(acc_hand, 3))import torch.nn.functional as Fn
from torch_geometric.nn import GCNConv
class GCN(torch.nn.Module):
def __init__(self, nin, nh, nout):
super().__init__()
self.c1 = GCNConv(nin, nh)
self.c2 = GCNConv(nh, nout)
def forward(self, x, ei):
x = Fn.relu(self.c1(x, ei))
x = Fn.dropout(x, training=self.training)
return self.c2(x, ei)
model = GCN(ds.num_features, 16, ds.num_classes).to(device)
dd = d.to(device)
opt = torch.optim.Adam(model.parameters(), lr=0.01, weight_decay=5e-4)
model.train()
for epoch in range(100):
opt.zero_grad()
out = model(dd.x, dd.edge_index)
loss = Fn.cross_entropy(out[dd.train_mask], dd.y[dd.train_mask])
loss.backward(); opt.step()
model.eval()
pred = model(dd.x, dd.edge_index).argmax(dim=1)
acc_gcn = float((pred[dd.test_mask] == dd.y[dd.test_mask]).float().mean())
print('GCN (dipelajari mesin):', round(acc_gcn, 3))🔎 Amati. Fitur spasial menunjukkan pola yang sama seperti deret waktu: split acak menyesatkan karena autokorelasi spasial, jadi pakai validasi berbasis blok. Pada graf, fitur struktur rancangan tangan (derajat, clustering) hanya menangkap sinyal topologi terbatas, sedangkan GCN memadukan fitur node dengan struktur tetangga sehingga akurasinya jauh lebih tinggi. Memecah node yang bertetangga secara acak juga membocorkan informasi lewat sisi (edge).
Section 2 - Mini Project
Soal
Ulangi perbandingan klasifikasi node pada dataset Citeseer (Planetoid(name='Citeseer')).
Tugas:
- Bangun fitur graf rancangan tangan (derajat, clustering, core number, opsional centrality) + regresi logistik.
- Latih GCN dua lapis pada fitur node + struktur.
- Bandingkan akurasi keduanya dan jelaskan mengapa GNN unggul.
Luaran: kode kedua pendekatan + perbandingan akurasi + 3-4 kalimat analisis.
Kriteria penilaian: (a) memakai mask train/test bawaan (hindari leakage antar-node); (b) GCN terlatih benar; (c) analisis peran struktur graf.
# DATA AWAL (jangan diubah)
ds2 = Planetoid(root='./citeseer', name='Citeseer')
d2 = ds2[0]
print('Citeseer:', d2)# Kerjakan di sini.
# Petunjuk: pakai kembali pola fitur networkx dan kelas GCN di atas untuk d2.