scikit-network 0.31.0__cp310-cp310-win_amd64.whl → 0.32.1__cp310-cp310-win_amd64.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.

Files changed (114) hide show
  1. {scikit_network-0.31.0.dist-info → scikit_network-0.32.1.dist-info}/AUTHORS.rst +3 -0
  2. {scikit_network-0.31.0.dist-info → scikit_network-0.32.1.dist-info}/METADATA +19 -3
  3. {scikit_network-0.31.0.dist-info → scikit_network-0.32.1.dist-info}/RECORD +112 -105
  4. {scikit_network-0.31.0.dist-info → scikit_network-0.32.1.dist-info}/WHEEL +1 -1
  5. sknetwork/__init__.py +1 -1
  6. sknetwork/classification/base.py +1 -1
  7. sknetwork/classification/base_rank.py +3 -3
  8. sknetwork/classification/diffusion.py +21 -13
  9. sknetwork/classification/knn.py +19 -13
  10. sknetwork/classification/metrics.py +1 -1
  11. sknetwork/classification/pagerank.py +12 -8
  12. sknetwork/classification/propagation.py +22 -15
  13. sknetwork/classification/tests/test_diffusion.py +10 -0
  14. sknetwork/classification/vote.cp310-win_amd64.pyd +0 -0
  15. sknetwork/classification/vote.cpp +14549 -8668
  16. sknetwork/clustering/__init__.py +3 -1
  17. sknetwork/clustering/base.py +1 -1
  18. sknetwork/clustering/kcenters.py +253 -0
  19. sknetwork/clustering/leiden.py +241 -0
  20. sknetwork/clustering/leiden_core.cp310-win_amd64.pyd +0 -0
  21. sknetwork/clustering/leiden_core.cpp +31564 -0
  22. sknetwork/clustering/leiden_core.pyx +124 -0
  23. sknetwork/clustering/louvain.py +118 -83
  24. sknetwork/clustering/louvain_core.cp310-win_amd64.pyd +0 -0
  25. sknetwork/clustering/louvain_core.cpp +21876 -16332
  26. sknetwork/clustering/louvain_core.pyx +86 -94
  27. sknetwork/clustering/postprocess.py +2 -2
  28. sknetwork/clustering/propagation_clustering.py +4 -4
  29. sknetwork/clustering/tests/test_API.py +7 -3
  30. sknetwork/clustering/tests/test_kcenters.py +92 -0
  31. sknetwork/clustering/tests/test_leiden.py +34 -0
  32. sknetwork/clustering/tests/test_louvain.py +2 -3
  33. sknetwork/data/load.py +2 -4
  34. sknetwork/data/parse.py +41 -20
  35. sknetwork/data/tests/test_parse.py +9 -12
  36. sknetwork/embedding/__init__.py +0 -1
  37. sknetwork/embedding/base.py +20 -19
  38. sknetwork/embedding/force_atlas.py +3 -2
  39. sknetwork/embedding/louvain_embedding.py +1 -1
  40. sknetwork/embedding/random_projection.py +5 -3
  41. sknetwork/embedding/spectral.py +0 -73
  42. sknetwork/embedding/tests/test_API.py +4 -28
  43. sknetwork/embedding/tests/test_louvain_embedding.py +4 -9
  44. sknetwork/embedding/tests/test_spectral.py +2 -5
  45. sknetwork/embedding/tests/test_svd.py +1 -1
  46. sknetwork/gnn/base_layer.py +3 -3
  47. sknetwork/gnn/gnn_classifier.py +40 -86
  48. sknetwork/gnn/layer.py +1 -1
  49. sknetwork/gnn/loss.py +1 -1
  50. sknetwork/gnn/optimizer.py +4 -3
  51. sknetwork/gnn/tests/test_base_layer.py +4 -4
  52. sknetwork/gnn/tests/test_gnn_classifier.py +12 -39
  53. sknetwork/gnn/utils.py +8 -8
  54. sknetwork/hierarchy/base.py +27 -0
  55. sknetwork/hierarchy/louvain_hierarchy.py +45 -41
  56. sknetwork/hierarchy/paris.cp310-win_amd64.pyd +0 -0
  57. sknetwork/hierarchy/paris.cpp +27521 -20771
  58. sknetwork/hierarchy/paris.pyx +7 -7
  59. sknetwork/hierarchy/postprocess.py +16 -16
  60. sknetwork/hierarchy/tests/test_algos.py +5 -0
  61. sknetwork/linalg/__init__.py +1 -1
  62. sknetwork/linalg/diteration.cp310-win_amd64.pyd +0 -0
  63. sknetwork/linalg/diteration.cpp +13916 -8050
  64. sknetwork/linalg/{normalization.py → normalizer.py} +17 -14
  65. sknetwork/linalg/operators.py +1 -1
  66. sknetwork/linalg/ppr_solver.py +1 -1
  67. sknetwork/linalg/push.cp310-win_amd64.pyd +0 -0
  68. sknetwork/linalg/push.cpp +23187 -16973
  69. sknetwork/linalg/tests/test_normalization.py +3 -7
  70. sknetwork/linalg/tests/test_operators.py +2 -6
  71. sknetwork/linalg/tests/test_ppr.py +1 -1
  72. sknetwork/linkpred/base.py +12 -1
  73. sknetwork/linkpred/nn.py +6 -6
  74. sknetwork/path/distances.py +11 -4
  75. sknetwork/path/shortest_path.py +1 -1
  76. sknetwork/path/tests/test_distances.py +7 -0
  77. sknetwork/path/tests/test_search.py +2 -2
  78. sknetwork/ranking/base.py +11 -6
  79. sknetwork/ranking/betweenness.cp310-win_amd64.pyd +0 -0
  80. sknetwork/ranking/betweenness.cpp +5256 -2190
  81. sknetwork/ranking/pagerank.py +13 -12
  82. sknetwork/ranking/tests/test_API.py +0 -2
  83. sknetwork/ranking/tests/test_betweenness.py +1 -1
  84. sknetwork/ranking/tests/test_pagerank.py +11 -5
  85. sknetwork/regression/base.py +18 -1
  86. sknetwork/regression/diffusion.py +24 -10
  87. sknetwork/regression/tests/test_diffusion.py +8 -0
  88. sknetwork/topology/__init__.py +3 -1
  89. sknetwork/topology/cliques.cp310-win_amd64.pyd +0 -0
  90. sknetwork/topology/cliques.cpp +23528 -16848
  91. sknetwork/topology/core.cp310-win_amd64.pyd +0 -0
  92. sknetwork/topology/core.cpp +22849 -16581
  93. sknetwork/topology/cycles.py +243 -0
  94. sknetwork/topology/minheap.cp310-win_amd64.pyd +0 -0
  95. sknetwork/topology/minheap.cpp +19495 -13469
  96. sknetwork/topology/structure.py +2 -42
  97. sknetwork/topology/tests/test_cycles.py +65 -0
  98. sknetwork/topology/tests/test_structure.py +2 -16
  99. sknetwork/topology/triangles.cp310-win_amd64.pyd +0 -0
  100. sknetwork/topology/triangles.cpp +5283 -1397
  101. sknetwork/topology/triangles.pyx +7 -4
  102. sknetwork/topology/weisfeiler_lehman_core.cp310-win_amd64.pyd +0 -0
  103. sknetwork/topology/weisfeiler_lehman_core.cpp +14781 -8915
  104. sknetwork/utils/format.py +1 -1
  105. sknetwork/utils/membership.py +2 -2
  106. sknetwork/visualization/__init__.py +2 -2
  107. sknetwork/visualization/dendrograms.py +55 -7
  108. sknetwork/visualization/graphs.py +261 -44
  109. sknetwork/visualization/tests/test_dendrograms.py +9 -9
  110. sknetwork/visualization/tests/test_graphs.py +63 -57
  111. sknetwork/embedding/louvain_hierarchy.py +0 -142
  112. sknetwork/embedding/tests/test_louvain_hierarchy.py +0 -19
  113. {scikit_network-0.31.0.dist-info → scikit_network-0.32.1.dist-info}/LICENSE +0 -0
  114. {scikit_network-0.31.0.dist-info → scikit_network-0.32.1.dist-info}/top_level.txt +0 -0
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env python3
2
2
  # -*- coding: utf-8 -*-
3
3
  """
4
- Created on May 2019
4
+ Created in May 2019
5
5
  @author: Nathan de Lara <nathan.delara@polytechnique.org>
6
6
  @author: Thomas Bonald <bonald@enst.fr>
7
7
  """
@@ -9,7 +9,6 @@ from typing import Union, Optional
9
9
 
10
10
  import numpy as np
11
11
  from scipy import sparse
12
- from scipy.sparse.linalg import LinearOperator
13
12
 
14
13
  from sknetwork.linalg.ppr_solver import get_pagerank
15
14
  from sknetwork.ranking.base import BaseRanking
@@ -73,24 +72,26 @@ class PageRank(BaseRanking):
73
72
  self.tol = tol
74
73
  self.bipartite = None
75
74
 
76
- def fit(self, input_matrix: Union[sparse.csr_matrix, np.ndarray, LinearOperator],
75
+ def fit(self, input_matrix: Union[sparse.csr_matrix, np.ndarray],
77
76
  weights: Optional[Union[dict, np.ndarray]] = None, weights_row: Optional[Union[dict, np.ndarray]] = None,
78
77
  weights_col: Optional[Union[dict, np.ndarray]] = None, force_bipartite: bool = False) -> 'PageRank':
79
- """Fit algorithm to data.
78
+ """Compute the pagerank of each node.
80
79
 
81
80
  Parameters
82
81
  ----------
83
- input_matrix :
82
+ input_matrix : sparse.csr_matrix, np.ndarray
84
83
  Adjacency matrix or biadjacency matrix of the graph.
85
- weights :
86
- Parameter to be used for Personalized PageRank.
87
- Restart distribution as a vector or a dict (node: weight).
84
+ weights : np.ndarray, dict
85
+ Weights of the restart distribution for Personalized PageRank.
88
86
  If ``None``, the uniform distribution is used (no personalization, default).
89
- weights_row, weights_col :
90
- Parameter to be used for Personalized PageRank on bipartite graphs.
91
- Restart distribution as vectors or dicts on rows, columns (node: weight).
87
+ weights_row : np.ndarray, dict
88
+ Weights on rows of the restart distribution for Personalized PageRank.
89
+ Used for bipartite graphs.
92
90
  If both weights_row and weights_col are ``None`` (default), the uniform distribution on rows is used.
93
- force_bipartite :
91
+ weights_col : np.ndarray, dict
92
+ Weights on columns of the restart distribution for Personalized PageRank.
93
+ Used for bipartite graphs.
94
+ force_bipartite : bool
94
95
  If ``True``, consider the input matrix as the biadjacency matrix of a bipartite graph.
95
96
  Returns
96
97
  -------
@@ -17,8 +17,6 @@ class TestPageRank(unittest.TestCase):
17
17
  score = method.fit_predict(adjacency)
18
18
  self.assertEqual(score.shape, (n, ))
19
19
  self.assertTrue(min(score) >= 0)
20
- score = method.fit_transform(adjacency)
21
- self.assertEqual(score.shape, (n,))
22
20
 
23
21
  def test_bipartite(self):
24
22
  biadjacency = test_bigraph()
@@ -35,4 +35,4 @@ class TestBetweenness(unittest.TestCase):
35
35
  betweenness = Betweenness()
36
36
 
37
37
  with self.assertRaises(ValueError):
38
- betweenness.fit_transform(adjacency)
38
+ betweenness.fit_predict(adjacency)
@@ -7,7 +7,7 @@ import unittest
7
7
  import numpy as np
8
8
 
9
9
  from sknetwork.data.models import cyclic_digraph
10
- from sknetwork.data.test_graphs import test_bigraph
10
+ from sknetwork.data.test_graphs import test_graph, test_digraph, test_bigraph
11
11
  from sknetwork.ranking.pagerank import PageRank
12
12
 
13
13
 
@@ -37,8 +37,8 @@ class TestPageRank(unittest.TestCase):
37
37
  seeds_array[0] = 1.
38
38
  seeds_dict = {0: 1}
39
39
 
40
- scores1 = pagerank.fit_transform(self.adjacency, seeds_array)
41
- scores2 = pagerank.fit_transform(self.adjacency, seeds_dict)
40
+ scores1 = pagerank.fit_predict(self.adjacency, seeds_array)
41
+ scores2 = pagerank.fit_predict(self.adjacency, seeds_dict)
42
42
  self.assertAlmostEqual(np.linalg.norm(scores1 - scores2), 0.)
43
43
 
44
44
  def test_input(self):
@@ -48,9 +48,15 @@ class TestPageRank(unittest.TestCase):
48
48
 
49
49
  def test_damping(self):
50
50
  pagerank = PageRank(damping_factor=0.99)
51
- scores = pagerank.fit_transform(self.adjacency)
51
+ scores = pagerank.fit_predict(self.adjacency)
52
52
  self.assertAlmostEqual(np.linalg.norm(scores - self.truth), 0.)
53
53
 
54
54
  pagerank = PageRank(damping_factor=0.01)
55
- scores = pagerank.fit_transform(self.adjacency)
55
+ scores = pagerank.fit_predict(self.adjacency)
56
56
  self.assertAlmostEqual(np.linalg.norm(scores - self.truth), 0.)
57
+
58
+ def test_bigraph(self):
59
+ pagerank = PageRank()
60
+ for adjacency in [test_graph(), test_digraph(), test_bigraph()]:
61
+ pagerank.fit(adjacency, weights_col={0: 1})
62
+ self.assertAlmostEqual(np.linalg.norm(pagerank.scores_col_ - pagerank.predict(columns=True)), 0.)
@@ -26,8 +26,25 @@ class BaseRegressor(Algorithm, ABC):
26
26
  def __init__(self):
27
27
  self.values_ = None
28
28
 
29
+ def predict(self, columns: bool = False) -> np.ndarray:
30
+ """Return the values predicted by the algorithm.
31
+
32
+ Parameters
33
+ ----------
34
+ columns : bool
35
+ If ``True``, return the prediction for columns.
36
+
37
+ Returns
38
+ -------
39
+ values : np.ndarray
40
+ Values.
41
+ """
42
+ if columns:
43
+ return self.values_col_
44
+ return self.values_
45
+
29
46
  def fit_predict(self, *args, **kwargs) -> np.ndarray:
30
- """Fit algorithm to data and return the scores. Same parameters as the ``fit`` method.
47
+ """Fit algorithm to data and return the values. Same parameters as the ``fit`` method.
31
48
 
32
49
  Returns
33
50
  -------
@@ -10,9 +10,9 @@ from typing import Union, Optional, Tuple
10
10
  import numpy as np
11
11
  from scipy import sparse
12
12
 
13
- from sknetwork.linalg.normalization import normalize
13
+ from sknetwork.linalg.normalizer import normalize
14
14
  from sknetwork.regression.base import BaseRegressor
15
- from sknetwork.utils.format import get_adjacency_values
15
+ from sknetwork.utils import get_adjacency_values, get_degrees
16
16
 
17
17
 
18
18
  def init_temperatures(seeds: np.ndarray, init: Optional[float]) -> Tuple[np.ndarray, np.ndarray]:
@@ -30,6 +30,12 @@ def init_temperatures(seeds: np.ndarray, init: Optional[float]) -> Tuple[np.ndar
30
30
  class Diffusion(BaseRegressor):
31
31
  """Regression by diffusion along the edges, given the temperatures of some seed nodes (heat equation).
32
32
 
33
+ The row vector of tempreatures :math:`T` evolves like:
34
+
35
+ :math:`T \\gets (1-\\alpha) T + \\alpha PT`
36
+
37
+ where :math:`\\alpha` is the damping factor and :math:`P` is the transition matrix of the random walk in the graph.
38
+
33
39
  All values are updated, including those of seed nodes (free diffusion).
34
40
  See ``Dirichlet`` for diffusion with boundary constraints.
35
41
 
@@ -37,6 +43,8 @@ class Diffusion(BaseRegressor):
37
43
  ----------
38
44
  n_iter : int
39
45
  Number of iterations of the diffusion (must be positive).
46
+ damping_factor : float
47
+ Damping factor.
40
48
 
41
49
  Attributes
42
50
  ----------
@@ -49,24 +57,25 @@ class Diffusion(BaseRegressor):
49
57
  Example
50
58
  -------
51
59
  >>> from sknetwork.data import house
52
- >>> diffusion = Diffusion(n_iter=2)
60
+ >>> diffusion = Diffusion(n_iter=1)
53
61
  >>> adjacency = house()
54
62
  >>> values = {0: 1, 2: 0}
55
63
  >>> values_pred = diffusion.fit_predict(adjacency, values)
56
- >>> np.round(values_pred, 2)
57
- array([0.58, 0.56, 0.38, 0.58, 0.42])
64
+ >>> np.round(values_pred, 1)
65
+ array([0.8, 0.5, 0.2, 0.4, 0.6])
58
66
 
59
67
  References
60
68
  ----------
61
69
  Chung, F. (2007). The heat kernel as the pagerank of a graph. Proceedings of the National Academy of Sciences.
62
70
  """
63
- def __init__(self, n_iter: int = 3):
71
+ def __init__(self, n_iter: int = 3, damping_factor: float = 0.5):
64
72
  super(Diffusion, self).__init__()
65
73
 
66
74
  if n_iter <= 0:
67
75
  raise ValueError('The number of iterations must be positive.')
68
76
  else:
69
77
  self.n_iter = n_iter
78
+ self.damping_factor = damping_factor
70
79
  self.bipartite = None
71
80
 
72
81
  def fit(self, input_matrix: Union[sparse.csr_matrix, np.ndarray],
@@ -98,7 +107,13 @@ class Diffusion(BaseRegressor):
98
107
  values_row=values_row,
99
108
  values_col=values_col)
100
109
  values, _ = init_temperatures(values, init)
101
- diffusion = normalize(adjacency)
110
+ diffusion = normalize(adjacency.T.tocsr())
111
+ degrees = get_degrees(diffusion)
112
+ diag = sparse.diags((degrees == 0).astype(int)).tocsr()
113
+ diffusion += diag
114
+
115
+ diffusion = (1 - self.damping_factor) * sparse.identity(len(degrees)).tocsr() + self.damping_factor * diffusion
116
+
102
117
  for i in range(self.n_iter):
103
118
  values = diffusion.dot(values)
104
119
 
@@ -110,10 +125,9 @@ class Diffusion(BaseRegressor):
110
125
 
111
126
 
112
127
  class Dirichlet(BaseRegressor):
113
- """Regression by the Dirichlet problem, given the temperature of some seed nodes
114
- (heat diffusion with boundary constraints).
128
+ """Regression by the Dirichlet problem (heat diffusion with boundary constraints).
115
129
 
116
- Only values of non-seed nodes are updated. The temperatures of seed nodes are fixed.
130
+ The temperatures of some seed nodes are fixed. The temperatures of other nodes are computed.
117
131
 
118
132
  Parameters
119
133
  ----------
@@ -14,6 +14,13 @@ class TestDiffusion(unittest.TestCase):
14
14
  def setUp(self):
15
15
  self.algos = [Diffusion(), Dirichlet()]
16
16
 
17
+ def test_predict(self):
18
+ adjacency = test_graph()
19
+ for algo in self.algos:
20
+ values = algo.fit_predict(adjacency, {0: 0, 1: 1, 2: 0.5})
21
+ values_ = algo.predict()
22
+ self.assertAlmostEqual(np.linalg.norm(values - values_), 0)
23
+
17
24
  def test_no_iter(self):
18
25
  with self.assertRaises(ValueError):
19
26
  Diffusion(n_iter=-1)
@@ -35,6 +42,7 @@ class TestDiffusion(unittest.TestCase):
35
42
  self.assertTrue(np.all(values <= 1) and np.all(values >= 0))
36
43
  values = algo.fit_predict(biadjacency, values_row={0: 0.1}, values_col={1: 2}, init=0.3)
37
44
  self.assertTrue(np.all(values <= 2) and np.all(values >= 0.1))
45
+ self.assertAlmostEqual(np.linalg.norm(algo.values_col_ - algo.predict(columns=True)), 0)
38
46
 
39
47
  def test_initial_state(self):
40
48
  for adjacency in [test_graph(), test_digraph()]:
@@ -2,5 +2,7 @@
2
2
  from sknetwork.topology.cliques import count_cliques
3
3
  from sknetwork.topology.core import get_core_decomposition
4
4
  from sknetwork.topology.triangles import count_triangles, get_clustering_coefficient
5
- from sknetwork.topology.structure import *
5
+ from sknetwork.topology.structure import is_connected, is_bipartite, is_symmetric, get_connected_components, \
6
+ get_largest_connected_component
7
+ from sknetwork.topology.cycles import is_acyclic, get_cycles, break_cycles
6
8
  from sknetwork.topology.weisfeiler_lehman import color_weisfeiler_lehman, are_isomorphic