kclique.py 2.4 KB

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