eigenvector.py 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230
  1. """Functions for computing eigenvector centrality."""
  2. import math
  3. import networkx as nx
  4. from networkx.utils import not_implemented_for
  5. __all__ = ["eigenvector_centrality", "eigenvector_centrality_numpy"]
  6. @nx._dispatch
  7. @not_implemented_for("multigraph")
  8. def eigenvector_centrality(G, max_iter=100, tol=1.0e-6, nstart=None, weight=None):
  9. r"""Compute the eigenvector centrality for the graph `G`.
  10. Eigenvector centrality computes the centrality for a node based on the
  11. centrality of its neighbors. The eigenvector centrality for node $i$ is
  12. the $i$-th element of the vector $x$ defined by the equation
  13. .. math::
  14. Ax = \lambda x
  15. where $A$ is the adjacency matrix of the graph `G` with eigenvalue
  16. $\lambda$. By virtue of the Perron–Frobenius theorem, there is a unique
  17. solution $x$, all of whose entries are positive, if $\lambda$ is the
  18. largest eigenvalue of the adjacency matrix $A$ ([2]_).
  19. Parameters
  20. ----------
  21. G : graph
  22. A networkx graph
  23. max_iter : integer, optional (default=100)
  24. Maximum number of iterations in power method.
  25. tol : float, optional (default=1.0e-6)
  26. Error tolerance used to check convergence in power method iteration.
  27. nstart : dictionary, optional (default=None)
  28. Starting value of eigenvector iteration for each node.
  29. weight : None or string, optional (default=None)
  30. If None, all edge weights are considered equal.
  31. Otherwise holds the name of the edge attribute used as weight.
  32. In this measure the weight is interpreted as the connection strength.
  33. Returns
  34. -------
  35. nodes : dictionary
  36. Dictionary of nodes with eigenvector centrality as the value.
  37. Examples
  38. --------
  39. >>> G = nx.path_graph(4)
  40. >>> centrality = nx.eigenvector_centrality(G)
  41. >>> sorted((v, f"{c:0.2f}") for v, c in centrality.items())
  42. [(0, '0.37'), (1, '0.60'), (2, '0.60'), (3, '0.37')]
  43. Raises
  44. ------
  45. NetworkXPointlessConcept
  46. If the graph `G` is the null graph.
  47. NetworkXError
  48. If each value in `nstart` is zero.
  49. PowerIterationFailedConvergence
  50. If the algorithm fails to converge to the specified tolerance
  51. within the specified number of iterations of the power iteration
  52. method.
  53. See Also
  54. --------
  55. eigenvector_centrality_numpy
  56. pagerank
  57. hits
  58. Notes
  59. -----
  60. The measure was introduced by [1]_ and is discussed in [2]_.
  61. The power iteration method is used to compute the eigenvector and
  62. convergence is **not** guaranteed. Our method stops after ``max_iter``
  63. iterations or when the change in the computed vector between two
  64. iterations is smaller than an error tolerance of
  65. ``G.number_of_nodes() * tol``. This implementation uses ($A + I$)
  66. rather than the adjacency matrix $A$ because it shifts the spectrum
  67. to enable discerning the correct eigenvector even for networks with
  68. multiple dominant eigenvalues.
  69. For directed graphs this is "left" eigenvector centrality which corresponds
  70. to the in-edges in the graph. For out-edges eigenvector centrality
  71. first reverse the graph with ``G.reverse()``.
  72. References
  73. ----------
  74. .. [1] Phillip Bonacich.
  75. "Power and Centrality: A Family of Measures."
  76. *American Journal of Sociology* 92(5):1170–1182, 1986
  77. <http://www.leonidzhukov.net/hse/2014/socialnetworks/papers/Bonacich-Centrality.pdf>
  78. .. [2] Mark E. J. Newman.
  79. *Networks: An Introduction.*
  80. Oxford University Press, USA, 2010, pp. 169.
  81. """
  82. if len(G) == 0:
  83. raise nx.NetworkXPointlessConcept(
  84. "cannot compute centrality for the null graph"
  85. )
  86. # If no initial vector is provided, start with the all-ones vector.
  87. if nstart is None:
  88. nstart = {v: 1 for v in G}
  89. if all(v == 0 for v in nstart.values()):
  90. raise nx.NetworkXError("initial vector cannot have all zero values")
  91. # Normalize the initial vector so that each entry is in [0, 1]. This is
  92. # guaranteed to never have a divide-by-zero error by the previous line.
  93. nstart_sum = sum(nstart.values())
  94. x = {k: v / nstart_sum for k, v in nstart.items()}
  95. nnodes = G.number_of_nodes()
  96. # make up to max_iter iterations
  97. for _ in range(max_iter):
  98. xlast = x
  99. x = xlast.copy() # Start with xlast times I to iterate with (A+I)
  100. # do the multiplication y^T = x^T A (left eigenvector)
  101. for n in x:
  102. for nbr in G[n]:
  103. w = G[n][nbr].get(weight, 1) if weight else 1
  104. x[nbr] += xlast[n] * w
  105. # Normalize the vector. The normalization denominator `norm`
  106. # should never be zero by the Perron--Frobenius
  107. # theorem. However, in case it is due to numerical error, we
  108. # assume the norm to be one instead.
  109. norm = math.hypot(*x.values()) or 1
  110. x = {k: v / norm for k, v in x.items()}
  111. # Check for convergence (in the L_1 norm).
  112. if sum(abs(x[n] - xlast[n]) for n in x) < nnodes * tol:
  113. return x
  114. raise nx.PowerIterationFailedConvergence(max_iter)
  115. def eigenvector_centrality_numpy(G, weight=None, max_iter=50, tol=0):
  116. r"""Compute the eigenvector centrality for the graph G.
  117. Eigenvector centrality computes the centrality for a node based on the
  118. centrality of its neighbors. The eigenvector centrality for node $i$ is
  119. .. math::
  120. Ax = \lambda x
  121. where $A$ is the adjacency matrix of the graph G with eigenvalue $\lambda$.
  122. By virtue of the Perron–Frobenius theorem, there is a unique and positive
  123. solution if $\lambda$ is the largest eigenvalue associated with the
  124. eigenvector of the adjacency matrix $A$ ([2]_).
  125. Parameters
  126. ----------
  127. G : graph
  128. A networkx graph
  129. weight : None or string, optional (default=None)
  130. The name of the edge attribute used as weight.
  131. If None, all edge weights are considered equal.
  132. In this measure the weight is interpreted as the connection strength.
  133. max_iter : integer, optional (default=100)
  134. Maximum number of iterations in power method.
  135. tol : float, optional (default=1.0e-6)
  136. Relative accuracy for eigenvalues (stopping criterion).
  137. The default value of 0 implies machine precision.
  138. Returns
  139. -------
  140. nodes : dictionary
  141. Dictionary of nodes with eigenvector centrality as the value.
  142. Examples
  143. --------
  144. >>> G = nx.path_graph(4)
  145. >>> centrality = nx.eigenvector_centrality_numpy(G)
  146. >>> print([f"{node} {centrality[node]:0.2f}" for node in centrality])
  147. ['0 0.37', '1 0.60', '2 0.60', '3 0.37']
  148. See Also
  149. --------
  150. eigenvector_centrality
  151. pagerank
  152. hits
  153. Notes
  154. -----
  155. The measure was introduced by [1]_.
  156. This algorithm uses the SciPy sparse eigenvalue solver (ARPACK) to
  157. find the largest eigenvalue/eigenvector pair.
  158. For directed graphs this is "left" eigenvector centrality which corresponds
  159. to the in-edges in the graph. For out-edges eigenvector centrality
  160. first reverse the graph with ``G.reverse()``.
  161. Raises
  162. ------
  163. NetworkXPointlessConcept
  164. If the graph ``G`` is the null graph.
  165. References
  166. ----------
  167. .. [1] Phillip Bonacich:
  168. Power and Centrality: A Family of Measures.
  169. American Journal of Sociology 92(5):1170–1182, 1986
  170. http://www.leonidzhukov.net/hse/2014/socialnetworks/papers/Bonacich-Centrality.pdf
  171. .. [2] Mark E. J. Newman:
  172. Networks: An Introduction.
  173. Oxford University Press, USA, 2010, pp. 169.
  174. """
  175. import numpy as np
  176. import scipy as sp
  177. import scipy.sparse.linalg # call as sp.sparse.linalg
  178. if len(G) == 0:
  179. raise nx.NetworkXPointlessConcept(
  180. "cannot compute centrality for the null graph"
  181. )
  182. M = nx.to_scipy_sparse_array(G, nodelist=list(G), weight=weight, dtype=float)
  183. _, eigenvector = sp.sparse.linalg.eigs(
  184. M.T, k=1, which="LR", maxiter=max_iter, tol=tol
  185. )
  186. largest = eigenvector.flatten().real
  187. norm = np.sign(largest.sum()) * sp.linalg.norm(largest)
  188. return dict(zip(G, largest / norm))