kclique.py 2.4 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879
  1. from collections import defaultdict
  2. import networkx as nx
  3. __all__ = ["k_clique_communities"]
  4. @nx._dispatchable
  5. def k_clique_communities(G, k, cliques=None):
  6. """Find k-clique communities in graph using the percolation method.
  7. A k-clique community is the union of all cliques of size k that
  8. can be reached through adjacent (sharing k-1 nodes) k-cliques.
  9. Parameters
  10. ----------
  11. G : NetworkX graph
  12. k : int
  13. Size of smallest clique
  14. cliques: list or generator
  15. Precomputed cliques (use networkx.find_cliques(G))
  16. Returns
  17. -------
  18. Yields sets of nodes, one for each k-clique community.
  19. Examples
  20. --------
  21. >>> G = nx.complete_graph(5)
  22. >>> K5 = nx.convert_node_labels_to_integers(G, first_label=2)
  23. >>> G.add_edges_from(K5.edges())
  24. >>> c = list(nx.community.k_clique_communities(G, 4))
  25. >>> sorted(list(c[0]))
  26. [0, 1, 2, 3, 4, 5, 6]
  27. >>> list(nx.community.k_clique_communities(G, 6))
  28. []
  29. References
  30. ----------
  31. .. [1] Gergely Palla, Imre Derényi, Illés Farkas1, and Tamás Vicsek,
  32. Uncovering the overlapping community structure of complex networks
  33. in nature and society Nature 435, 814-818, 2005,
  34. doi:10.1038/nature03607
  35. """
  36. if k < 2:
  37. raise nx.NetworkXError(f"k={k}, k must be greater than 1.")
  38. if cliques is None:
  39. cliques = nx.find_cliques(G)
  40. cliques = [frozenset(c) for c in cliques if len(c) >= k]
  41. # First index which nodes are in which cliques
  42. membership_dict = defaultdict(list)
  43. for clique in cliques:
  44. for node in clique:
  45. membership_dict[node].append(clique)
  46. # For each clique, see which adjacent cliques percolate
  47. perc_graph = nx.Graph()
  48. perc_graph.add_nodes_from(cliques)
  49. for clique in cliques:
  50. for adj_clique in _get_adjacent_cliques(clique, membership_dict):
  51. if len(clique.intersection(adj_clique)) >= (k - 1):
  52. perc_graph.add_edge(clique, adj_clique)
  53. # Connected components of clique graph with perc edges
  54. # are the percolated cliques
  55. for component in nx.connected_components(perc_graph):
  56. yield (frozenset.union(*component))
  57. def _get_adjacent_cliques(clique, membership_dict):
  58. adjacent_cliques = set()
  59. for n in clique:
  60. for adj_clique in membership_dict[n]:
  61. if clique != adj_clique:
  62. adjacent_cliques.add(adj_clique)
  63. return adjacent_cliques