|
6 | 6 |
|
7 | 7 | import numpy as np |
8 | 8 | from scipy.linalg import expm |
| 9 | +from scipy.stats import ttest_ind |
| 10 | +from bct import degrees_und |
9 | 11 |
|
10 | 12 |
|
11 | 13 | def communicability_bin(adjacency, normalize=False): |
@@ -99,3 +101,86 @@ def communicability_wei(adjacency): |
99 | 101 | cmc[np.diag_indices_from(cmc)] = 0 |
100 | 102 |
|
101 | 103 | return cmc |
| 104 | + |
| 105 | + |
| 106 | +def rich_feeder_peripheral(x, sc, stat='median'): |
| 107 | + """ |
| 108 | + Calculates connectivity values in rich, feeder, and peripheral edges. |
| 109 | +
|
| 110 | + Parameters |
| 111 | + ---------- |
| 112 | + x : (N, N) numpy.ndarray |
| 113 | + Symmetric correlation or connectivity matrix |
| 114 | + sc : (N, N) numpy.ndarray |
| 115 | + Binary structural connectivity matrix |
| 116 | + stat : {'mean', 'median'}, optional |
| 117 | + Statistic to use over rich/feeder/peripheral links. Default: 'median' |
| 118 | +
|
| 119 | + Returns |
| 120 | + ------- |
| 121 | + rfp : (3, k) numpy.ndarray |
| 122 | + Array of median rich (0), feeder (1), and peripheral (2) |
| 123 | + values, defined by `x`. `k` is the maximum degree defined on `sc`. |
| 124 | + pvals : (3, k) numpy.ndarray |
| 125 | + p-value for each link, computed using Welch's t-test. |
| 126 | + Rich links are compared against non-rich links. Feeder links are |
| 127 | + compared against peripheral links. Peripheral links are compared |
| 128 | + against feeder links. T-test is one-sided. |
| 129 | +
|
| 130 | + Author |
| 131 | + ------ |
| 132 | + This code was written by Justine Hansen who promises to fix and even |
| 133 | + optimize the code should any issues arise, provided you let her know. |
| 134 | + """ |
| 135 | + |
| 136 | + stats = ['mean', 'median'] |
| 137 | + if stat not in stats: |
| 138 | + raise ValueError(f'Provided stat {stat} not valid.\ |
| 139 | + Must be one of {stats}') |
| 140 | + |
| 141 | + nnodes = len(sc) |
| 142 | + mask = np.triu(np.ones(nnodes), 1) > 0 |
| 143 | + node_degree = degrees_und(sc) |
| 144 | + k = np.max(node_degree).astype(np.int64) |
| 145 | + rfp_label = np.zeros((len(sc[mask]), k)) |
| 146 | + |
| 147 | + for degthresh in range(k): # for each degree threshold |
| 148 | + hub_idx = np.where(node_degree >= degthresh) # find the hubs |
| 149 | + hub = np.zeros([nnodes, 1]) |
| 150 | + hub[hub_idx, :] = 1 |
| 151 | + |
| 152 | + rfp = np.zeros([nnodes, nnodes]) # for each link, define rfp |
| 153 | + for edge1 in range(nnodes): |
| 154 | + for edge2 in range(nnodes): |
| 155 | + if hub[edge1] + hub[edge2] == 2: |
| 156 | + rfp[edge1, edge2] = 1 # rich |
| 157 | + if hub[edge1] + hub[edge2] == 1: |
| 158 | + rfp[edge1, edge2] = 2 # feeder |
| 159 | + if hub[edge1] + hub[edge2] == 0: |
| 160 | + rfp[edge1, edge2] = 3 # peripheral |
| 161 | + rfp_label[:, degthresh] = rfp[mask] |
| 162 | + |
| 163 | + rfp = np.zeros([3, k]) |
| 164 | + pvals = np.zeros([3, k]) |
| 165 | + for degthresh in range(k): |
| 166 | + |
| 167 | + redfunc = np.median if stat == 'median' else np.mean |
| 168 | + for linktype in range(3): |
| 169 | + rfp[linktype, degthresh] = redfunc(x[mask][rfp_label[:, degthresh] |
| 170 | + == linktype + 1]) |
| 171 | + |
| 172 | + # p-value (one-sided Welch's t-test) |
| 173 | + _, pvals[0, degthresh] = ttest_ind( |
| 174 | + x[mask][rfp_label[:, degthresh] == 1], |
| 175 | + x[mask][rfp_label[:, degthresh] != 1], |
| 176 | + equal_var=False, alternative='greater') |
| 177 | + _, pvals[1, degthresh] = ttest_ind( |
| 178 | + x[mask][rfp_label[:, degthresh] == 2], |
| 179 | + x[mask][rfp_label[:, degthresh] == 3], |
| 180 | + equal_var=False, alternative='greater') |
| 181 | + _, pvals[2, degthresh] = ttest_ind( |
| 182 | + x[mask][rfp_label[:, degthresh] == 3], |
| 183 | + x[mask][rfp_label[:, degthresh] == 2], |
| 184 | + equal_var=False, alternative='greater') |
| 185 | + |
| 186 | + return rfp, pvals |
0 commit comments