├── CliquePercolationMethod.py
├── LICENSE
├── README.md
└── karate.GraphML
/CliquePercolationMethod.py:
--------------------------------------------------------------------------------
1 | from igraph import Graph, summary, plot
2 | from functools import partial
3 | from multiprocessing.pool import Pool
4 | import time
5 |
6 |
7 | def clique_percolation_method(graph, k = 3, workers = 1, attribute = None, verbose = False):
8 | """
9 | Function that implements the Clique Percolation Method (CPM) algorithm for
10 | finding overlapping communities within networks, introduced by Palla et al. (2005).
11 |
12 | Parameters
13 | ----------
14 | graph : igraph object
15 | The igraph object containing the graph.
16 | k : int, optional
17 | Size of the clique. The default is 3.
18 | workers : int, optional
19 | Number of threads to allocate for running this algorithm. The default is 1.
20 | attribute : str, optional
21 | The attribute of the vertices to use for displaying nodes within the communities.
22 | For displaying purposes, if vertices have names, the latter can be quite handy to figure out which node belongs to a certain community.
23 | If no attribute is given, the algorithm will display their id. The default is None.
24 | verbose : bool, optional
25 | If set to True it shows status updates. The default is False.
26 |
27 | Raises
28 | ------
29 | TypeError
30 | If the types of the variables passed are incorrect.
31 | ValueError
32 | If the values of the variables passed are incorrect.
33 |
34 | Returns
35 | -------
36 | list
37 | Contains lists of communities (lists).
38 |
39 | """
40 | if not isinstance(graph,Graph):
41 | raise TypeError("The object graph must be an instance of the igraph class")
42 |
43 | if not isinstance(k,int):
44 | raise TypeError("Expecting size of cliques (k) to be an integer")
45 |
46 | if not isinstance(workers,int):
47 | raise TypeError("Number of workers must be integer")
48 |
49 | if workers < 1:
50 | raise ValueError("Expecting number of workers greater than or equal to 1")
51 |
52 | if attribute is not None:
53 | if not isinstance(attribute,str):
54 | raise TypeError("Expecting attribute to be a string")
55 |
56 | if attribute not in graph.vs.attributes():
57 | raise ValueError("Attribute {} in vertices does not exist".format(attribute))
58 |
59 | if not isinstance(verbose,bool):
60 | raise TypeError("Field verbose must be set to either True or False")
61 |
62 | communities = list()
63 |
64 | if verbose:
65 | start_time = time.time()
66 |
67 | # FINDING CLIQUES
68 | cliques = graph.cliques(min=k, max=k)
69 | num_cliques = len(cliques)
70 |
71 | if verbose:
72 | print("Finished cliques --- %s seconds ---" % (time.time() - start_time))
73 | print("Cliques found %s" % (num_cliques))
74 |
75 | set_cliques = [set(i) for i in cliques]
76 |
77 | # FINDING CLIQUE GRAPH
78 | indices = list(range(num_cliques))
79 |
80 | edge_list = list()
81 | minimum = k-1
82 | annotate = partial(partial_clique_graph, set_cliques=set_cliques, minimum=minimum, num_cliques=num_cliques)
83 |
84 | pool = Pool(workers)
85 | edges = pool.map(annotate, indices)
86 | edge_list = [j for i in edges for j in i]
87 |
88 | if verbose:
89 | print("Finished comparison cliques --- %s seconds ---" % (time.time() - start_time))
90 |
91 | clique_graph = Graph(edge_list)
92 | clique_graph.vs["name"] = [i for i in range(0,num_cliques)]
93 |
94 | # FINDING CONNECTED COMPONENTS IN THE GRAPH
95 | components = clique_graph.decompose()
96 |
97 | # CREATING COMMUNITIES
98 | for component in components:
99 | members_list = [list(cliques[i["name"]]) for i in component.vs]
100 | this_community = [item for sublist in members_list for item in sublist]
101 | communities.append(list(set(this_community)))
102 |
103 | if attribute is not None:
104 | communities_with_names = list()
105 | for community in communities:
106 | communities_with_names.append([graph.vs[element][attribute] for element in community])
107 | communities = communities_with_names
108 |
109 | if verbose:
110 | print("Finished all --- %s seconds ---" % (time.time() - start_time))
111 |
112 | for comm in communities:
113 | print(len(comm))
114 |
115 | return communities
116 |
117 |
118 | def partial_clique_graph(i, set_cliques, minimum, num_cliques):
119 | """
120 | Function that supports the creation of the clique graph, the second stage of CPM.
121 | This function is detached from the main function since it is parallelised
122 | (based on the amout of workers).
123 |
124 | Parameters
125 | ----------
126 | i : integer
127 | The iterator for parallelisation.
128 | set_cliques : list(set)
129 | List containing all found cliques. Each clique is a set so it becomes easier to compare
130 | minimum : int
131 | Minimum overlapping between two cliques (size_of_cliques-1).
132 | num_cliques : int
133 | Number of cliques found in the graph.
134 |
135 | Returns
136 | -------
137 | edge_list : list
138 | List of edges belonging to the iterated node.
139 |
140 | """
141 | edge_list = list()
142 | this_set = set_cliques[i]
143 | for j in range(i+1, num_cliques):
144 | if len(this_set.intersection(set_cliques[j])) == minimum:
145 | edge_list.append((i,j))
146 | return edge_list
147 |
148 |
149 | def test():
150 | g = Graph()
151 | g.add_vertices(["1","2","3","4","5","6","7","8","9"])
152 | g.add_edges([("1", "2"), ("1", "3"), ("1", "4"), ("2", "3"), ("3", "4"), ("4", "5"), ("4", "6"), ("5", "6"), ("5", "8"), ("5", "7"), ("6", "8"), ("6", "7"), ("7", "8"), ("7", "9")])
153 | summary(g)
154 | plot(g)
155 | communities = clique_percolation_method(g,3)
156 | print("Cliques:")
157 | for count, comm in enumerate(communities):
158 | print("{}: {}".format(count,[g.vs[i]["name"] for i in comm]))
159 |
160 |
161 | def test_karate():
162 | karate = Graph.Read_GraphML("karate.GraphML")
163 | summary(karate)
164 | communities = clique_percolation_method(karate,3,attribute="name")
165 | print("Cliques:")
166 | for count, comm in enumerate(communities):
167 | print("{}: {}".format(count,comm))
168 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 Angelo Antonio Salatino
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # CliquePercolationMethod-Python
2 | Clique Percolation Method (CPM) is an algorithm for finding overlapping communities within networks, introduced by Palla et al. (2005, see references). This implementation in Python, firstly detects communities of size k, then creates a clique graph. Each community will be represented by each connected component in the clique graph.
3 |
4 | # Algorithm
5 | The algorithm performs the following steps:
6 |
7 | 1- first find all cliques of size k in the graph
8 | 2- then create graph where nodes are cliques of size k
9 | 3- add edges if two nodes (cliques) share k-1 common nodes
10 | 4- each connected component is a community
11 |
12 | # Main Implementations
13 | * clique_percolation_method(graph, k = 3): Implementation of the Clique Percolation Method
14 |
15 | It requires igraph library:
16 | ```
17 | pip install python-igraph
18 | ```
19 |
20 | # Run
21 | In this version, the main script contains some test functionalities that help on how to get going with this algorithm.
22 | ```
23 | import CliquePercolationMethod as cpm
24 |
25 | cpm.text()
26 | # or
27 | cpm.test_karate()
28 | ```
29 |
30 | # Parameters
31 | * **graph** : igraph object
32 | The _igraph object_ containing the graph.
33 | * **k** : int, optional
34 | Size of the clique. The default is _3_.
35 | * **workers** : int, optional
36 | Number of threads to allocate for running this algorithm. The default is _1_.
37 | * **attribute** : str, optional
38 | The attribute of the vertices to use for displaying nodes within the communities.
39 | For displaying purposes, if vertices have names, the latter can be quite handy to figure out which node belongs to a certain community.
40 | If no attribute is given, the algorithm will display their id. The default is _None_.
41 | * **verbose** : bool, optional
42 | If set to _True_ it shows status updates. The default is _False_.
43 |
44 | # Reference
45 | Palla, Gergely, Imre Derényi, Illés Farkas, and Tamás Vicsek. "Uncovering the overlapping community structure of complex networks in nature and society." Nature 435, no. 7043 (2005): 814-818.
46 |
--------------------------------------------------------------------------------
/karate.GraphML:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 | Zachary's karate club network
15 | Wayne W. Zachary. An Information Flow Model for Conflict and Fission in Small Groups. Journal of Anthropological Research Vol. 33, No. 4 452-473
16 | Wayne W. Zachary
17 |
18 | 1
19 | Mr Hi
20 |
21 |
22 | 1
23 | Actor 2
24 |
25 |
26 | 1
27 | Actor 3
28 |
29 |
30 | 1
31 | Actor 4
32 |
33 |
34 | 1
35 | Actor 5
36 |
37 |
38 | 1
39 | Actor 6
40 |
41 |
42 | 1
43 | Actor 7
44 |
45 |
46 | 1
47 | Actor 8
48 |
49 |
50 | 2
51 | Actor 9
52 |
53 |
54 | 2
55 | Actor 10
56 |
57 |
58 | 1
59 | Actor 11
60 |
61 |
62 | 1
63 | Actor 12
64 |
65 |
66 | 1
67 | Actor 13
68 |
69 |
70 | 1
71 | Actor 14
72 |
73 |
74 | 2
75 | Actor 15
76 |
77 |
78 | 2
79 | Actor 16
80 |
81 |
82 | 1
83 | Actor 17
84 |
85 |
86 | 1
87 | Actor 18
88 |
89 |
90 | 2
91 | Actor 19
92 |
93 |
94 | 1
95 | Actor 20
96 |
97 |
98 | 2
99 | Actor 21
100 |
101 |
102 | 1
103 | Actor 22
104 |
105 |
106 | 2
107 | Actor 23
108 |
109 |
110 | 2
111 | Actor 24
112 |
113 |
114 | 2
115 | Actor 25
116 |
117 |
118 | 2
119 | Actor 26
120 |
121 |
122 | 2
123 | Actor 27
124 |
125 |
126 | 2
127 | Actor 28
128 |
129 |
130 | 2
131 | Actor 29
132 |
133 |
134 | 2
135 | Actor 30
136 |
137 |
138 | 2
139 | Actor 31
140 |
141 |
142 | 2
143 | Actor 32
144 |
145 |
146 | 2
147 | Actor 33
148 |
149 |
150 | 2
151 | John A
152 |
153 |
154 | 4
155 |
156 |
157 | 5
158 |
159 |
160 | 3
161 |
162 |
163 | 3
164 |
165 |
166 | 3
167 |
168 |
169 | 3
170 |
171 |
172 | 2
173 |
174 |
175 | 2
176 |
177 |
178 | 2
179 |
180 |
181 | 3
182 |
183 |
184 | 1
185 |
186 |
187 | 3
188 |
189 |
190 | 2
191 |
192 |
193 | 2
194 |
195 |
196 | 2
197 |
198 |
199 | 2
200 |
201 |
202 | 6
203 |
204 |
205 | 3
206 |
207 |
208 | 4
209 |
210 |
211 | 5
212 |
213 |
214 | 1
215 |
216 |
217 | 2
218 |
219 |
220 | 2
221 |
222 |
223 | 2
224 |
225 |
226 | 3
227 |
228 |
229 | 4
230 |
231 |
232 | 5
233 |
234 |
235 | 1
236 |
237 |
238 | 3
239 |
240 |
241 | 2
242 |
243 |
244 | 2
245 |
246 |
247 | 2
248 |
249 |
250 | 3
251 |
252 |
253 | 3
254 |
255 |
256 | 3
257 |
258 |
259 | 2
260 |
261 |
262 | 3
263 |
264 |
265 | 5
266 |
267 |
268 | 3
269 |
270 |
271 | 3
272 |
273 |
274 | 3
275 |
276 |
277 | 3
278 |
279 |
280 | 3
281 |
282 |
283 | 4
284 |
285 |
286 | 2
287 |
288 |
289 | 3
290 |
291 |
292 | 3
293 |
294 |
295 | 2
296 |
297 |
298 | 3
299 |
300 |
301 | 4
302 |
303 |
304 | 1
305 |
306 |
307 | 2
308 |
309 |
310 | 1
311 |
312 |
313 | 3
314 |
315 |
316 | 1
317 |
318 |
319 | 2
320 |
321 |
322 | 3
323 |
324 |
325 | 5
326 |
327 |
328 | 4
329 |
330 |
331 | 3
332 |
333 |
334 | 5
335 |
336 |
337 | 4
338 |
339 |
340 | 2
341 |
342 |
343 | 3
344 |
345 |
346 | 2
347 |
348 |
349 | 7
350 |
351 |
352 | 4
353 |
354 |
355 | 2
356 |
357 |
358 | 4
359 |
360 |
361 | 2
362 |
363 |
364 | 2
365 |
366 |
367 | 4
368 |
369 |
370 | 2
371 |
372 |
373 | 3
374 |
375 |
376 | 3
377 |
378 |
379 | 4
380 |
381 |
382 | 4
383 |
384 |
385 | 5
386 |
387 |
388 |
--------------------------------------------------------------------------------