-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathclusters.py
More file actions
297 lines (243 loc) · 10.5 KB
/
Copy pathclusters.py
File metadata and controls
297 lines (243 loc) · 10.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
import numpy as np
from itertools import permutations
import markov_clustering as mc
import funcs
def markov_clusters(adj_mat, inflation):
'''
Compute clusters on an adjacency matrix using the Markov Clustering algorithm
Calls markov_clustering.run_mcl to compute clusters. Then returns cluster
membership for each node in adj_mat
Parameters
----------
adj_mat (numpy.array) : Binary matrix of super-threshold correlations
Can be found using get_adjacency_matrix()
inflation (float) : inflation parameter passed to run_mcl
Returns
-------
clusters (list) : List of numbers in order of adj_mat entries, indicating
cluster memberships for each node
'''
result = mc.run_mcl(adj_mat, inflation=inflation)
clusters = mc.get_clusters(result)
return clusters
def delta_matrix(matrix, clusters):
"""
Compute delta matrix where delta[i,j]=1 if i and j belong
to same cluster and i!=j
Parameters
----------
matrix (numpy.array) : Binary matrix of super-threshold correlations
Can be found using get_adjacency_matrix()
clusters (list) : The clusters returned by markov_clusters
Returns
-------
delta (numpy.array) : delta matrix
"""
delta = np.zeros(matrix.shape)
for i in clusters :
for j in permutations(i, 2):
delta[j] = 1
return delta
def modularity(matrix, clusters):
"""
Compute Q value for modularity of cluster assignments within a matrix
Used for assessing optimal clustering using 'test_modularity()'
Parameters
----------
matrix (numpy.array) : Binary matrix of super-threshold correlations
Can be found using get_adjacency_matrix()
clusters (list) : The clusters returned by markov_clusters
Returns
-------
Q (numpy.array) : modularity metric
"""
m = matrix.sum()
matrix_2 = matrix
expected = lambda i,j: (matrix_2[i,:].sum()*matrix[:,j].sum() )
delta = delta_matrix(matrix, clusters)
indices = np.array(delta.nonzero())
Q = sum( matrix[i, j] - expected(i, j)/m for i, j in indices.T )/m
return Q
def test_modularity(matrix,
inflations=[i / 10 for i in range(11, 46)],
expansions=[2]):
'''
Tests clustering quality for Markov clustering with multiple
inflation values
Calls markov_clusters() to compute clusters, for each inflation value
in inflations. Then returns cluster list of Q values for all inflations
Parameters
----------
matrix (numpy.array) : Binary matrix of super-threshold correlations
Can be found using get_adjacency_matrix()
inflations (list(float)) : inflation parameter passed to run_mcl
Returns
-------
Qs (list) : List of modularity metric values for each inflation value
'''
Qs = np.empty((len(inflations), len(expansions)))
for i, inflation in enumerate(inflations):
for j, expansion in enumerate(expansions):
result = mc.run_mcl(matrix, inflation=inflation, expansion=expansion)
clusters = mc.get_clusters(result)
Q = modularity(matrix=result, clusters=clusters)
# print("inflation:", inflation, "expansion:", expansion, "modularity:", Q)
Qs[i, j] = Q
return Qs
def get_cluster_arr(cluster_list_of_tuples):
'''
Convert cluster info from a list of tuples, as provided by the
markov_clustering.run_mcl().get_clusters() function, into a
numpy array the length of the list of Regions (data.index),
where each entry is cluster index
Parameters
----------
cluster_list_of_tuples (List(tuple)) : List of (region_number, cluster_ind)
Returns
-------
clusters_arr (numpy.array) : Array of cluster assignments, sorted by Region index
'''
clusters_arr = np.empty((np.sum([len(cluster) for cluster in cluster_list_of_tuples])))
# Sort cluster_list_of_tuples by sizes of tuples
# to set cluster number based on size of cluster
sorted_cluster_list_of_tuples = sorted(cluster_list_of_tuples, key=len, reverse=True)
for c, ns in enumerate(sorted_cluster_list_of_tuples):
for n in ns:
clusters_arr[n] = c
return clusters_arr
def rearrange_corr_df_by_clusters(corr_df, clusters_arr):
'''
Rearrange rows and columns of a correlation DataFrame by cluster order
Parameters
----------
corr_df (pandas.DataFrame) : DataFrame of correlation coefficients, can be
found with funcs.get_cross_correlation_matrix
clusters_arr (numpy.array) : Array of cluster assignments, sorted by Region index
found with get_cluster_arr
Returns
-------
corr_df_soted (pandas.DataFrame) : DataFrame of correlation coefficients,
sorted by cluster assignments
'''
indices = np.argsort(clusters_arr)
corr_df_sorted = corr_df[corr_df.index[indices]].iloc[indices]
return corr_df_sorted
def rearrange_adj_mat_by_clusters(adj_mat, clusters_arr):
'''
Rearrange rows and columns of an adjacency matrix numpy.array by cluster order
Parameters
----------
adj_mat (numpy.array) : Adjacency matrix found with funcs.get_adjacency_matrix
clusters_arr (numpy.array) : Array of cluster assignments, sorted by Region index
found with get_cluster_arr
Returns
-------
adj_mat_soted (numpy.array) : Adjacency matrix, sorted by cluster assignments
'''
indices = np.argsort(clusters_arr)
adj_mat_sorted = adj_mat[indices][:,indices]
return adj_mat_sorted
def get_cluster_ids_for_groups(data, groups, threshold_type='p', threshold=0.05, method='pearson'):
'''
Compute cluster IDs on a dataset for all groups
Wrapper to start from c-fos cell count data, compute adjacency matrix for
each group, then run markov clustering for each group with multiple
inflation values, and return cluster assignments
Parameters
----------
data (pandas.DataFrame) : data loaded into DataFrame format by 'load_data' function
group (string) : Group name, must be in first MultiIndex level in data
threshold_type (string) : {'p', 'r'} -- determines whether the thresholds
should be passed to 'get_adjacency_matrix' as
'p_threshold' or 'r_threshold'
threshold (float) : threshold value to compute adj_mats for
method (string) : {‘pearson’, ‘kendall’, ‘spearman’}
Passed to both get_adjacency_matrix
Returns
-------
cluster_ids_dict (dict{string: numpy.array}) : Dictionary of cluster assignments
for each group:
{'group_name': clusters_arr}
'''
adj_mat_dict = funcs.get_adj_mat_dict_for_groups(data,
groups,
threshold_type=threshold_type,
threshold=threshold,
method=method
)
cluster_ids_dict = {}
for group in groups:
cluster_ids_dict[group] = get_cluster_ids(adj_mat_dict[group])
return cluster_ids_dict
def get_cluster_ids(adj_mat):
'''
Compute cluster assignments for an adjacency matrix
Uses inflation values from 1.1 to 30.6 and finds 'optimal' inflation value
for Markov Clustering by finding the higher modularity metric
Parameters
----------
adj_mat (numpy.array) : Adjacency matrix found with funcs.get_adjacency_matrix
Returns
-------
clusters_arr (numpy.array) : Array of cluster assignments in order of
rows of adj_mat
'''
inflations = [i / 10 for i in range(11, 306)]
expansions = [2]
Qs = test_modularity(adj_mat, inflations=inflations, expansions=expansions)
clusters = markov_clusters(adj_mat, inflations[np.argmax(Qs)])
clusters_arr = get_cluster_arr(clusters)
return clusters_arr
def get_node_to_cluster(cluster_ids):
'''
Convert cluster array into a dictionary of node index: cluster pairs
Parameters
----------
cluster_ids (list(int) or numpy.array) : iterable of ordered cluster ids
Returns
-------
node_to_cluster (dict{int: int}) : Dict of {node index: cluster id} pairs
'''
node_to_cluster = dict(zip(range(len(cluster_ids)), cluster_ids))
return node_to_cluster
def get_cluster_to_nodes(cluster_ids):
'''
Convert cluster array into a dictionary of cluster id: node index pairs
Parameters
----------
cluster_ids (list(int) or numpy.array) : iterable of ordered cluster ids
Returns
-------
node_to_cluster (dict{int: int}) : Dict of {cluster id: node index} pairs
'''
node_to_cluster = get_node_to_cluster(cluster_ids=cluster_ids)
cluster_to_nodes = dict()
for key, value in node_to_cluster.items():
cluster_to_nodes.setdefault(value, set()).add(key)
return cluster_to_nodes
def trim_disconnected_nodes(data, adj_mat, cluster_ids, min_size=2):
'''
Remove nodes from data sets that are in small clusters
Finds clustsers of size < min_size, and removes nodes in those clustsers
from data, adj_mat and cluster_ids
Parameters
----------
data (pandas.DataFrame) : data loaded into DataFrame format by 'load_data' function
adj_mat (numpy.array) : Adjacency matrix found with funcs.get_adjacency_matrix
cluster_ids (list(int) or numpy.array) : iterable of ordered cluster ids
Returns
-------
trimmed_data (pandas.DataFrame) : trimmed data frame of input data
trimmed_adj_mat (numpy.array) : trimmed adjacency matrix
trimmed_cluster_ids (list(int) or numpy.array) : trimmed iterable of
ordered cluster ids
'''
cluster_to_nodes = get_cluster_to_nodes(cluster_ids)
nodes_to_trim = []
for cluster_id, cluster_nodes in cluster_to_nodes.items():
if len(cluster_nodes) < min_size:
nodes_to_trim.extend(cluster_nodes)
trimmed_data = data.drop(data.index[nodes_to_trim])
trimmed_adj_mat = np.delete(np.delete(adj_mat, nodes_to_trim, axis=0), nodes_to_trim, axis=1)
trimmed_cluster_ids = np.delete(cluster_ids, nodes_to_trim)
return trimmed_data, trimmed_adj_mat, trimmed_cluster_ids