laplacian.py 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  1. """
  2. Laplacian centrality measures.
  3. """
  4. import networkx as nx
  5. __all__ = ["laplacian_centrality"]
  6. def laplacian_centrality(
  7. G, normalized=True, nodelist=None, weight="weight", walk_type=None, alpha=0.95
  8. ):
  9. r"""Compute the Laplacian centrality for nodes in the graph `G`.
  10. The Laplacian Centrality of a node ``i`` is measured by the drop in the
  11. Laplacian Energy after deleting node ``i`` from the graph. The Laplacian Energy
  12. is the sum of the squared eigenvalues of a graph's Laplacian matrix.
  13. .. math::
  14. C_L(u_i,G) = \frac{(\Delta E)_i}{E_L (G)} = \frac{E_L (G)-E_L (G_i)}{E_L (G)}
  15. E_L (G) = \sum_{i=0}^n \lambda_i^2
  16. Where $E_L (G)$ is the Laplacian energy of graph `G`,
  17. E_L (G_i) is the Laplacian energy of graph `G` after deleting node ``i``
  18. and $\lambda_i$ are the eigenvalues of `G`'s Laplacian matrix.
  19. This formula shows the normalized value. Without normalization,
  20. the numerator on the right side is returned.
  21. Parameters
  22. ----------
  23. G : graph
  24. A networkx graph
  25. normalized : bool (default = True)
  26. If True the centrality score is scaled so the sum over all nodes is 1.
  27. If False the centrality score for each node is the drop in Laplacian
  28. energy when that node is removed.
  29. nodelist : list, optional (default = None)
  30. The rows and columns are ordered according to the nodes in nodelist.
  31. If nodelist is None, then the ordering is produced by G.nodes().
  32. weight: string or None, optional (default=`weight`)
  33. Optional parameter `weight` to compute the Laplacian matrix.
  34. The edge data key used to compute each value in the matrix.
  35. If None, then each edge has weight 1.
  36. walk_type : string or None, optional (default=None)
  37. Optional parameter `walk_type` used when calling
  38. :func:`directed_laplacian_matrix <networkx.directed_laplacian_matrix>`.
  39. If None, the transition matrix is selected depending on the properties
  40. of the graph. Otherwise can be `random`, `lazy`, or `pagerank`.
  41. alpha : real (default = 0.95)
  42. Optional parameter `alpha` used when calling
  43. :func:`directed_laplacian_matrix <networkx.directed_laplacian_matrix>`.
  44. (1 - alpha) is the teleportation probability used with pagerank.
  45. Returns
  46. -------
  47. nodes : dictionary
  48. Dictionary of nodes with Laplacian centrality as the value.
  49. Examples
  50. --------
  51. >>> G = nx.Graph()
  52. >>> edges = [(0, 1, 4), (0, 2, 2), (2, 1, 1), (1, 3, 2), (1, 4, 2), (4, 5, 1)]
  53. >>> G.add_weighted_edges_from(edges)
  54. >>> sorted((v, f"{c:0.2f}") for v, c in laplacian_centrality(G).items())
  55. [(0, '0.70'), (1, '0.90'), (2, '0.28'), (3, '0.22'), (4, '0.26'), (5, '0.04')]
  56. Notes
  57. -----
  58. The algorithm is implemented based on [1]_ with an extension to directed graphs
  59. using the ``directed_laplacian_matrix`` function.
  60. Raises
  61. ------
  62. NetworkXPointlessConcept
  63. If the graph `G` is the null graph.
  64. References
  65. ----------
  66. .. [1] Qi, X., Fuller, E., Wu, Q., Wu, Y., and Zhang, C.-Q. (2012).
  67. Laplacian centrality: A new centrality measure for weighted networks.
  68. Information Sciences, 194:240-253.
  69. https://math.wvu.edu/~cqzhang/Publication-files/my-paper/INS-2012-Laplacian-W.pdf
  70. See Also
  71. --------
  72. directed_laplacian_matrix
  73. laplacian_matrix
  74. """
  75. import numpy as np
  76. import scipy as sp
  77. import scipy.linalg # call as sp.linalg
  78. if len(G) == 0:
  79. raise nx.NetworkXPointlessConcept("null graph has no centrality defined")
  80. if nodelist != None:
  81. nodeset = set(G.nbunch_iter(nodelist))
  82. if len(nodeset) != len(nodelist):
  83. raise nx.NetworkXError("nodelist has duplicate nodes or nodes not in G")
  84. nodes = nodelist + [n for n in G if n not in nodeset]
  85. else:
  86. nodelist = nodes = list(G)
  87. if G.is_directed():
  88. lap_matrix = nx.directed_laplacian_matrix(G, nodes, weight, walk_type, alpha)
  89. else:
  90. lap_matrix = nx.laplacian_matrix(G, nodes, weight).toarray()
  91. full_energy = np.power(sp.linalg.eigh(lap_matrix, eigvals_only=True), 2).sum()
  92. # calculate laplacian centrality
  93. laplace_centralities_dict = {}
  94. for i, node in enumerate(nodelist):
  95. # remove row and col i from lap_matrix
  96. all_but_i = list(np.arange(lap_matrix.shape[0]))
  97. all_but_i.remove(i)
  98. A_2 = lap_matrix[all_but_i, :][:, all_but_i]
  99. # Adjust diagonal for removed row
  100. new_diag = lap_matrix.diagonal() - abs(lap_matrix[:, i])
  101. np.fill_diagonal(A_2, new_diag[all_but_i])
  102. new_energy = np.power(sp.linalg.eigh(A_2, eigvals_only=True), 2).sum()
  103. lapl_cent = full_energy - new_energy
  104. if normalized:
  105. lapl_cent = lapl_cent / full_energy
  106. laplace_centralities_dict[node] = lapl_cent
  107. return laplace_centralities_dict