5
5
# Imports
6
6
#-----------------------------------------------------------------------------
7
7
8
-
9
8
import networkx as nx
10
9
import numpy as np
11
10
from scipy import sparse
12
11
13
12
#-----------------------------------------------------------------------------
14
13
# Functions
15
14
#-----------------------------------------------------------------------------
15
+
16
+ def inter_node_distances (graph ):
17
+ """Compute the shortest path lengths between all nodes in graph.
18
+
19
+ This performs the same operation as NetworkX's
20
+ all_pairs_shortest_path_lengths with two exceptions: Here, self
21
+ paths are excluded from the dictionary returned, and the distance
22
+ between disconnected nodes is set to infinity. The latter
23
+ difference is consistent with the Brain Connectivity Toolbox for
24
+ Matlab.
25
+
26
+ Parameters
27
+ ----------
28
+ graph: networkx Graph
29
+ An undirected graph.
30
+
31
+ Returns
32
+ -------
33
+ lengths: dictionary
34
+ Dictionary of shortest path lengths keyed by source and target.
35
+
36
+ """
37
+ lengths = nx .all_pairs_shortest_path_length (graph )
38
+ node_labels = sorted (lengths )
39
+ for src in node_labels :
40
+ lengths [src ].pop (src )
41
+ for targ in node_labels :
42
+ if src != targ :
43
+ try :
44
+ lengths [src ][targ ]
45
+ except KeyError :
46
+ lengths [src ][targ ] = np .inf
47
+ return lengths
48
+
49
+
16
50
def compute_sigma (arr ,clustarr ,lparr ):
17
51
""" Function for computing sigma given a graph array arr and clust and lp
18
52
arrays from a pseudorandom graph for a particular block b."""
@@ -24,35 +58,41 @@ def compute_sigma(arr,clustarr,lparr):
24
58
25
59
return out
26
60
27
- def nodal_pathlengths (G ,n_nodes ):
28
- """ Compute mean path length for each node.
29
- Note: it is unclear how to treat infinite path lengths. For now, I replace them with np.inf, but this may make taking the mean later on difficult
30
- Inputs: G graph data output from mkgraph; n_nodes number of nodes in graph"""
31
- nodal_means = np .zeros ((n_nodes ),dtype = float )
32
- lengths = nx .all_pairs_shortest_path_length (G )
33
- for src ,pair in lengths .iteritems ():
34
- source_paths = []
35
- source_arr = np .array ([])
36
- for targ ,val in pair .items ():
37
- if src == targ :
38
- continue # we want to include src,target repeats, right?
39
- source_paths .append (float (val ))
40
- source_arr = np .array (source_paths )
41
-
42
- if source_arr .size == 0 : #make the mean path length 0 if node is disconnected
43
- source_arr = np .array ([np .nan ])
44
- nodal_means [src ]= source_arr .mean ()
45
- #nodal_array=np.array(nodal_means)
46
- return nodal_means
47
-
48
- def assert_no_selfloops (G ):
49
- """Raise an error if the graph G has any selfloops.
61
+
62
+ def nodal_pathlengths (graph ):
63
+ """Compute mean path length for each node.
64
+
65
+ Parameters
66
+ ----------
67
+ graph: networkx Graph
68
+ An undirected graph.
69
+
70
+ Returns
71
+ -------
72
+ nodal_means: numpy array
73
+ An array with each node's mean shortest path length to all other
74
+ nodes. The array is in ascending order of node labels.
75
+
76
+ Notes
77
+ -----
78
+ Per the Brain Connectivity Toolbox for Matlab, the distance between
79
+ one node and another that cannot be reached from it is set to
80
+ infinity.
81
+
50
82
"""
51
- if G .nodes_with_selfloops ():
83
+ lengths = inter_node_distances (graph )
84
+ nodal_means = [np .mean (lengths [src ].values ()) for src in sorted (lengths )]
85
+ return np .array (nodal_means )
86
+
87
+
88
+ def assert_no_selfloops (graph ):
89
+ """Raise an error if the graph graph has any selfloops.
90
+ """
91
+ if graph .nodes_with_selfloops ():
52
92
raise ValueError ("input graph can not have selfloops" )
53
93
54
- #@profile
55
- def path_lengths (G ):
94
+
95
+ def path_lengths (graph ):
56
96
"""Compute array of all shortest path lengths for the given graph.
57
97
58
98
The length of the output array is the number of unique pairs of nodes that
@@ -64,12 +104,12 @@ def path_lengths(G):
64
104
65
105
Parameters
66
106
----------
67
- G : an undirected graph object.
107
+ graph : an undirected graph object.
68
108
"""
69
109
70
- assert_no_selfloops (G )
110
+ assert_no_selfloops (graph )
71
111
72
- length = nx .all_pairs_shortest_path_length (G )
112
+ length = nx .all_pairs_shortest_path_length (graph )
73
113
paths = []
74
114
seen = set ()
75
115
for src ,targets in length .iteritems ():
@@ -82,7 +122,7 @@ def path_lengths(G):
82
122
83
123
84
124
#@profile
85
- def path_lengthsSPARSE (G ):
125
+ def path_lengthsSPARSE (graph ):
86
126
"""Compute array of all shortest path lengths for the given graph.
87
127
88
128
XXX - implementation using scipy.sparse. This might be faster for very
@@ -99,14 +139,14 @@ def path_lengthsSPARSE(G):
99
139
100
140
Parameters
101
141
----------
102
- G : an undirected graph object.
142
+ graph : an undirected graph object.
103
143
"""
104
144
105
- assert_no_selfloops (G )
145
+ assert_no_selfloops (graph )
106
146
107
- length = nx .all_pairs_shortest_path_length (G )
147
+ length = nx .all_pairs_shortest_path_length (graph )
108
148
109
- nnod = G .number_of_nodes ()
149
+ nnod = graph .number_of_nodes ()
110
150
paths_mat = sparse .dok_matrix ((nnod ,nnod ))
111
151
112
152
for src ,targets in length .iteritems ():
@@ -116,45 +156,59 @@ def path_lengthsSPARSE(G):
116
156
return sparse .triu (paths_mat ,1 ).data
117
157
118
158
119
- def glob_efficiency (G ):
159
+ def glob_efficiency (graph ):
120
160
"""Compute array of global efficiency for the given graph.
121
161
122
162
Global efficiency: returns a list of the inverse path length matrix
123
163
across all nodes The mean of this value is equal to the global efficiency
124
164
of the network."""
125
165
126
- return 1.0 / path_lengths (G )
127
-
128
- def nodal_efficiency (G ):
129
- """Compute array of global efficiency for the given graph.
166
+ return 1.0 / path_lengths (graph )
130
167
131
- Nodal efficiency: XXX - define."""
132
-
133
- nodepaths = []
134
- length = nx .all_pairs_shortest_path_length (G )
135
- for src ,targets in length .iteritems ():
136
- paths = []
137
- for targ ,val in targets .items ():
138
- if src == targ :
139
- continue
140
-
141
- paths .append (1.0 / val )
142
-
143
- nodepaths .append (np .mean (paths ))
144
-
145
- return np .array (nodepaths )
146
168
147
- #@profile
148
- def local_efficiency (G ):
169
+ def nodal_efficiency (graph ):
170
+ """Return array with nodal efficiency for each node in graph.
171
+
172
+ See Achard and Bullmore (2007, PLoS Comput Biol) for the definition
173
+ of nodal efficiency.
174
+
175
+ Parameters
176
+ ----------
177
+ graph: networkx Graph
178
+ An undirected graph.
179
+
180
+ Returns
181
+ -------
182
+ nodal_efficiencies: numpy array
183
+ An array with the nodal efficiency for each node in graph, in
184
+ the order specified by node_labels. The array is in ascending
185
+ order of node labels.
186
+
187
+ Notes
188
+ -----
189
+ Per the Brain Connectivity Toolbox for Matlab, the distance between
190
+ one node and another that cannot be reached from it is set to
191
+ infinity.
192
+
193
+ """
194
+ lengths = inter_node_distances (graph )
195
+ nodal_efficiencies = np .zeros (len (lengths ), dtype = float )
196
+ for src in sorted (lengths ):
197
+ inverse_paths = [1.0 / val for val in lengths [src ].itervalues ()]
198
+ nodal_efficiencies [src ] = np .mean (inverse_paths )
199
+ return nodal_efficiencies
200
+
201
+
202
+ def local_efficiency (graph ):
149
203
"""Compute array of global efficiency for the given grap.h
150
204
151
205
Local efficiency: returns a list of paths that represent the nodal
152
206
efficiencies across all nodes with their direct neighbors"""
153
207
154
208
nodepaths = []
155
- length = nx .all_pairs_shortest_path_length (G )
156
- for n in G .nodes ():
157
- nneighb = nx .neighbors (G ,n )
209
+ length = nx .all_pairs_shortest_path_length (graph )
210
+ for n in graph .nodes ():
211
+ nneighb = nx .neighbors (graph ,n )
158
212
159
213
paths = []
160
214
for src ,targets in length .iteritems ():
@@ -176,19 +230,18 @@ def local_efficiency(G):
176
230
return np .array (nodepaths )
177
231
178
232
179
- #@profile
180
- def local_efficiency (G ):
233
+ def local_efficiency (graph ):
181
234
"""Compute array of local efficiency for the given graph.
182
235
183
236
Local efficiency: returns a list of paths that represent the nodal
184
237
efficiencies across all nodes with their direct neighbors"""
185
238
186
- assert_no_selfloops (G )
239
+ assert_no_selfloops (graph )
187
240
188
241
nodepaths = []
189
- length = nx .all_pairs_shortest_path_length (G )
190
- for n in G :
191
- nneighb = set (nx .neighbors (G ,n ))
242
+ length = nx .all_pairs_shortest_path_length (graph )
243
+ for n in graph :
244
+ nneighb = set (nx .neighbors (graph ,n ))
192
245
193
246
paths = []
194
247
for nei in nneighb :
@@ -205,20 +258,20 @@ def local_efficiency(G):
205
258
return np .array (nodepaths )
206
259
207
260
208
- def dynamical_importance (G ):
209
- """Compute dynamical importance for G .
261
+ def dynamical_importance (graph ):
262
+ """Compute dynamical importance for graph .
210
263
211
264
Ref: Restrepo, Ott, Hunt. Phys. Rev. Lett. 97, 094102 (2006)
212
265
"""
213
266
# spectrum of the original graph
214
- eigvals = nx .adjacency_spectrum (G )
267
+ eigvals = nx .adjacency_spectrum (graph )
215
268
lambda0 = eigvals [0 ]
216
- # Now, loop over all nodes in G , and for each, make a copy of G , remove
269
+ # Now, loop over all nodes in graph , and for each, make a copy of graph , remove
217
270
# that node, and compute the change in lambda.
218
- nnod = G .number_of_nodes ()
271
+ nnod = graph .number_of_nodes ()
219
272
dyimp = np .empty (nnod ,float )
220
273
for n in range (nnod ):
221
- gn = G .copy ()
274
+ gn = graph .copy ()
222
275
gn .remove_node (n )
223
276
lambda_n = nx .adjacency_spectrum (gn )[0 ]
224
277
dyimp [n ] = lambda0 - lambda_n
@@ -227,22 +280,22 @@ def dynamical_importance(G):
227
280
return dyimp
228
281
229
282
230
- def weighted_degree (G ):
283
+ def weighted_degree (graph ):
231
284
"""Return an array of degrees that takes weights into account.
232
285
233
286
For unweighted graphs, this is the same as the normal degree() method
234
287
(though we return an array instead of a list).
235
288
"""
236
- amat = nx .adj_matrix (G ).A # get a normal array out of it
289
+ amat = nx .adj_matrix (graph ).A # get a normal array out of it
237
290
return abs (amat ).sum (0 ) # weights are sums across rows
238
291
239
292
240
- def graph_summary (G ):
293
+ def graph_summary (graph ):
241
294
"""Compute a set of statistics summarizing the structure of a graph.
242
295
243
296
Parameters
244
297
----------
245
- G : a graph object.
298
+ graph : a graph object.
246
299
247
300
threshold : float, optional
248
301
@@ -252,36 +305,44 @@ def graph_summary(G):
252
305
"""
253
306
254
307
# Average path length
255
- lp = path_lengths (G )
256
- clust = np .array (nx .clustering (G ).values ())
257
- glob_eff = glob_efficiency (G )
258
- loc_eff = local_efficiency (G )
308
+ lp = path_lengths (graph )
309
+ clust = np .array (nx .clustering (graph ).values ())
310
+ glob_eff = glob_efficiency (graph )
311
+ loc_eff = local_efficiency (graph )
259
312
260
313
return dict ( lp = lp .mean (), clust = clust .mean (), glob_eff = glob_eff .mean (),
261
314
loc_eff = loc_eff .mean () )
262
315
263
- def nodal_summaryOut (G , n_nodes ):
264
- """ Compute statistics for individual nodes
316
+
317
+ def nodal_summaryOut (graph ):
318
+ """Compute statistics for individual nodes.
265
319
266
320
Parameters
267
321
----------
268
- G: graph data output from mkgraph
269
- out: array output from nodal_summaryOut, so can keep appending
270
- cost: cost value for these calculations
271
- n_nodes: number of nodes in graph.
272
-
322
+ graph: networkx graph
323
+ An undirected graph.
324
+
273
325
Returns
274
326
-------
327
+ dictionary
328
+ The keys of this dictionary are lp (which refers to path
329
+ length), clust (clustering coefficient), b_cen (betweenness
330
+ centrality), c_cen (closeness centrality), nod_eff (nodal
331
+ efficiency), loc_eff (local efficiency), and deg (degree). The
332
+ values are arrays (or lists, in some cases) of metrics, in
333
+ ascending order of node labels.
275
334
276
- A dict with: lp, clust, b_cen, c_cen, nod_eff, loc_eff, degree."""
277
-
278
- lp = nodal_pathlengths (G ,n_nodes ) #can't use the regular one, because it substitutes [] for disconnected nodes
279
- clust = np .array (nx .clustering (G ).values ())
280
- b_cen = np .array (nx .betweenness_centrality (G ).values ())
281
- c_cen = np .array (nx .closeness_centrality (G ).values ())
282
- nod_eff = nodal_efficiency (G )
283
- loc_eff = local_efficiency (G )
284
- deg = G .degree ().values ()
285
-
335
+ """
336
+ lp = nodal_pathlengths (graph )
337
+ clust_dict = nx .clustering (graph )
338
+ clust = np .array ([clust_dict [n ] for n in sorted (clust_dict )])
339
+ b_cen_dict = nx .betweenness_centrality (graph )
340
+ b_cen = np .array ([b_cen_dict [n ] for n in sorted (b_cen_dict )])
341
+ c_cen_dict = nx .closeness_centrality (graph )
342
+ c_cen = np .array ([c_cen_dict [n ] for n in sorted (c_cen_dict )])
343
+ nod_eff = nodal_efficiency (graph )
344
+ loc_eff = local_efficiency (graph )
345
+ deg_dict = graph .degree ()
346
+ deg = [deg_dict [n ] for n in sorted (deg_dict )]
286
347
return dict (lp = lp , clust = clust , b_cen = b_cen , c_cen = c_cen , nod_eff = nod_eff ,
287
- loc_eff = loc_eff ,deg = deg )
348
+ loc_eff = loc_eff , deg = deg )
0 commit comments