@@ -38,21 +38,38 @@ def nodal_pathlengths(G, n_nodes):
38
38
Returns
39
39
-------
40
40
nodal_means: numpy array
41
- Array of length n_nodes with each node's mean shortest path
42
- length to other nodes. For disconnected nodes, the value in
43
- this array is np.nan.
41
+ An array with each node's mean shortest path length to all other
42
+ nodes. The array is in ascending order of node labels.
43
+
44
+ Notes
45
+ -----
46
+ This function assumes the nodes are labeled 0 to n_nodes - 1.
47
+
48
+ Per the Brain Connectivity Toolbox for Matlab, the distance between
49
+ one node and another that cannot be reached from it is set to
50
+ infinity.
44
51
45
52
"""
46
53
# float is the default dtype for np.zeros, but we'll choose it explicitly
47
54
# in case numpy ever changes the default to something else.
48
55
nodal_means = np .zeros (n_nodes , dtype = float )
49
56
lengths = nx .all_pairs_shortest_path_length (G )
50
- for src , pair in lengths .iteritems ():
51
- source_arr = np .array ([val for targ , val in pair .iteritems () if src !=
52
- targ ], dtype = float )
53
- if source_arr .size == 0 :
54
- source_arr = np .array ([np .nan ])
55
- nodal_means [src ]= source_arr .mean ()
57
+ # As stated in the Python documentation, "Keys and values are listed in an
58
+ # arbitrary order which is non-random, varies across Python
59
+ # implementations, and depends on the dictionary's history of insertions
60
+ # and deletions." Thus, we cannot assume we'd traverse the nodes in
61
+ # ascending order if we were to iterate through 'lengths'.
62
+ node_labels = range (n_nodes )
63
+ for src in node_labels :
64
+ source_lengths = []
65
+ for targ in node_labels :
66
+ if src != targ :
67
+ try :
68
+ val = lengths [src ][targ ]
69
+ except KeyError :
70
+ val = np .inf
71
+ source_lengths .append (val )
72
+ nodal_means [src ] = np .mean (source_lengths )
56
73
return nodal_means
57
74
58
75
@@ -135,27 +152,54 @@ def glob_efficiency(G):
135
152
of the network."""
136
153
137
154
return 1.0 / path_lengths (G )
138
-
139
- def nodal_efficiency (G ):
140
- """Compute array of global efficiency for the given graph.
141
155
142
- Nodal efficiency: XXX - define."""
143
-
144
- nodepaths = []
145
- length = nx .all_pairs_shortest_path_length (G )
146
- for src ,targets in length .iteritems ():
147
- paths = []
148
- for targ ,val in targets .items ():
149
- if src == targ :
150
- continue
151
-
152
- paths .append (1.0 / val )
153
-
154
- nodepaths .append (np .mean (paths ))
155
-
156
- return np .array (nodepaths )
157
156
158
- #@profile
157
+ def nodal_efficiency (G , n_nodes ):
158
+ """Return array with nodal efficiency for each node in G.
159
+
160
+ See Achard and Bullmore (2007, PLoS Comput Biol) for the definition
161
+ of nodal efficiency.
162
+
163
+ Parameters
164
+ ----------
165
+ G: networkx Graph
166
+ An undirected graph.
167
+
168
+ n_nodes: integer
169
+ Number of nodes in G.
170
+
171
+ Returns
172
+ -------
173
+ nodal_efficiencies: numpy array
174
+ An array with the nodal efficiency for each node in G, in
175
+ the order specified by node_labels. The array is in ascending
176
+ order of node labels.
177
+
178
+ Notes
179
+ -----
180
+ This function assumes the nodes are labeled 0 to n_nodes - 1.
181
+
182
+ Per the Brain Connectivity Toolbox for Matlab, the distance between
183
+ one node and another that cannot be reached from it is set to
184
+ infinity.
185
+
186
+ """
187
+ nodal_efficiencies = np .zeros (n_nodes , dtype = float )
188
+ lengths = nx .all_pairs_shortest_path_length (G )
189
+ node_labels = range (n_nodes )
190
+ for src in node_labels :
191
+ inverse_paths = []
192
+ for targ in node_labels :
193
+ if src != targ :
194
+ try :
195
+ val = lengths [src ][targ ]
196
+ except KeyError :
197
+ val = np .inf
198
+ inverse_paths .append (1.0 / val )
199
+ nodal_efficiencies [src ] = np .mean (inverse_paths )
200
+ return nodal_efficiencies
201
+
202
+
159
203
def local_efficiency (G ):
160
204
"""Compute array of global efficiency for the given grap.h
161
205
@@ -290,17 +334,26 @@ def nodal_summaryOut(G, n_nodes):
290
334
length), clust (clustering coefficient), b_cen (betweenness
291
335
centrality), c_cen (closeness centrality), nod_eff (nodal
292
336
efficiency), loc_eff (local efficiency), and deg (degree). The
293
- values are lists of metrics, in ascending order of node labels.
337
+ values are arrays (or lists, in some cases) of metrics, in
338
+ ascending order of node labels.
294
339
295
340
"""
296
- # nodal_pathlengths is needed because NetworkX's shortest_path_length
297
- # returns an empty list for disconnected nodes.
298
- lp = nodal_pathlengths (G ,n_nodes )
299
- clust = np .array (nx .clustering (G ).values ())
300
- b_cen = np .array (nx .betweenness_centrality (G ).values ())
301
- c_cen = np .array (nx .closeness_centrality (G ).values ())
302
- nod_eff = nodal_efficiency (G )
341
+ lp = nodal_pathlengths (G , n_nodes )
342
+ # As stated in the Python documentation, "Keys and values are listed in an
343
+ # arbitrary order which is non-random, varies across Python
344
+ # implementations, and depends on the dictionary's history of insertions
345
+ # and deletions." Thus, we cannot expect, e.g., nx.clustering(G)
346
+ # to have the nodes listed in ascending order, as we desire.
347
+ node_labels = range (n_nodes )
348
+ clust_dict = nx .clustering (G )
349
+ clust = np .array ([clust_dict [n ] for n in node_labels ])
350
+ b_cen_dict = nx .betweenness_centrality (G )
351
+ b_cen = np .array ([b_cen_dict [n ] for n in node_labels ])
352
+ c_cen_dict = nx .closeness_centrality (G )
353
+ c_cen = np .array ([c_cen_dict [n ] for n in node_labels ])
354
+ nod_eff = nodal_efficiency (G , n_nodes )
303
355
loc_eff = local_efficiency (G )
304
- deg = G .degree ().values ()
356
+ deg_dict = G .degree ()
357
+ deg = [deg_dict [n ] for n in node_labels ]
305
358
return dict (lp = lp , clust = clust , b_cen = b_cen , c_cen = c_cen , nod_eff = nod_eff ,
306
359
loc_eff = loc_eff , deg = deg )
0 commit comments