Skip to content

Commit 2819e02

Browse files
committed
[ENH] Added rich_feeder_peripheral function
1 parent 79936ea commit 2819e02

File tree

1 file changed

+79
-1
lines changed

1 file changed

+79
-1
lines changed

netneurotools/metrics.py

Lines changed: 79 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@
66

77
import numpy as np
88
from scipy.linalg import expm
9-
9+
from scipy.stats import ttest_ind
10+
from bct import degrees_und
1011

1112
def communicability_bin(adjacency, normalize=False):
1213
"""
@@ -99,3 +100,80 @@ def communicability_wei(adjacency):
99100
cmc[np.diag_indices_from(cmc)] = 0
100101

101102
return cmc
103+
104+
def rich_feeder_peripheral(x, sc, stat = 'median'):
105+
"""
106+
Calculates median or mean "connectivity" in rich (hub to hub), feeder (hub to non-hub),
107+
and peripheral (non-hub to non-hub) links.
108+
109+
This function takes a square symmetric correlation/connectivity matrix `x`
110+
and computes the median or mean value within rich, feeder, and peripheral links.
111+
Hubs are defined againt a threshold (from 0 to the maximum degree `k`,
112+
defined on the structural connectivity matrix, `sc`).
113+
114+
115+
Parameters
116+
----------
117+
x : (N, N) symmetric numpy.ndarray.
118+
sc : (N, N) symmetric numpy.ndarray
119+
binary structural connectivity matrix
120+
stat : 'median' (default) or 'mean'.
121+
statistic to use over rich/feeder/peripheral links.
122+
123+
Returns
124+
-------
125+
rfp : (3, k) numpy.ndarray of median rich (0), feeder (1), and peripheral (2)
126+
values, defined by `x`. `k` is the maximum degree defined on `sc`.
127+
pvals : (3, k) numpy.ndarray p-value for each link, computed using Welch's t-test.
128+
Rich links are compared against non-rich links. Feeder links are
129+
compared against peripheral links. Peripheral links are compared
130+
against feeder links. T-test is two-sided.
131+
132+
Author
133+
------
134+
This code was written by Justine Hansen who promises to fix and even
135+
optimize the code should any issues arise, provided you let her know.
136+
137+
"""
138+
nnodes = len(sc)
139+
mask = np.triu(np.ones(nnodes),1) > 0
140+
node_degree = degrees_und(sc)
141+
k = np.max(node_degree).astype(np.int64)
142+
rfp_label = np.zeros((len(sc[mask]),k))
143+
144+
for i in range(k): # for each degree threshold
145+
hub_idx = np.where(node_degree >= i) # find the hubs
146+
hub = np.zeros([nnodes,1])
147+
hub[hub_idx,:] = 1
148+
149+
rfp = np.zeros([nnodes,nnodes]) # for each link, define rfp
150+
for ii in range(nnodes):
151+
for iii in range(nnodes):
152+
if hub[ii] + hub[iii] == 2:
153+
rfp[ii,iii] = 1 # rich
154+
if hub[ii] + hub[iii] == 1:
155+
rfp[ii,iii] = 2 # feeder
156+
if hub[ii] + hub[iii] == 0:
157+
rfp[ii,iii] = 3 # peripheral
158+
rfp_label[:,i] = rfp[mask]
159+
160+
rfp = np.zeros([3,k])
161+
pvals = np.zeros([3,k])
162+
for i in range(k):
163+
164+
if stat == 'median':
165+
rfp[0,i] = np.median(x[rfp_label[:,i] == 1]) # rich
166+
rfp[1,i] = np.median(x[rfp_label[:,i] == 2]) # feeder
167+
rfp[2,i] = np.median(x[rfp_label[:,i] == 3]) # peripheral
168+
169+
if stat == 'mean':
170+
rfp[0,i] = np.mean(x[rfp_label[:,i] == 1]) # rich
171+
rfp[1,i] = np.mean(x[rfp_label[:,i] == 2]) # feeder
172+
rfp[2,i] = np.mean(x[rfp_label[:,i] == 3]) # peripheral
173+
174+
# p-value
175+
_, pvals[0,i] = ttest_ind(x[rfp_label[:,i] == 1], x[rfp_label[:,i] != 1], equal_var=False) # Welch's t-test
176+
_, pvals[1,i] = ttest_ind(x[rfp_label[:,i] == 2], x[rfp_label[:,i] == 3], equal_var=False)
177+
_, pvals[2,i] = ttest_ind(x[rfp_label[:,i] == 3], x[rfp_label[:,i] == 2], equal_var=False)
178+
179+
return rfp, pvals

0 commit comments

Comments
 (0)