-
Notifications
You must be signed in to change notification settings - Fork 41
Expand file tree
/
Copy pathexample_decomposition_and_classification.py
More file actions
244 lines (196 loc) · 8.08 KB
/
Copy pathexample_decomposition_and_classification.py
File metadata and controls
244 lines (196 loc) · 8.08 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
"""
Decomposition and Classification Example: Network Decomposition for Node Classification
This example demonstrates a complete workflow:
1. Load a multilayer/heterogeneous network
2. Decompose it using different heuristics
3. Generate node representations using Personalized PageRank (PPR)
4. Train classifiers to predict node labels
5. Compare performance across decomposition heuristics
This approach is useful for:
- Node classification in heterogeneous networks
- Feature extraction from network structure
- Comparing different network decomposition strategies
- Semi-supervised learning on graphs
The decomposition process extracts meaningful subgraphs (meta-paths)
that capture different aspects of the network structure.
SKIP_CI: slow - Classification workflow with multiple decompositions takes more than 10 seconds
"""
import os
import time
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.svm import SVC
from sklearn.metrics import f1_score
from sklearn.model_selection import StratifiedShuffleSplit
from py3plex.core import multinet
from py3plex.algorithms.network_classification import PPR
from py3plex.utils import get_dataset_path
print("=" * 70)
print("NETWORK DECOMPOSITION AND CLASSIFICATION")
print("=" * 70)
# Dataset configuration
dataset = get_dataset_path("imdb.gpickle")
# Check if dataset exists
if not os.path.exists(dataset):
print(f"Error: Dataset file '{dataset}' not found.")
print("This example requires the IMDB network dataset.")
print("Target nodes must have 'labels' property for classification.")
exit(1)
print(f"\nStep 1: Loading network")
print("-" * 70)
print(f" Dataset: {dataset}")
# Load the multilayer network
multilayer_network = multinet.multi_layer_network().load_network(
input_file=dataset,
directed=True,
input_type=dataset.split(".")[-1] # Detect format from extension
)
print(" [OK] Network loaded successfully!")
print("\n Network statistics:")
multilayer_network.basic_stats()
print(f"\nStep 2: Extracting decomposition cycles (meta-paths)")
print("-" * 70)
# Get unique decomposition cycles (meta-paths)
# Meta-paths are sequences of node/edge types that form meaningful patterns
# Example: Author->Paper->Author, Movie->Actor->Movie, etc.
triplet_set = list(set(multilayer_network.get_decomposition_cycles()))
print(f" Found {len(triplet_set)} unique meta-path patterns:")
for i, triplet in enumerate(triplet_set[:5], 1): # Show first 5
print(f" {i}. {triplet}")
if len(triplet_set) > 5:
print(f" ... and {len(triplet_set) - 5} more")
print(f"\nStep 3: Setting up decomposition heuristics")
print("-" * 70)
# Different heuristics for weighting meta-path importance
# Each heuristic emphasizes different structural properties
heuristics = ["idf", "tf", "chi", "ig", "gr", "delta", "rf", "okapi"]
print(" Heuristics to evaluate:")
print(" - idf: Inverse Document Frequency (rare paths weighted higher)")
print(" - tf: Term Frequency (common paths weighted higher)")
print(" - chi: Chi-squared test (statistical significance)")
print(" - ig: Information Gain (classification informativeness)")
print(" - gr: Gain Ratio (normalized information gain)")
print(" - delta: Delta measure (distributional difference)")
print(" - rf: Relevance Frequency (relevant occurrence weighting)")
print(" - okapi: Okapi BM25 (information retrieval weighting)")
print(f"\nStep 4: Decomposing network and training classifiers")
print("-" * 70)
print(" This may take several minutes...")
# Initialize results storage
df = pd.DataFrame()
total_combinations = len(heuristics)
current = 0
# Iterate through different decomposition heuristics
for decomposition in multilayer_network.get_decomposition(
heuristic=heuristics,
cycle=triplet_set
):
current += 1
# Unpack decomposition results
decomposed_network = decomposition[0] # Decomposed network
labels = decomposition[1][:, 1] # Node labels for classification
heuristic = decomposition[2] # Current heuristic name
print(f"\n [{current}/{total_combinations}] Processing heuristic: {heuristic}")
# Construct Personalized PageRank (PPR) matrix
# PPR provides node representations based on random walk probabilities
print(f" - Constructing PPR feature matrix...")
vectors = PPR.construct_PPR_matrix(decomposed_network)
print(f" - Feature matrix shape: {vectors.shape}")
print(f" - Number of labeled nodes: {len(labels)}")
# Storage for this heuristic's results
micros = []
macros = []
times = []
# Evaluate across different train/test splits
print(f" - Evaluating across multiple train/test splits...")
for test_size in np.arange(0.1, 1, 0.1):
train_size = 1 - test_size
# Stratified split ensures balanced class distribution
rs = StratifiedShuffleSplit(
n_splits=10,
test_size=test_size,
random_state=612312
)
# Run multiple splits for robust evaluation
for train_idx, test_idx in rs.split(vectors, labels):
start = time.time()
# Split data
train_x = vectors[train_idx]
test_x = vectors[test_idx]
train_labels = labels[train_idx]
test_labels = labels[test_idx]
# Train SVM classifier
clf = SVC()
clf.fit(train_x, train_labels)
# Predict on test set
preds = clf.predict(test_x)
# Calculate F1 scores
# Micro-F1: global average (good for imbalanced classes)
# Macro-F1: average per class (all classes weighted equally)
mi = f1_score(test_labels, preds, average='micro')
ma = f1_score(test_labels, preds, average='macro')
end = time.time()
elapsed = end - start
micros.append(mi)
macros.append(ma)
times.append(elapsed)
# Store averaged results for this train/test ratio
outarray = {
"percent_train": np.round(train_size, 1),
"micro_F": np.mean(micros),
"macro_F": np.mean(macros),
"setting": "PPR",
"time": np.mean(times),
"heuristic": heuristic
}
df = pd.concat([df, pd.DataFrame([outarray])], ignore_index=True)
print("\n" + "=" * 70)
print("CLASSIFICATION RESULTS")
print("=" * 70)
# Display results summary
print("\nResults DataFrame:")
print(df.to_string(index=False))
# Find best performing heuristic
best_heuristic = df.loc[df['micro_F'].idxmax()]
print(f"\nBest Performing Configuration:")
print(f" Heuristic: {best_heuristic['heuristic']}")
print(f" Training %: {best_heuristic['percent_train'] * 100:.0f}%")
print(f" Micro-F1: {best_heuristic['micro_F']:.4f}")
print(f" Macro-F1: {best_heuristic['macro_F']:.4f}")
print(f" Avg Time: {best_heuristic['time']:.4f}s")
print(f"\nStep 5: Visualizing results")
print("-" * 70)
# Create visualization
plt.figure(figsize=(12, 6))
sns.lineplot(
data=df,
x='percent_train',
y='micro_F',
hue='heuristic',
marker='o',
linewidth=2
)
plt.xlabel('Training Data Percentage', fontsize=12)
plt.ylabel('Micro-F1 Score', fontsize=12)
plt.title('Classification Performance vs Training Data Size', fontsize=14)
plt.legend(title='Heuristic', bbox_to_anchor=(1.05, 1), loc='upper left')
plt.grid(True, alpha=0.3)
plt.tight_layout()
print(" Generating visualization...")
print(" (Close the window to exit)")
plt.show()
print("\n" + "=" * 70)
print("DECOMPOSITION AND CLASSIFICATION COMPLETE")
print("=" * 70)
print("\nKey Insights:")
print(" - Different heuristics capture different network properties")
print(" - Performance typically improves with more training data")
print(" - PPR-based features are effective for heterogeneous networks")
print(" - Meta-path decomposition preserves semantic relationships")
print("\nNext Steps:")
print(" - Try different classifiers (Random Forest, Neural Networks)")
print(" - Experiment with different meta-path patterns")
print(" - Combine multiple heuristics for ensemble methods")
print(" - Apply to other heterogeneous network datasets")