scikit-network 0.33.0__cp312-cp312-macosx_11_0_arm64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of scikit-network might be problematic. Click here for more details.
- scikit_network-0.33.0.dist-info/AUTHORS.rst +43 -0
- scikit_network-0.33.0.dist-info/LICENSE +34 -0
- scikit_network-0.33.0.dist-info/METADATA +517 -0
- scikit_network-0.33.0.dist-info/RECORD +216 -0
- scikit_network-0.33.0.dist-info/WHEEL +5 -0
- scikit_network-0.33.0.dist-info/top_level.txt +1 -0
- sknetwork/__init__.py +21 -0
- sknetwork/base.py +67 -0
- sknetwork/classification/__init__.py +8 -0
- sknetwork/classification/base.py +142 -0
- sknetwork/classification/base_rank.py +133 -0
- sknetwork/classification/diffusion.py +134 -0
- sknetwork/classification/knn.py +139 -0
- sknetwork/classification/metrics.py +205 -0
- sknetwork/classification/pagerank.py +66 -0
- sknetwork/classification/propagation.py +152 -0
- sknetwork/classification/tests/__init__.py +1 -0
- sknetwork/classification/tests/test_API.py +30 -0
- sknetwork/classification/tests/test_diffusion.py +77 -0
- sknetwork/classification/tests/test_knn.py +23 -0
- sknetwork/classification/tests/test_metrics.py +53 -0
- sknetwork/classification/tests/test_pagerank.py +20 -0
- sknetwork/classification/tests/test_propagation.py +24 -0
- sknetwork/classification/vote.cpython-312-darwin.so +0 -0
- sknetwork/classification/vote.pyx +56 -0
- sknetwork/clustering/__init__.py +8 -0
- sknetwork/clustering/base.py +172 -0
- sknetwork/clustering/kcenters.py +253 -0
- sknetwork/clustering/leiden.py +242 -0
- sknetwork/clustering/leiden_core.cpython-312-darwin.so +0 -0
- sknetwork/clustering/leiden_core.pyx +124 -0
- sknetwork/clustering/louvain.py +286 -0
- sknetwork/clustering/louvain_core.cpython-312-darwin.so +0 -0
- sknetwork/clustering/louvain_core.pyx +124 -0
- sknetwork/clustering/metrics.py +91 -0
- sknetwork/clustering/postprocess.py +66 -0
- sknetwork/clustering/propagation_clustering.py +104 -0
- sknetwork/clustering/tests/__init__.py +1 -0
- sknetwork/clustering/tests/test_API.py +38 -0
- sknetwork/clustering/tests/test_kcenters.py +60 -0
- sknetwork/clustering/tests/test_leiden.py +34 -0
- sknetwork/clustering/tests/test_louvain.py +129 -0
- sknetwork/clustering/tests/test_metrics.py +50 -0
- sknetwork/clustering/tests/test_postprocess.py +39 -0
- sknetwork/data/__init__.py +6 -0
- sknetwork/data/base.py +33 -0
- sknetwork/data/load.py +406 -0
- sknetwork/data/models.py +459 -0
- sknetwork/data/parse.py +644 -0
- sknetwork/data/test_graphs.py +84 -0
- sknetwork/data/tests/__init__.py +1 -0
- sknetwork/data/tests/test_API.py +30 -0
- sknetwork/data/tests/test_base.py +14 -0
- sknetwork/data/tests/test_load.py +95 -0
- sknetwork/data/tests/test_models.py +52 -0
- sknetwork/data/tests/test_parse.py +250 -0
- sknetwork/data/tests/test_test_graphs.py +29 -0
- sknetwork/data/tests/test_toy_graphs.py +68 -0
- sknetwork/data/timeout.py +38 -0
- sknetwork/data/toy_graphs.py +611 -0
- sknetwork/embedding/__init__.py +8 -0
- sknetwork/embedding/base.py +94 -0
- sknetwork/embedding/force_atlas.py +198 -0
- sknetwork/embedding/louvain_embedding.py +148 -0
- sknetwork/embedding/random_projection.py +135 -0
- sknetwork/embedding/spectral.py +141 -0
- sknetwork/embedding/spring.py +198 -0
- sknetwork/embedding/svd.py +359 -0
- sknetwork/embedding/tests/__init__.py +1 -0
- sknetwork/embedding/tests/test_API.py +49 -0
- sknetwork/embedding/tests/test_force_atlas.py +35 -0
- sknetwork/embedding/tests/test_louvain_embedding.py +33 -0
- sknetwork/embedding/tests/test_random_projection.py +28 -0
- sknetwork/embedding/tests/test_spectral.py +81 -0
- sknetwork/embedding/tests/test_spring.py +50 -0
- sknetwork/embedding/tests/test_svd.py +43 -0
- sknetwork/gnn/__init__.py +10 -0
- sknetwork/gnn/activation.py +117 -0
- sknetwork/gnn/base.py +181 -0
- sknetwork/gnn/base_activation.py +89 -0
- sknetwork/gnn/base_layer.py +109 -0
- sknetwork/gnn/gnn_classifier.py +305 -0
- sknetwork/gnn/layer.py +153 -0
- sknetwork/gnn/loss.py +180 -0
- sknetwork/gnn/neighbor_sampler.py +65 -0
- sknetwork/gnn/optimizer.py +164 -0
- sknetwork/gnn/tests/__init__.py +1 -0
- sknetwork/gnn/tests/test_activation.py +56 -0
- sknetwork/gnn/tests/test_base.py +75 -0
- sknetwork/gnn/tests/test_base_layer.py +37 -0
- sknetwork/gnn/tests/test_gnn_classifier.py +130 -0
- sknetwork/gnn/tests/test_layers.py +80 -0
- sknetwork/gnn/tests/test_loss.py +33 -0
- sknetwork/gnn/tests/test_neigh_sampler.py +23 -0
- sknetwork/gnn/tests/test_optimizer.py +43 -0
- sknetwork/gnn/tests/test_utils.py +41 -0
- sknetwork/gnn/utils.py +127 -0
- sknetwork/hierarchy/__init__.py +6 -0
- sknetwork/hierarchy/base.py +96 -0
- sknetwork/hierarchy/louvain_hierarchy.py +272 -0
- sknetwork/hierarchy/metrics.py +234 -0
- sknetwork/hierarchy/paris.cpython-312-darwin.so +0 -0
- sknetwork/hierarchy/paris.pyx +316 -0
- sknetwork/hierarchy/postprocess.py +350 -0
- sknetwork/hierarchy/tests/__init__.py +1 -0
- sknetwork/hierarchy/tests/test_API.py +24 -0
- sknetwork/hierarchy/tests/test_algos.py +34 -0
- sknetwork/hierarchy/tests/test_metrics.py +62 -0
- sknetwork/hierarchy/tests/test_postprocess.py +57 -0
- sknetwork/linalg/__init__.py +9 -0
- sknetwork/linalg/basics.py +37 -0
- sknetwork/linalg/diteration.cpython-312-darwin.so +0 -0
- sknetwork/linalg/diteration.pyx +47 -0
- sknetwork/linalg/eig_solver.py +93 -0
- sknetwork/linalg/laplacian.py +15 -0
- sknetwork/linalg/normalizer.py +86 -0
- sknetwork/linalg/operators.py +225 -0
- sknetwork/linalg/polynome.py +76 -0
- sknetwork/linalg/ppr_solver.py +170 -0
- sknetwork/linalg/push.cpython-312-darwin.so +0 -0
- sknetwork/linalg/push.pyx +71 -0
- sknetwork/linalg/sparse_lowrank.py +142 -0
- sknetwork/linalg/svd_solver.py +91 -0
- sknetwork/linalg/tests/__init__.py +1 -0
- sknetwork/linalg/tests/test_eig.py +44 -0
- sknetwork/linalg/tests/test_laplacian.py +18 -0
- sknetwork/linalg/tests/test_normalization.py +34 -0
- sknetwork/linalg/tests/test_operators.py +66 -0
- sknetwork/linalg/tests/test_polynome.py +38 -0
- sknetwork/linalg/tests/test_ppr.py +50 -0
- sknetwork/linalg/tests/test_sparse_lowrank.py +61 -0
- sknetwork/linalg/tests/test_svd.py +38 -0
- sknetwork/linkpred/__init__.py +2 -0
- sknetwork/linkpred/base.py +46 -0
- sknetwork/linkpred/nn.py +126 -0
- sknetwork/linkpred/tests/__init__.py +1 -0
- sknetwork/linkpred/tests/test_nn.py +27 -0
- sknetwork/log.py +19 -0
- sknetwork/path/__init__.py +5 -0
- sknetwork/path/dag.py +54 -0
- sknetwork/path/distances.py +98 -0
- sknetwork/path/search.py +31 -0
- sknetwork/path/shortest_path.py +61 -0
- sknetwork/path/tests/__init__.py +1 -0
- sknetwork/path/tests/test_dag.py +37 -0
- sknetwork/path/tests/test_distances.py +62 -0
- sknetwork/path/tests/test_search.py +40 -0
- sknetwork/path/tests/test_shortest_path.py +40 -0
- sknetwork/ranking/__init__.py +8 -0
- sknetwork/ranking/base.py +61 -0
- sknetwork/ranking/betweenness.cpython-312-darwin.so +0 -0
- sknetwork/ranking/betweenness.pyx +97 -0
- sknetwork/ranking/closeness.py +92 -0
- sknetwork/ranking/hits.py +94 -0
- sknetwork/ranking/katz.py +83 -0
- sknetwork/ranking/pagerank.py +110 -0
- sknetwork/ranking/postprocess.py +37 -0
- sknetwork/ranking/tests/__init__.py +1 -0
- sknetwork/ranking/tests/test_API.py +32 -0
- sknetwork/ranking/tests/test_betweenness.py +38 -0
- sknetwork/ranking/tests/test_closeness.py +30 -0
- sknetwork/ranking/tests/test_hits.py +20 -0
- sknetwork/ranking/tests/test_pagerank.py +62 -0
- sknetwork/ranking/tests/test_postprocess.py +26 -0
- sknetwork/regression/__init__.py +4 -0
- sknetwork/regression/base.py +61 -0
- sknetwork/regression/diffusion.py +210 -0
- sknetwork/regression/tests/__init__.py +1 -0
- sknetwork/regression/tests/test_API.py +32 -0
- sknetwork/regression/tests/test_diffusion.py +56 -0
- sknetwork/sknetwork.py +3 -0
- sknetwork/test_base.py +35 -0
- sknetwork/test_log.py +15 -0
- sknetwork/topology/__init__.py +8 -0
- sknetwork/topology/cliques.cpython-312-darwin.so +0 -0
- sknetwork/topology/cliques.pyx +149 -0
- sknetwork/topology/core.cpython-312-darwin.so +0 -0
- sknetwork/topology/core.pyx +90 -0
- sknetwork/topology/cycles.py +243 -0
- sknetwork/topology/minheap.cpython-312-darwin.so +0 -0
- sknetwork/topology/minheap.pxd +20 -0
- sknetwork/topology/minheap.pyx +109 -0
- sknetwork/topology/structure.py +194 -0
- sknetwork/topology/tests/__init__.py +1 -0
- sknetwork/topology/tests/test_cliques.py +28 -0
- sknetwork/topology/tests/test_core.py +19 -0
- sknetwork/topology/tests/test_cycles.py +65 -0
- sknetwork/topology/tests/test_structure.py +85 -0
- sknetwork/topology/tests/test_triangles.py +38 -0
- sknetwork/topology/tests/test_wl.py +72 -0
- sknetwork/topology/triangles.cpython-312-darwin.so +0 -0
- sknetwork/topology/triangles.pyx +151 -0
- sknetwork/topology/weisfeiler_lehman.py +133 -0
- sknetwork/topology/weisfeiler_lehman_core.cpython-312-darwin.so +0 -0
- sknetwork/topology/weisfeiler_lehman_core.pyx +114 -0
- sknetwork/utils/__init__.py +7 -0
- sknetwork/utils/check.py +355 -0
- sknetwork/utils/format.py +221 -0
- sknetwork/utils/membership.py +82 -0
- sknetwork/utils/neighbors.py +115 -0
- sknetwork/utils/tests/__init__.py +1 -0
- sknetwork/utils/tests/test_check.py +190 -0
- sknetwork/utils/tests/test_format.py +63 -0
- sknetwork/utils/tests/test_membership.py +24 -0
- sknetwork/utils/tests/test_neighbors.py +41 -0
- sknetwork/utils/tests/test_tfidf.py +18 -0
- sknetwork/utils/tests/test_values.py +66 -0
- sknetwork/utils/tfidf.py +37 -0
- sknetwork/utils/values.py +76 -0
- sknetwork/visualization/__init__.py +4 -0
- sknetwork/visualization/colors.py +34 -0
- sknetwork/visualization/dendrograms.py +277 -0
- sknetwork/visualization/graphs.py +1039 -0
- sknetwork/visualization/tests/__init__.py +1 -0
- sknetwork/visualization/tests/test_dendrograms.py +53 -0
- sknetwork/visualization/tests/test_graphs.py +176 -0
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
"""Tests for clustering API"""
|
|
4
|
+
import unittest
|
|
5
|
+
|
|
6
|
+
from sknetwork.clustering import *
|
|
7
|
+
from sknetwork.data.test_graphs import *
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class TestClusteringAPI(unittest.TestCase):
|
|
11
|
+
|
|
12
|
+
def setUp(self):
|
|
13
|
+
self.algos = [Louvain(return_aggregate=True), Leiden(return_aggregate=True),
|
|
14
|
+
PropagationClustering(return_aggregate=True)]
|
|
15
|
+
|
|
16
|
+
def test_regular(self):
|
|
17
|
+
for algo in self.algos:
|
|
18
|
+
for adjacency in [test_graph(), test_digraph(), test_disconnected_graph()]:
|
|
19
|
+
n = adjacency.shape[0]
|
|
20
|
+
labels = algo.fit_predict(adjacency)
|
|
21
|
+
n_labels = len(set(labels))
|
|
22
|
+
self.assertEqual(labels.shape, (n,))
|
|
23
|
+
self.assertEqual(algo.aggregate_.shape, (n_labels, n_labels))
|
|
24
|
+
adjacency_bool = adjacency.astype(bool)
|
|
25
|
+
labels = algo.fit_predict(adjacency_bool)
|
|
26
|
+
n_labels = len(set(labels))
|
|
27
|
+
self.assertEqual(labels.shape, (n,))
|
|
28
|
+
self.assertEqual(algo.aggregate_.shape, (n_labels, n_labels))
|
|
29
|
+
membership = algo.fit_transform(adjacency_bool)
|
|
30
|
+
self.assertEqual(membership.shape, (n, n_labels))
|
|
31
|
+
|
|
32
|
+
def test_bipartite(self):
|
|
33
|
+
biadjacency = test_bigraph()
|
|
34
|
+
n_row, n_col = biadjacency.shape
|
|
35
|
+
for algo in self.algos:
|
|
36
|
+
algo.fit(biadjacency)
|
|
37
|
+
self.assertEqual(algo.labels_row_.shape, (n_row,))
|
|
38
|
+
self.assertEqual(algo.labels_col_.shape, (n_col,))
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
"""Tests for KCenters"""
|
|
4
|
+
import unittest
|
|
5
|
+
|
|
6
|
+
from sknetwork.clustering import KCenters
|
|
7
|
+
from sknetwork.data.test_graphs import *
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class TestKCentersClustering(unittest.TestCase):
|
|
11
|
+
|
|
12
|
+
def test_kcenters(self):
|
|
13
|
+
# Test undirected graph
|
|
14
|
+
n_clusters = 2
|
|
15
|
+
adjacency = test_graph()
|
|
16
|
+
n_row = adjacency.shape[0]
|
|
17
|
+
kcenters = KCenters(n_clusters=n_clusters)
|
|
18
|
+
labels = kcenters.fit_predict(adjacency)
|
|
19
|
+
self.assertEqual(len(labels), n_row)
|
|
20
|
+
self.assertEqual(len(set(labels)), n_clusters)
|
|
21
|
+
|
|
22
|
+
# Test directed graph
|
|
23
|
+
n_clusters = 3
|
|
24
|
+
adjacency = test_digraph()
|
|
25
|
+
n_row = adjacency.shape[0]
|
|
26
|
+
kcenters = KCenters(n_clusters=n_clusters, directed=True)
|
|
27
|
+
labels = kcenters.fit_predict(adjacency)
|
|
28
|
+
self.assertEqual(len(labels), n_row)
|
|
29
|
+
self.assertEqual(len(set(labels)), n_clusters)
|
|
30
|
+
|
|
31
|
+
# Test bipartite graph
|
|
32
|
+
n_clusters = 2
|
|
33
|
+
biadjacency = test_bigraph()
|
|
34
|
+
n_row, n_col = biadjacency.shape
|
|
35
|
+
kcenters = KCenters(n_clusters=n_clusters)
|
|
36
|
+
kcenters.fit(biadjacency)
|
|
37
|
+
labels = kcenters.labels_
|
|
38
|
+
self.assertEqual(len(kcenters.labels_row_), n_row)
|
|
39
|
+
self.assertEqual(len(kcenters.labels_col_), n_col)
|
|
40
|
+
self.assertEqual(len(set(labels)), n_clusters)
|
|
41
|
+
|
|
42
|
+
def test_kcenters_error(self):
|
|
43
|
+
# Test value errors
|
|
44
|
+
adjacency = test_graph()
|
|
45
|
+
biadjacency = test_bigraph()
|
|
46
|
+
|
|
47
|
+
# test n_clusters error
|
|
48
|
+
kcenters = KCenters(n_clusters=1)
|
|
49
|
+
with self.assertRaises(ValueError):
|
|
50
|
+
kcenters.fit(adjacency)
|
|
51
|
+
|
|
52
|
+
# test n_init error
|
|
53
|
+
kcenters = KCenters(n_clusters=2, n_init=0)
|
|
54
|
+
with self.assertRaises(ValueError):
|
|
55
|
+
kcenters.fit(adjacency)
|
|
56
|
+
|
|
57
|
+
# test center_position error
|
|
58
|
+
kcenters = KCenters(n_clusters=2, center_position="other")
|
|
59
|
+
with self.assertRaises(ValueError):
|
|
60
|
+
kcenters.fit(biadjacency)
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
"""Tests for Leiden"""
|
|
4
|
+
import unittest
|
|
5
|
+
|
|
6
|
+
from sknetwork.clustering import Leiden
|
|
7
|
+
from sknetwork.data.test_graphs import *
|
|
8
|
+
from sknetwork.utils import bipartite2undirected
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class TestLeidenClustering(unittest.TestCase):
|
|
12
|
+
|
|
13
|
+
def test_disconnected(self):
|
|
14
|
+
adjacency = test_disconnected_graph()
|
|
15
|
+
n = adjacency.shape[0]
|
|
16
|
+
labels = Leiden().fit_predict(adjacency)
|
|
17
|
+
self.assertEqual(len(labels), n)
|
|
18
|
+
|
|
19
|
+
def test_modularity(self):
|
|
20
|
+
adjacency = test_graph()
|
|
21
|
+
leiden_d = Leiden(modularity='dugue')
|
|
22
|
+
leiden_n = Leiden(modularity='newman')
|
|
23
|
+
labels_d = leiden_d.fit_predict(adjacency)
|
|
24
|
+
labels_n = leiden_n.fit_predict(adjacency)
|
|
25
|
+
self.assertTrue((labels_d == labels_n).all())
|
|
26
|
+
|
|
27
|
+
def test_bipartite(self):
|
|
28
|
+
biadjacency = test_bigraph()
|
|
29
|
+
adjacency = bipartite2undirected(biadjacency)
|
|
30
|
+
leiden = Leiden(modularity='newman')
|
|
31
|
+
labels1 = leiden.fit_predict(adjacency)
|
|
32
|
+
leiden.fit(biadjacency)
|
|
33
|
+
labels2 = np.concatenate((leiden.labels_row_, leiden.labels_col_))
|
|
34
|
+
self.assertTrue((labels1 == labels2).all())
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
"""Tests for Louvain"""
|
|
4
|
+
import unittest
|
|
5
|
+
|
|
6
|
+
from sknetwork.clustering import Louvain
|
|
7
|
+
from sknetwork.data import karate_club, star_wars
|
|
8
|
+
from sknetwork.data.test_graphs import *
|
|
9
|
+
from sknetwork.utils import bipartite2undirected
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class TestLouvainClustering(unittest.TestCase):
|
|
13
|
+
|
|
14
|
+
def test_disconnected(self):
|
|
15
|
+
adjacency = test_disconnected_graph()
|
|
16
|
+
n = adjacency.shape[0]
|
|
17
|
+
labels = Louvain().fit_predict(adjacency)
|
|
18
|
+
self.assertEqual(len(labels), n)
|
|
19
|
+
|
|
20
|
+
def test_modularity(self):
|
|
21
|
+
adjacency = karate_club()
|
|
22
|
+
louvain_d = Louvain(modularity='dugue')
|
|
23
|
+
louvain_n = Louvain(modularity='newman')
|
|
24
|
+
labels_d = louvain_d.fit_predict(adjacency)
|
|
25
|
+
labels_n = louvain_n.fit_predict(adjacency)
|
|
26
|
+
self.assertTrue((labels_d == labels_n).all())
|
|
27
|
+
louvain_p = Louvain(modularity='potts')
|
|
28
|
+
louvain_p.fit_predict(adjacency)
|
|
29
|
+
|
|
30
|
+
def test_bilouvain(self):
|
|
31
|
+
biadjacency = star_wars()
|
|
32
|
+
adjacency = bipartite2undirected(biadjacency)
|
|
33
|
+
louvain = Louvain(modularity='newman')
|
|
34
|
+
labels1 = louvain.fit_predict(adjacency)
|
|
35
|
+
louvain.fit(biadjacency)
|
|
36
|
+
labels2 = np.concatenate((louvain.labels_row_, louvain.labels_col_))
|
|
37
|
+
self.assertTrue((labels1 == labels2).all())
|
|
38
|
+
|
|
39
|
+
def test_options(self):
|
|
40
|
+
adjacency = karate_club()
|
|
41
|
+
|
|
42
|
+
# resolution
|
|
43
|
+
louvain = Louvain(resolution=2)
|
|
44
|
+
labels = louvain.fit_predict(adjacency)
|
|
45
|
+
self.assertEqual(len(set(labels)), 7)
|
|
46
|
+
|
|
47
|
+
# tolerance
|
|
48
|
+
louvain = Louvain(resolution=2, tol_aggregation=0.1)
|
|
49
|
+
labels = louvain.fit_predict(adjacency)
|
|
50
|
+
self.assertEqual(len(set(labels)), 7)
|
|
51
|
+
|
|
52
|
+
# shuffling
|
|
53
|
+
louvain = Louvain(resolution=2, shuffle_nodes=True, random_state=42)
|
|
54
|
+
labels = louvain.fit_predict(adjacency)
|
|
55
|
+
self.assertEqual(len(set(labels)), 7)
|
|
56
|
+
|
|
57
|
+
# aggregate graph
|
|
58
|
+
louvain = Louvain(return_aggregate=True)
|
|
59
|
+
labels = louvain.fit_predict(adjacency)
|
|
60
|
+
n_labels = len(set(labels))
|
|
61
|
+
self.assertEqual(louvain.aggregate_.shape, (n_labels, n_labels))
|
|
62
|
+
|
|
63
|
+
# aggregate graph
|
|
64
|
+
Louvain(n_aggregations=1, sort_clusters=False).fit(adjacency)
|
|
65
|
+
|
|
66
|
+
def test_options_with_64_bit(self):
|
|
67
|
+
adjacency = karate_club()
|
|
68
|
+
# force 64-bit index
|
|
69
|
+
adjacency.indices = adjacency.indices.astype(np.int64)
|
|
70
|
+
adjacency.indptr = adjacency.indptr.astype(np.int64)
|
|
71
|
+
|
|
72
|
+
# resolution
|
|
73
|
+
louvain = Louvain(resolution=2)
|
|
74
|
+
labels = louvain.fit_predict(adjacency)
|
|
75
|
+
self.assertEqual(len(set(labels)), 7)
|
|
76
|
+
|
|
77
|
+
# tolerance
|
|
78
|
+
louvain = Louvain(resolution=2, tol_aggregation=0.1)
|
|
79
|
+
labels = louvain.fit_predict(adjacency)
|
|
80
|
+
self.assertEqual(len(set(labels)), 7)
|
|
81
|
+
|
|
82
|
+
# shuffling
|
|
83
|
+
louvain = Louvain(resolution=2, shuffle_nodes=True, random_state=42)
|
|
84
|
+
labels = louvain.fit_predict(adjacency)
|
|
85
|
+
self.assertEqual(len(set(labels)), 7)
|
|
86
|
+
|
|
87
|
+
# aggregate graph
|
|
88
|
+
louvain = Louvain(return_aggregate=True)
|
|
89
|
+
labels = louvain.fit_predict(adjacency)
|
|
90
|
+
n_labels = len(set(labels))
|
|
91
|
+
self.assertEqual(louvain.aggregate_.shape, (n_labels, n_labels))
|
|
92
|
+
|
|
93
|
+
# aggregate graph
|
|
94
|
+
Louvain(n_aggregations=1, sort_clusters=False).fit(adjacency)
|
|
95
|
+
|
|
96
|
+
# check if labels are 64-bit
|
|
97
|
+
self.assertEqual(labels.dtype, np.int64)
|
|
98
|
+
|
|
99
|
+
def test_predict(self):
|
|
100
|
+
adjacency = karate_club()
|
|
101
|
+
n_nodes = adjacency.shape[0]
|
|
102
|
+
louvain = Louvain()
|
|
103
|
+
labels = louvain.fit_predict(adjacency)
|
|
104
|
+
self.assertEqual(len(labels), n_nodes)
|
|
105
|
+
probs = louvain.fit_predict_proba(adjacency)
|
|
106
|
+
self.assertEqual(probs.shape[0], n_nodes)
|
|
107
|
+
membership = louvain.fit_transform(adjacency)
|
|
108
|
+
self.assertEqual(membership.shape[0], n_nodes)
|
|
109
|
+
biadjacency = star_wars()
|
|
110
|
+
n_row, n_col = biadjacency.shape
|
|
111
|
+
louvain.fit(biadjacency)
|
|
112
|
+
labels = louvain.predict()
|
|
113
|
+
self.assertEqual(len(labels), n_row)
|
|
114
|
+
labels = louvain.predict(columns=True)
|
|
115
|
+
self.assertEqual(len(labels), n_col)
|
|
116
|
+
probs = louvain.predict_proba()
|
|
117
|
+
self.assertEqual(probs.shape[0], n_row)
|
|
118
|
+
probs = louvain.predict(columns=True)
|
|
119
|
+
self.assertEqual(probs.shape[0], n_col)
|
|
120
|
+
membership = louvain.transform()
|
|
121
|
+
self.assertEqual(membership.shape[0], n_row)
|
|
122
|
+
membership = louvain.transform(columns=True)
|
|
123
|
+
self.assertEqual(membership.shape[0], n_col)
|
|
124
|
+
|
|
125
|
+
def test_invalid(self):
|
|
126
|
+
adjacency = karate_club()
|
|
127
|
+
louvain = Louvain(modularity='toto')
|
|
128
|
+
with self.assertRaises(ValueError):
|
|
129
|
+
louvain.fit(adjacency)
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
# tests for metrics.py
|
|
3
|
+
""""tests for clustering metrics"""
|
|
4
|
+
import unittest
|
|
5
|
+
|
|
6
|
+
import numpy as np
|
|
7
|
+
|
|
8
|
+
from sknetwork.clustering import get_modularity, Louvain
|
|
9
|
+
from sknetwork.data import star_wars, karate_club
|
|
10
|
+
from sknetwork.data.test_graphs import test_graph
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class TestClusteringMetrics(unittest.TestCase):
|
|
14
|
+
|
|
15
|
+
def setUp(self):
|
|
16
|
+
"""Basic graph for tests"""
|
|
17
|
+
self.adjacency = test_graph()
|
|
18
|
+
n = self.adjacency.shape[0]
|
|
19
|
+
labels = np.zeros(n)
|
|
20
|
+
labels[0] = 1
|
|
21
|
+
self.labels = labels.astype(int)
|
|
22
|
+
self.unique_cluster = np.zeros(n, dtype=int)
|
|
23
|
+
|
|
24
|
+
def test_api(self):
|
|
25
|
+
for metric in [get_modularity]:
|
|
26
|
+
_, fit, div = metric(self.adjacency, self.labels, return_all=True)
|
|
27
|
+
mod = metric(self.adjacency, self.labels, return_all=False)
|
|
28
|
+
self.assertAlmostEqual(fit - div, mod)
|
|
29
|
+
self.assertAlmostEqual(metric(self.adjacency, self.unique_cluster), 0.)
|
|
30
|
+
|
|
31
|
+
with self.assertRaises(ValueError):
|
|
32
|
+
metric(self.adjacency, self.labels[:3])
|
|
33
|
+
|
|
34
|
+
def test_modularity(self):
|
|
35
|
+
adjacency = karate_club()
|
|
36
|
+
labels = Louvain().fit_predict(adjacency)
|
|
37
|
+
self.assertAlmostEqual(get_modularity(adjacency, labels), 0.42, 2)
|
|
38
|
+
|
|
39
|
+
def test_bimodularity(self):
|
|
40
|
+
biadjacency = star_wars()
|
|
41
|
+
labels_row = np.array([0, 0, 1, 1])
|
|
42
|
+
labels_col = np.array([0, 1, 0])
|
|
43
|
+
self.assertAlmostEqual(get_modularity(biadjacency, labels_row, labels_col), 0.12, 2)
|
|
44
|
+
|
|
45
|
+
with self.assertRaises(ValueError):
|
|
46
|
+
get_modularity(biadjacency, labels_row)
|
|
47
|
+
with self.assertRaises(ValueError):
|
|
48
|
+
get_modularity(biadjacency, labels_row[:2], labels_col)
|
|
49
|
+
with self.assertRaises(ValueError):
|
|
50
|
+
get_modularity(biadjacency, labels_row, labels_col[:2])
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
"""Tests for clustering post-processing"""
|
|
4
|
+
import unittest
|
|
5
|
+
|
|
6
|
+
import numpy as np
|
|
7
|
+
|
|
8
|
+
from sknetwork.data import house, star_wars
|
|
9
|
+
from sknetwork.clustering.postprocess import reindex_labels, aggregate_graph
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class TestClusteringPostProcessing(unittest.TestCase):
|
|
13
|
+
|
|
14
|
+
def test_reindex_clusters(self):
|
|
15
|
+
truth = np.array([1, 1, 2, 0, 0, 0])
|
|
16
|
+
|
|
17
|
+
labels = np.array([0, 0, 1, 2, 2, 2])
|
|
18
|
+
output = reindex_labels(labels)
|
|
19
|
+
self.assertTrue(np.array_equal(truth, output))
|
|
20
|
+
|
|
21
|
+
labels = np.array([0, 0, 5, 2, 2, 2])
|
|
22
|
+
output = reindex_labels(labels)
|
|
23
|
+
self.assertTrue(np.array_equal(truth, output))
|
|
24
|
+
|
|
25
|
+
def test_aggregate_graph(self):
|
|
26
|
+
adjacency = house()
|
|
27
|
+
labels = np.array([0, 0, 1, 1, 2])
|
|
28
|
+
aggregate = aggregate_graph(adjacency, labels)
|
|
29
|
+
self.assertEqual(aggregate.shape, (3, 3))
|
|
30
|
+
|
|
31
|
+
biadjacency = star_wars()
|
|
32
|
+
labels = np.array([0, 0, 1, 2])
|
|
33
|
+
labels_row = np.array([0, 1, 3, -1])
|
|
34
|
+
labels_col = np.array([0, 0, 1])
|
|
35
|
+
aggregate = aggregate_graph(biadjacency, labels=labels, labels_col=labels_col)
|
|
36
|
+
self.assertEqual(aggregate.shape, (3, 2))
|
|
37
|
+
self.assertEqual(aggregate.shape, (3, 2))
|
|
38
|
+
aggregate = aggregate_graph(biadjacency, labels_row=labels_row, labels_col=labels_col)
|
|
39
|
+
self.assertEqual(aggregate.shape, (4, 2))
|
sknetwork/data/base.py
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
"""
|
|
4
|
+
Created in May 2023
|
|
5
|
+
@author: Thomas Bonald <bonald@enst.fr>
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class Dataset(dict):
|
|
10
|
+
"""Container object for datasets.
|
|
11
|
+
Dictionary-like object that exposes its keys as attributes.
|
|
12
|
+
>>> dataset = Dataset(name='dataset')
|
|
13
|
+
>>> dataset['name']
|
|
14
|
+
'dataset'
|
|
15
|
+
>>> dataset.name
|
|
16
|
+
'dataset'
|
|
17
|
+
"""
|
|
18
|
+
def __init__(self, **kwargs):
|
|
19
|
+
super().__init__(kwargs)
|
|
20
|
+
|
|
21
|
+
def __setattr__(self, key, value):
|
|
22
|
+
self[key] = value
|
|
23
|
+
|
|
24
|
+
def __getattr__(self, key):
|
|
25
|
+
try:
|
|
26
|
+
return self[key]
|
|
27
|
+
except KeyError:
|
|
28
|
+
raise AttributeError(key)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
# alias for Dataset
|
|
32
|
+
Bunch = Dataset
|
|
33
|
+
|