nltools 0.6.0.dev0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- nltools/__init__.py +55 -0
- nltools/algorithms/__init__.py +90 -0
- nltools/algorithms/alignment/__init__.py +21 -0
- nltools/algorithms/alignment/procrustes.py +565 -0
- nltools/algorithms/alignment/srm.py +758 -0
- nltools/algorithms/backends.py +1059 -0
- nltools/algorithms/corrections.py +177 -0
- nltools/algorithms/decoding.py +327 -0
- nltools/algorithms/inference/__init__.py +50 -0
- nltools/algorithms/inference/bootstrap.py +1386 -0
- nltools/algorithms/inference/correlation.py +373 -0
- nltools/algorithms/inference/intersubject.py +422 -0
- nltools/algorithms/inference/isc.py +1554 -0
- nltools/algorithms/inference/matrix.py +602 -0
- nltools/algorithms/inference/one_sample.py +288 -0
- nltools/algorithms/inference/random.py +122 -0
- nltools/algorithms/inference/timeseries.py +347 -0
- nltools/algorithms/inference/two_sample.py +212 -0
- nltools/algorithms/inference/utils.py +58 -0
- nltools/algorithms/inference/validation.py +282 -0
- nltools/algorithms/neighborhoods.py +207 -0
- nltools/algorithms/outliers.py +308 -0
- nltools/algorithms/regression.py +83 -0
- nltools/algorithms/signal.py +303 -0
- nltools/algorithms/similarity.py +234 -0
- nltools/algorithms/validation.py +151 -0
- nltools/cross_validation.py +72 -0
- nltools/data/__init__.py +30 -0
- nltools/data/adjacency/__init__.py +875 -0
- nltools/data/adjacency/io.py +111 -0
- nltools/data/adjacency/modeling.py +569 -0
- nltools/data/adjacency/plotting.py +174 -0
- nltools/data/adjacency/state.py +349 -0
- nltools/data/adjacency/stats.py +596 -0
- nltools/data/adjacency/utils.py +79 -0
- nltools/data/atlases/__init__.py +23 -0
- nltools/data/atlases/labeling.py +158 -0
- nltools/data/atlases/loading.py +76 -0
- nltools/data/atlases/registry.py +96 -0
- nltools/data/atlases/reporting.py +456 -0
- nltools/data/braindata/__init__.py +2170 -0
- nltools/data/braindata/analysis.py +1381 -0
- nltools/data/braindata/bootstrap.py +398 -0
- nltools/data/braindata/io.py +896 -0
- nltools/data/braindata/modeling.py +594 -0
- nltools/data/braindata/plotting.py +501 -0
- nltools/data/braindata/prediction.py +1250 -0
- nltools/data/braindata/utils.py +348 -0
- nltools/data/braindata/validation.py +197 -0
- nltools/data/braindata/viewer.js +266 -0
- nltools/data/braindata/viewer.py +770 -0
- nltools/data/combine.py +27 -0
- nltools/data/designmatrix/__init__.py +1032 -0
- nltools/data/designmatrix/append.py +518 -0
- nltools/data/designmatrix/diagnostics.py +248 -0
- nltools/data/designmatrix/io.py +356 -0
- nltools/data/designmatrix/plotting.py +291 -0
- nltools/data/designmatrix/regressors.py +463 -0
- nltools/data/designmatrix/transforms.py +200 -0
- nltools/data/designmatrix/utils.py +350 -0
- nltools/data/ownership.py +129 -0
- nltools/data/results.py +291 -0
- nltools/data/roc/__init__.py +398 -0
- nltools/data/simulator/__init__.py +927 -0
- nltools/data/simulator/haxby.py +124 -0
- nltools/data/validation.py +83 -0
- nltools/datasets.py +218 -0
- nltools/io/__init__.py +10 -0
- nltools/io/events.py +67 -0
- nltools/io/h5.py +246 -0
- nltools/mask.py +403 -0
- nltools/models/__init__.py +11 -0
- nltools/models/glm.py +543 -0
- nltools/models/results.py +49 -0
- nltools/models/ridge.py +1303 -0
- nltools/models/validation.py +26 -0
- nltools/plotting/__init__.py +32 -0
- nltools/plotting/adjacency.py +421 -0
- nltools/plotting/brain.py +669 -0
- nltools/plotting/decomposition.py +111 -0
- nltools/plotting/prediction.py +110 -0
- nltools/resources/covariates_example.csv +161 -0
- nltools/resources/onsets_example.csv +40 -0
- nltools/templates/__init__.py +51 -0
- nltools/templates/config.py +144 -0
- nltools/templates/fetch.py +260 -0
- nltools/templates/matching.py +183 -0
- nltools/templates/paths.py +106 -0
- nltools/templates/registry.py +25 -0
- nltools/utils.py +230 -0
- nltools/version.py +13 -0
- nltools-0.6.0.dev0.dist-info/METADATA +95 -0
- nltools-0.6.0.dev0.dist-info/RECORD +95 -0
- nltools-0.6.0.dev0.dist-info/WHEEL +4 -0
- nltools-0.6.0.dev0.dist-info/licenses/LICENSE +21 -0
|
@@ -0,0 +1,875 @@
|
|
|
1
|
+
"""Provide data structures for working with similarity and dissimilarity matrices."""
|
|
2
|
+
|
|
3
|
+
from copy import deepcopy
|
|
4
|
+
import numpy as np
|
|
5
|
+
import polars as pl
|
|
6
|
+
from sklearn.metrics.pairwise import pairwise_distances
|
|
7
|
+
|
|
8
|
+
from nltools.utils import _attempt_to_import
|
|
9
|
+
from .utils import _apply_stat, _perform_arithmetic
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
# Optional dependencies
|
|
13
|
+
nx = _attempt_to_import("networkx")
|
|
14
|
+
|
|
15
|
+
MAX_INT = np.iinfo(np.int32).max
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class Adjacency:
|
|
19
|
+
"""Represent adjacency matrices in vectorized form.
|
|
20
|
+
|
|
21
|
+
Store distance/similarity matrices as strict upper triangles and directed
|
|
22
|
+
matrices as full row-major vectors. Symmetric reconstruction always has a
|
|
23
|
+
zero diagonal; input diagonals are discarded. Flat rectangular stacks require
|
|
24
|
+
an explicit `*_flat` matrix type. A list or 2-D flat array retains stack rank,
|
|
25
|
+
including one matrix. A zero-length symmetric vector represents one node.
|
|
26
|
+
Construction and result methods return independently owned mutable state.
|
|
27
|
+
|
|
28
|
+
Args:
|
|
29
|
+
data (Adjacency | np.ndarray | pd.DataFrame | pl.DataFrame | str | Path | list): A square
|
|
30
|
+
matrix, a flattened vector, a `.csv`/`.h5` path, or a list of
|
|
31
|
+
matrices/`Adjacency` instances/`.csv` paths to stack.
|
|
32
|
+
Y (pd.DataFrame | pl.DataFrame, optional): Matrix metadata, one row per matrix.
|
|
33
|
+
None inherits metadata during copy construction.
|
|
34
|
+
matrix_type (str, optional): Type of matrix. One of `'distance'`, `'similarity'`,
|
|
35
|
+
`'directed'`, `'distance_flat'`, `'similarity_flat'`, `'directed_flat'`.
|
|
36
|
+
For copy construction, this confirms the existing kind without reinterpreting it.
|
|
37
|
+
labels (list, optional): Shared node labels, or a nested matrix-by-node
|
|
38
|
+
label grid for a stack. None inherits labels during copy construction.
|
|
39
|
+
|
|
40
|
+
Attributes:
|
|
41
|
+
data (np.ndarray): Vectorized matrix values. Shape `(vector_length,)` for a
|
|
42
|
+
single matrix or `(n_matrices, vector_length)` for a stack; symmetric
|
|
43
|
+
matrices store only the upper triangle without the diagonal.
|
|
44
|
+
matrix_type (str): One of `'distance'`, `'similarity'`, `'directed'`, or
|
|
45
|
+
`'empty'` (the `'_flat'` input variants are normalized to their base type).
|
|
46
|
+
is_single_matrix (bool): True for single storage; a one-row stack is False.
|
|
47
|
+
issymmetric (bool): True for distance/similarity matrices, False for directed.
|
|
48
|
+
labels (list): Node labels (empty list when none were given).
|
|
49
|
+
Y (pl.DataFrame): Training labels as a polars DataFrame (possibly empty).
|
|
50
|
+
is_empty (bool): True if the instance holds no matrices.
|
|
51
|
+
n_nodes (int): Number of nodes `n` for an `(n, n)` matrix.
|
|
52
|
+
shape (tuple): Logical shape — `(n_nodes, n_nodes)` for a single matrix,
|
|
53
|
+
`(n_matrices, n_nodes, n_nodes)` for a stack, including typed empty stacks;
|
|
54
|
+
`(0, 0)` for an untyped empty constructor.
|
|
55
|
+
vector_shape (tuple): Shape of the internal vectorized storage (`data.shape`).
|
|
56
|
+
"""
|
|
57
|
+
|
|
58
|
+
def __init__(self, data=None, *, Y=None, matrix_type=None, labels=None):
|
|
59
|
+
from .state import _initialize
|
|
60
|
+
|
|
61
|
+
_initialize(self, data, matrix_type=matrix_type, labels=labels, Y=Y)
|
|
62
|
+
|
|
63
|
+
# ── Dunders (alphabetical) ──────────────────────────────────────────
|
|
64
|
+
|
|
65
|
+
def __add__(self, y):
|
|
66
|
+
return _perform_arithmetic(self, y, np.add, "add")
|
|
67
|
+
|
|
68
|
+
def __copy__(self):
|
|
69
|
+
from nltools.data.ownership import _copy_complete
|
|
70
|
+
|
|
71
|
+
return _copy_complete(self)
|
|
72
|
+
|
|
73
|
+
def __deepcopy__(self, memo):
|
|
74
|
+
from nltools.data.ownership import _copy_complete
|
|
75
|
+
|
|
76
|
+
return _copy_complete(self, memo)
|
|
77
|
+
|
|
78
|
+
def __getitem__(self, index):
|
|
79
|
+
from .state import _select
|
|
80
|
+
|
|
81
|
+
return _select(self, index)
|
|
82
|
+
|
|
83
|
+
def __iter__(self):
|
|
84
|
+
for x in range(len(self)):
|
|
85
|
+
yield self[x]
|
|
86
|
+
|
|
87
|
+
def __len__(self):
|
|
88
|
+
if self.is_single_matrix:
|
|
89
|
+
return 1
|
|
90
|
+
return self.data.shape[0]
|
|
91
|
+
|
|
92
|
+
def __mul__(self, y):
|
|
93
|
+
return _perform_arithmetic(self, y, np.multiply, "multiply")
|
|
94
|
+
|
|
95
|
+
def __radd__(self, y):
|
|
96
|
+
return _perform_arithmetic(self, y, np.add, "add", reverse=True)
|
|
97
|
+
|
|
98
|
+
def __repr__(self):
|
|
99
|
+
return f"{self.__class__.__module__}.{self.__class__.__name__}(shape={self.shape}, Y={self.Y.shape}, is_symmetric={self.issymmetric}, matrix_type={self.matrix_type})"
|
|
100
|
+
|
|
101
|
+
def __rmul__(self, y):
|
|
102
|
+
return _perform_arithmetic(self, y, np.multiply, "multiply", reverse=True)
|
|
103
|
+
|
|
104
|
+
def __rsub__(self, y):
|
|
105
|
+
return _perform_arithmetic(self, y, np.subtract, "subtract", reverse=True)
|
|
106
|
+
|
|
107
|
+
def __sub__(self, y):
|
|
108
|
+
return _perform_arithmetic(self, y, np.subtract, "subtract")
|
|
109
|
+
|
|
110
|
+
def __truediv__(self, y):
|
|
111
|
+
return _perform_arithmetic(self, y, np.divide, "divide")
|
|
112
|
+
|
|
113
|
+
# ── Properties (alphabetical) ───────────────────────────────────────
|
|
114
|
+
|
|
115
|
+
@property
|
|
116
|
+
def Y(self) -> pl.DataFrame:
|
|
117
|
+
"""Training labels as a polars DataFrame (possibly empty)."""
|
|
118
|
+
return self._Y
|
|
119
|
+
|
|
120
|
+
@Y.setter
|
|
121
|
+
def Y(self, value) -> None:
|
|
122
|
+
from .state import _owned_frame
|
|
123
|
+
|
|
124
|
+
self._Y = _owned_frame(value, len(self))
|
|
125
|
+
|
|
126
|
+
@property
|
|
127
|
+
def is_empty(self) -> bool:
|
|
128
|
+
"""Check if Adjacency object is empty.
|
|
129
|
+
|
|
130
|
+
Returns:
|
|
131
|
+
bool: True if the adjacency matrix is empty, False otherwise.
|
|
132
|
+
"""
|
|
133
|
+
return len(self) == 0
|
|
134
|
+
|
|
135
|
+
@property
|
|
136
|
+
def n_nodes(self):
|
|
137
|
+
"""Return the number of nodes in the adjacency matrix.
|
|
138
|
+
|
|
139
|
+
Returns:
|
|
140
|
+
int: Number of nodes (n) for an (n, n) matrix.
|
|
141
|
+
"""
|
|
142
|
+
return self._n_nodes
|
|
143
|
+
|
|
144
|
+
@property
|
|
145
|
+
def shape(self):
|
|
146
|
+
"""Return the logical shape of the adjacency matrix.
|
|
147
|
+
|
|
148
|
+
Returns:
|
|
149
|
+
tuple: `(n_nodes, n_nodes)` for a single matrix, `(n_matrices, n_nodes,
|
|
150
|
+
n_nodes)` for stacked matrices, including typed empty stacks; `(0, 0)`
|
|
151
|
+
for an untyped empty constructor.
|
|
152
|
+
|
|
153
|
+
Note:
|
|
154
|
+
Use `.vector_shape` to get the internal vectorized representation shape.
|
|
155
|
+
"""
|
|
156
|
+
if self.matrix_type == "empty":
|
|
157
|
+
return (0, 0)
|
|
158
|
+
|
|
159
|
+
if self.is_single_matrix:
|
|
160
|
+
return (self.n_nodes, self.n_nodes)
|
|
161
|
+
return (len(self), self.n_nodes, self.n_nodes)
|
|
162
|
+
|
|
163
|
+
@property
|
|
164
|
+
def vector_shape(self):
|
|
165
|
+
"""Return shape of internal vectorized representation.
|
|
166
|
+
|
|
167
|
+
Returns:
|
|
168
|
+
tuple: `(vector_length,)` for a single matrix, `(n_matrices,
|
|
169
|
+
vector_length)` for stacked matrices.
|
|
170
|
+
|
|
171
|
+
Note:
|
|
172
|
+
This is the raw shape of the internal data storage.
|
|
173
|
+
Use `.shape` for the logical (n_nodes, n_nodes) shape.
|
|
174
|
+
"""
|
|
175
|
+
return self.data.shape
|
|
176
|
+
|
|
177
|
+
# ── Public methods (alphabetical) ───────────────────────────────────
|
|
178
|
+
|
|
179
|
+
def append(self, data):
|
|
180
|
+
"""Append data to an Adjacency instance.
|
|
181
|
+
|
|
182
|
+
Args:
|
|
183
|
+
data (Adjacency): Adjacency instance to append.
|
|
184
|
+
|
|
185
|
+
Returns:
|
|
186
|
+
Adjacency: New appended Adjacency instance.
|
|
187
|
+
"""
|
|
188
|
+
from .state import _append
|
|
189
|
+
|
|
190
|
+
return _append(self, data)
|
|
191
|
+
|
|
192
|
+
def bootstrap(
|
|
193
|
+
self,
|
|
194
|
+
statistic,
|
|
195
|
+
*,
|
|
196
|
+
n_samples=5000,
|
|
197
|
+
confidence_level=0.95,
|
|
198
|
+
return_samples=False,
|
|
199
|
+
n_jobs=-1,
|
|
200
|
+
random_state=None,
|
|
201
|
+
progress_bar: bool = False,
|
|
202
|
+
):
|
|
203
|
+
"""Bootstrap an aggregate statistic across a stack of matrices.
|
|
204
|
+
|
|
205
|
+
Resamples matrices with replacement and aggregates the replicates as
|
|
206
|
+
they complete, so what the run holds is the retained tail — about
|
|
207
|
+
``(1 - confidence_level)`` of the replicates per edge — plus one
|
|
208
|
+
dispatch window, rather than all ``n_samples`` matrices.
|
|
209
|
+
|
|
210
|
+
Args:
|
|
211
|
+
statistic (str): Statistic to bootstrap: `'mean'`, `'median'`,
|
|
212
|
+
`'std'`, `'sum'`, `'min'`, or `'max'` — each the corresponding
|
|
213
|
+
NumPy reduction over matrices, with `'std'` at ``ddof=0``.
|
|
214
|
+
n_samples (int): Number of bootstrap replicates, at least two.
|
|
215
|
+
Default 5000.
|
|
216
|
+
confidence_level (float): Confidence level of the reported
|
|
217
|
+
interval, strictly between zero and one. Default 0.95. The
|
|
218
|
+
bounds are the central percentile interval, elementwise
|
|
219
|
+
marginal per edge.
|
|
220
|
+
return_samples (bool): Retain and return every replicate. Default
|
|
221
|
+
False.
|
|
222
|
+
n_jobs (int): CPU worker ceiling. -1 (default) means all cores.
|
|
223
|
+
random_state (int | None): Random seed for reproducibility.
|
|
224
|
+
progress_bar (bool): If True, show a progress bar. Default False.
|
|
225
|
+
|
|
226
|
+
Returns:
|
|
227
|
+
BootstrapResult: ``estimate`` (the statistic on the unresampled
|
|
228
|
+
stack), ``standard_error``, ``ci_lower`` and ``ci_upper`` as
|
|
229
|
+
single-matrix `Adjacency` objects, plus ``samples`` as a NumPy
|
|
230
|
+
array with the bootstrap axis first when
|
|
231
|
+
``return_samples=True``.
|
|
232
|
+
|
|
233
|
+
Examples:
|
|
234
|
+
```python
|
|
235
|
+
boot = adj.bootstrap("mean", n_samples=1000)
|
|
236
|
+
boot.estimate # → Adjacency
|
|
237
|
+
```
|
|
238
|
+
"""
|
|
239
|
+
from .modeling import _bootstrap
|
|
240
|
+
|
|
241
|
+
return _bootstrap(
|
|
242
|
+
self,
|
|
243
|
+
statistic,
|
|
244
|
+
n_samples=n_samples,
|
|
245
|
+
confidence_level=confidence_level,
|
|
246
|
+
return_samples=return_samples,
|
|
247
|
+
n_jobs=n_jobs,
|
|
248
|
+
random_state=random_state,
|
|
249
|
+
progress_bar=progress_bar,
|
|
250
|
+
)
|
|
251
|
+
|
|
252
|
+
def cluster_summary(self, *, clusters=None, summary="mean", scope="within"):
|
|
253
|
+
"""Provide summaries of clusters within Adjacency matrices.
|
|
254
|
+
|
|
255
|
+
Computes mean/median of within and between cluster values. Requires a
|
|
256
|
+
list of cluster ids indicating the row/column of each cluster.
|
|
257
|
+
|
|
258
|
+
Args:
|
|
259
|
+
clusters (list): Cluster label for each row/column.
|
|
260
|
+
summary (str | None): Central tendency, `'mean'` or `'median'`. If None,
|
|
261
|
+
return all values instead of a summary.
|
|
262
|
+
scope (str): Summarize `'within'` cluster or `'between'` clusters.
|
|
263
|
+
|
|
264
|
+
Returns:
|
|
265
|
+
dict: Per-cluster summaries keyed by cluster label.
|
|
266
|
+
"""
|
|
267
|
+
from .stats import _cluster_summary
|
|
268
|
+
|
|
269
|
+
return _cluster_summary(self, clusters=clusters, summary=summary, scope=scope)
|
|
270
|
+
|
|
271
|
+
def copy(self):
|
|
272
|
+
"""Return an independently owned copy, preserving internal aliases and cycles."""
|
|
273
|
+
return deepcopy(self)
|
|
274
|
+
|
|
275
|
+
def distance( # nosemgrep: kwargs-internal-forwarding # forwards to sklearn.metrics.pairwise_distances
|
|
276
|
+
self, metric="correlation", *, include_diag=False, **kwargs
|
|
277
|
+
):
|
|
278
|
+
"""Calculate distance between images within an Adjacency() instance.
|
|
279
|
+
|
|
280
|
+
Args:
|
|
281
|
+
metric (str): Distance metric; any metric accepted by
|
|
282
|
+
`sklearn.metrics.pairwise_distances` (scikit-learn or scipy).
|
|
283
|
+
include_diag (bool): Whether to include the main diagonal when
|
|
284
|
+
computing distances between adjacency matrices. Only applies
|
|
285
|
+
to symmetric matrices. Default False (consistent with how
|
|
286
|
+
symmetric matrices are stored without the diagonal).
|
|
287
|
+
**kwargs (dict): Forwarded to `sklearn.metrics.pairwise_distances`.
|
|
288
|
+
|
|
289
|
+
Returns:
|
|
290
|
+
Adjacency: A 2D distance matrix.
|
|
291
|
+
"""
|
|
292
|
+
if include_diag and self.issymmetric:
|
|
293
|
+
# Get square form and extract upper triangle WITH diagonal
|
|
294
|
+
squares = self.squareform()
|
|
295
|
+
if self.is_single_matrix:
|
|
296
|
+
squares = [squares]
|
|
297
|
+
# Extract upper triangle including diagonal for each matrix
|
|
298
|
+
data_with_diag = []
|
|
299
|
+
for sq in squares:
|
|
300
|
+
mask = np.triu(
|
|
301
|
+
np.ones_like(sq, dtype=bool), k=0
|
|
302
|
+
) # k=0 includes diagonal
|
|
303
|
+
data_with_diag.append(sq[mask])
|
|
304
|
+
data = np.array(data_with_diag)
|
|
305
|
+
else:
|
|
306
|
+
data = np.atleast_2d(self.data)
|
|
307
|
+
|
|
308
|
+
return Adjacency(
|
|
309
|
+
pairwise_distances(data, metric=metric, **kwargs),
|
|
310
|
+
matrix_type="distance",
|
|
311
|
+
)
|
|
312
|
+
|
|
313
|
+
def distance_to_similarity(self, metric="correlation", beta=1):
|
|
314
|
+
"""Convert distance matrix to similarity matrix.
|
|
315
|
+
|
|
316
|
+
Currently only implemented for the 'correlation' and 'euclidean' metrics.
|
|
317
|
+
|
|
318
|
+
Args:
|
|
319
|
+
metric (str): Either 'correlation' or 'euclidean'.
|
|
320
|
+
beta (float): Scale parameter of the exponential used for 'euclidean' (default: 1).
|
|
321
|
+
|
|
322
|
+
Returns:
|
|
323
|
+
Adjacency: The converted similarity matrix.
|
|
324
|
+
"""
|
|
325
|
+
from .state import _distance_to_similarity
|
|
326
|
+
|
|
327
|
+
return _distance_to_similarity(self, metric, beta)
|
|
328
|
+
|
|
329
|
+
def generate_permutations(self, n_permute, random_state=None):
|
|
330
|
+
"""Generate permuted versions of an Adjacency instance lazily.
|
|
331
|
+
|
|
332
|
+
Args:
|
|
333
|
+
n_permute (int): Number of permutations.
|
|
334
|
+
random_state (int | np.random.RandomState, optional): Random seed for
|
|
335
|
+
reproducibility.
|
|
336
|
+
|
|
337
|
+
Yields:
|
|
338
|
+
Adjacency: Permuted version of self.
|
|
339
|
+
|
|
340
|
+
Examples:
|
|
341
|
+
```python
|
|
342
|
+
for perm in adj.generate_permutations(1000):
|
|
343
|
+
out = neural_distance_mat.similarity(perm)
|
|
344
|
+
```
|
|
345
|
+
"""
|
|
346
|
+
from .modeling import _generate_permutations
|
|
347
|
+
|
|
348
|
+
return _generate_permutations(self, n_permute, random_state)
|
|
349
|
+
|
|
350
|
+
def mean(self, axis=0):
|
|
351
|
+
"""Calculate mean of Adjacency.
|
|
352
|
+
|
|
353
|
+
Args:
|
|
354
|
+
axis (int): Calculate mean over matrices (0) or upper triangle (1).
|
|
355
|
+
|
|
356
|
+
Returns:
|
|
357
|
+
float | Adjacency | np.ndarray: A float for a single matrix; an
|
|
358
|
+
Adjacency when `axis=0`; an array when `axis=1`.
|
|
359
|
+
"""
|
|
360
|
+
return _apply_stat(self, np.nanmean, axis)
|
|
361
|
+
|
|
362
|
+
def median(self, axis=0):
|
|
363
|
+
"""Calculate median of Adjacency.
|
|
364
|
+
|
|
365
|
+
Args:
|
|
366
|
+
axis (int): Calculate median over matrices (0) or upper triangle (1).
|
|
367
|
+
|
|
368
|
+
Returns:
|
|
369
|
+
float | Adjacency | np.ndarray: A float for a single matrix; an
|
|
370
|
+
Adjacency when `axis=0`; an array when `axis=1`.
|
|
371
|
+
"""
|
|
372
|
+
return _apply_stat(self, np.nanmedian, axis)
|
|
373
|
+
|
|
374
|
+
def plot( # nosemgrep: kwargs-internal-forwarding # forwards to seaborn via _plot_adjacency
|
|
375
|
+
self, *, limit=3, ax=None, **kwargs
|
|
376
|
+
):
|
|
377
|
+
"""Create a heatmap of an Adjacency matrix.
|
|
378
|
+
|
|
379
|
+
Args:
|
|
380
|
+
limit (int): Number of heatmaps to plot if the object contains multiple
|
|
381
|
+
matrices. Default 3.
|
|
382
|
+
ax (matplotlib.axes.Axes, optional): Axis to draw on (single matrix only).
|
|
383
|
+
**kwargs (dict): Forwarded to `seaborn.heatmap`.
|
|
384
|
+
"""
|
|
385
|
+
from .plotting import _plot_adjacency
|
|
386
|
+
|
|
387
|
+
return _plot_adjacency(self, limit=limit, ax=ax, **kwargs)
|
|
388
|
+
|
|
389
|
+
def plot_between_label_distance( # nosemgrep: kwargs-internal-forwarding # forwards to seaborn via stats.plot_between_label_distance
|
|
390
|
+
self, *, labels=None, ax=None, permutation_test=True, n_permute=5000, **kwargs
|
|
391
|
+
):
|
|
392
|
+
"""Create a heatmap of the average distance between every pair of labels.
|
|
393
|
+
|
|
394
|
+
Args:
|
|
395
|
+
labels (np.ndarray, optional): Group label per node; defaults to the
|
|
396
|
+
stored labels.
|
|
397
|
+
ax (matplotlib.axes.Axes, optional): Axis to draw on.
|
|
398
|
+
permutation_test (bool): Also compute the mean-difference and p-value
|
|
399
|
+
matrices from a two-sample permutation test comparing each
|
|
400
|
+
group's within-label distances against its distances to each
|
|
401
|
+
other group. Default True.
|
|
402
|
+
n_permute (int): Number of permutations for the test. Default 5000.
|
|
403
|
+
**kwargs (dict): Forwarded to `seaborn.heatmap`.
|
|
404
|
+
|
|
405
|
+
Returns:
|
|
406
|
+
tuple[pl.DataFrame, ...]: `(long_df, within_mean_df)` without the
|
|
407
|
+
permutation test, or `(long_df, within_mean_df, mean_diff_df,
|
|
408
|
+
p_df)` with it. `long_df` holds every pairwise distance with its
|
|
409
|
+
`Group` and `Comparison` labels; the others are long-format
|
|
410
|
+
label-pair frames.
|
|
411
|
+
"""
|
|
412
|
+
from .stats import _plot_between_label_distance
|
|
413
|
+
|
|
414
|
+
return _plot_between_label_distance(
|
|
415
|
+
self,
|
|
416
|
+
labels=labels,
|
|
417
|
+
ax=ax,
|
|
418
|
+
permutation_test=permutation_test,
|
|
419
|
+
n_permute=n_permute,
|
|
420
|
+
**kwargs,
|
|
421
|
+
)
|
|
422
|
+
|
|
423
|
+
def plot_label_distance( # nosemgrep: kwargs-internal-forwarding # forwards to seaborn via stats.plot_label_distance
|
|
424
|
+
self, labels=None, ax=None, *, permutation_test=False, n_permute=5000, **kwargs
|
|
425
|
+
):
|
|
426
|
+
"""Create a violin plot of within- and between-label distances.
|
|
427
|
+
|
|
428
|
+
Args:
|
|
429
|
+
labels (np.ndarray, optional): Group label per node; defaults to the
|
|
430
|
+
stored labels.
|
|
431
|
+
ax (matplotlib.axes.Axes, optional): Axis to draw on.
|
|
432
|
+
permutation_test (bool): Run a two-sample permutation test of within
|
|
433
|
+
against between distance for each group. Default False.
|
|
434
|
+
n_permute (int): Number of permutations for the test. Default 5000.
|
|
435
|
+
**kwargs (dict): Forwarded to `seaborn.violinplot`, plus `fontsize`
|
|
436
|
+
for the axis label and title (default 18).
|
|
437
|
+
|
|
438
|
+
Returns:
|
|
439
|
+
pl.DataFrame | tuple[pl.DataFrame, dict]: The long-format frame with
|
|
440
|
+
columns `Distance`, `Type`, `Group`, or `(long_df, stats)` when
|
|
441
|
+
`permutation_test=True`, where `stats` maps each group label to
|
|
442
|
+
its permutation-test result.
|
|
443
|
+
"""
|
|
444
|
+
from .stats import _plot_label_distance
|
|
445
|
+
|
|
446
|
+
return _plot_label_distance(
|
|
447
|
+
self,
|
|
448
|
+
labels,
|
|
449
|
+
ax,
|
|
450
|
+
permutation_test=permutation_test,
|
|
451
|
+
n_permute=n_permute,
|
|
452
|
+
**kwargs,
|
|
453
|
+
)
|
|
454
|
+
|
|
455
|
+
def plot_mds( # nosemgrep: kwargs-internal-forwarding # forwards to matplotlib via plotting.plot_mds
|
|
456
|
+
self,
|
|
457
|
+
*,
|
|
458
|
+
n_components=2,
|
|
459
|
+
metric_mds=True,
|
|
460
|
+
labels=None,
|
|
461
|
+
labels_color=None,
|
|
462
|
+
cmap=None,
|
|
463
|
+
view=(30, 20),
|
|
464
|
+
figsize=None,
|
|
465
|
+
ax=None,
|
|
466
|
+
n_jobs=-1,
|
|
467
|
+
**kwargs,
|
|
468
|
+
):
|
|
469
|
+
"""Plot multidimensional scaling.
|
|
470
|
+
|
|
471
|
+
Args:
|
|
472
|
+
n_components (int): Number of dimensions to project (2 or 3).
|
|
473
|
+
metric_mds (bool): Perform metric (True) or non-metric (False) scaling.
|
|
474
|
+
Default True.
|
|
475
|
+
labels (list, optional): Overrides the labels stored on the instance.
|
|
476
|
+
labels_color (list, optional): One color per label.
|
|
477
|
+
cmap (matplotlib.colors.Colormap, optional): Colormap. Default `plt.cm.hot_r`.
|
|
478
|
+
view (tuple): Elevation/azimuth for a 3-D plot. Default (30, 20).
|
|
479
|
+
figsize (list): Figure size. Default [12, 8].
|
|
480
|
+
ax (matplotlib.axes.Axes, optional): Axis to draw on.
|
|
481
|
+
n_jobs (int): Number of parallel jobs.
|
|
482
|
+
**kwargs (dict): Forwarded to `sklearn.manifold.MDS`.
|
|
483
|
+
"""
|
|
484
|
+
from .plotting import _plot_mds
|
|
485
|
+
|
|
486
|
+
return _plot_mds(
|
|
487
|
+
self,
|
|
488
|
+
n_components=n_components,
|
|
489
|
+
metric_mds=metric_mds,
|
|
490
|
+
labels=labels,
|
|
491
|
+
labels_color=labels_color,
|
|
492
|
+
cmap=cmap,
|
|
493
|
+
view=view,
|
|
494
|
+
figsize=figsize,
|
|
495
|
+
ax=ax,
|
|
496
|
+
n_jobs=n_jobs,
|
|
497
|
+
**kwargs,
|
|
498
|
+
)
|
|
499
|
+
|
|
500
|
+
def plot_silhouette(
|
|
501
|
+
self,
|
|
502
|
+
*,
|
|
503
|
+
labels=None,
|
|
504
|
+
ax=None,
|
|
505
|
+
permutation_test=True,
|
|
506
|
+
n_permute=5000,
|
|
507
|
+
colors=None,
|
|
508
|
+
figsize=(6, 4),
|
|
509
|
+
):
|
|
510
|
+
"""Create a silhouette plot.
|
|
511
|
+
|
|
512
|
+
Args:
|
|
513
|
+
labels (np.ndarray, optional): Cluster/group label per node (overrides
|
|
514
|
+
stored labels).
|
|
515
|
+
ax (matplotlib.axes.Axes, optional): Axis to draw on.
|
|
516
|
+
permutation_test (bool): Whether to run a permutation test. Default True.
|
|
517
|
+
n_permute (int): Number of permutations for the test. Default 5000.
|
|
518
|
+
colors (list, optional): RGB triplets, one per cluster. Default: seaborn
|
|
519
|
+
`'hls'` palette.
|
|
520
|
+
figsize (tuple): Figure size. Default (6, 4).
|
|
521
|
+
|
|
522
|
+
Returns:
|
|
523
|
+
pl.DataFrame: Columns `label` and `mean_silhouette`, plus `p` when
|
|
524
|
+
`permutation_test=True`.
|
|
525
|
+
"""
|
|
526
|
+
from .stats import _plot_silhouette
|
|
527
|
+
|
|
528
|
+
return _plot_silhouette(
|
|
529
|
+
self,
|
|
530
|
+
labels=labels,
|
|
531
|
+
ax=ax,
|
|
532
|
+
permutation_test=permutation_test,
|
|
533
|
+
n_permute=n_permute,
|
|
534
|
+
colors=colors,
|
|
535
|
+
figsize=figsize,
|
|
536
|
+
)
|
|
537
|
+
|
|
538
|
+
def r_to_z(self):
|
|
539
|
+
"""Apply Fisher's r-to-z transformation to each data element."""
|
|
540
|
+
from .stats import _r_to_z
|
|
541
|
+
|
|
542
|
+
return _r_to_z(self)
|
|
543
|
+
|
|
544
|
+
def regress(self, X, *, tail=2):
|
|
545
|
+
"""Run a regression on an adjacency instance.
|
|
546
|
+
|
|
547
|
+
Pass an `Adjacency` as `X` to decompose this matrix with other matrices, or a
|
|
548
|
+
`DesignMatrix` to regress each cell across a stack of matrices.
|
|
549
|
+
|
|
550
|
+
Args:
|
|
551
|
+
X (Adjacency | DesignMatrix): Design matrix.
|
|
552
|
+
tail (int | str): `2`/`'two'` (two-tailed, default) or `1`/`'one'`
|
|
553
|
+
(one-tailed: beta > 0; negate a regressor for the other direction).
|
|
554
|
+
|
|
555
|
+
Returns:
|
|
556
|
+
dict: Keys `beta`, `sigma` (coefficient standard error), `t`, `p`,
|
|
557
|
+
`df`, and `residual`. With DesignMatrix predictors, coefficient
|
|
558
|
+
fields are Adjacency maps per predictor (single for one predictor).
|
|
559
|
+
With Adjacency predictors, a single response is required and
|
|
560
|
+
coefficient fields are native predictor arrays or scalars.
|
|
561
|
+
`df` is a scalar; `residual` retains response shape and metadata.
|
|
562
|
+
"""
|
|
563
|
+
from .modeling import _regress
|
|
564
|
+
|
|
565
|
+
return _regress(self, X, tail=tail)
|
|
566
|
+
|
|
567
|
+
def similarity(
|
|
568
|
+
self,
|
|
569
|
+
data,
|
|
570
|
+
*,
|
|
571
|
+
plot=False,
|
|
572
|
+
method="2d",
|
|
573
|
+
n_permute=5000,
|
|
574
|
+
metric="spearman",
|
|
575
|
+
include_diag=False,
|
|
576
|
+
nan_policy="omit",
|
|
577
|
+
tail=2,
|
|
578
|
+
return_null=False,
|
|
579
|
+
n_jobs=-1,
|
|
580
|
+
random_state=None,
|
|
581
|
+
progress_bar: bool = False,
|
|
582
|
+
):
|
|
583
|
+
"""Calculate similarity between two Adjacency matrices.
|
|
584
|
+
|
|
585
|
+
The default uses Spearman correlation and a permutation test.
|
|
586
|
+
|
|
587
|
+
Args:
|
|
588
|
+
data (Adjacency | np.ndarray): Adjacency to compare against, or a 1-D array
|
|
589
|
+
the same size as `self.data`.
|
|
590
|
+
plot (bool): Plot the two stacked adjacency matrices being compared.
|
|
591
|
+
Default False.
|
|
592
|
+
method (str | None): Permutation scheme, `'1d'`, `'2d'`, or None (no
|
|
593
|
+
permutation test).
|
|
594
|
+
n_permute (int): Number of permutations for the p-value. Default 5000.
|
|
595
|
+
metric (str): `'spearman'`, `'pearson'`, or `'kendall'`.
|
|
596
|
+
include_diag (bool): Only applies to `'directed'` matrices with
|
|
597
|
+
`method=None` or `method='1d'`. Default False (self-similarity is
|
|
598
|
+
uninformative). Symmetric matrices never store the diagonal, so this
|
|
599
|
+
flag is a no-op for them.
|
|
600
|
+
nan_policy (str): How to handle NaN values on the 1-D paths
|
|
601
|
+
(`method='1d'` or `method=None`): `'omit'` removes NaN pairwise
|
|
602
|
+
before computing the correlation (default), `'propagate'` lets NaN
|
|
603
|
+
flow through, `'raise'` errors if any NaN is present.
|
|
604
|
+
`method='2d'` raises on any NaN whatever the policy.
|
|
605
|
+
tail (int | str): `2`/`'two'` (two-tailed, default) or `1`/`'one'`
|
|
606
|
+
(one-tailed, positive direction).
|
|
607
|
+
return_null (bool): If True, also return the null distribution. Default False.
|
|
608
|
+
n_jobs (int): Number of parallel jobs. Default -1 (all cores).
|
|
609
|
+
random_state (int, optional): Random seed for reproducibility.
|
|
610
|
+
progress_bar (bool): If True, show a progress bar. Default False.
|
|
611
|
+
|
|
612
|
+
Returns:
|
|
613
|
+
dict | list[dict]: A correlation result dict with keys
|
|
614
|
+
'correlation' and 'p' for a single matrix, or a list of these
|
|
615
|
+
dicts for a stack.
|
|
616
|
+
|
|
617
|
+
Note:
|
|
618
|
+
`metric` and `method` are easy to mix up. `metric` is the
|
|
619
|
+
correlation used to compare the two matrices. `method` is the
|
|
620
|
+
permutation scheme: `'2d'` shuffles rows and columns together (the
|
|
621
|
+
Mantel test, the right null for a symmetric RDM), `'1d'` shuffles
|
|
622
|
+
the vectorized entries, and None skips the test entirely.
|
|
623
|
+
"""
|
|
624
|
+
from .stats import _similarity
|
|
625
|
+
|
|
626
|
+
return _similarity(
|
|
627
|
+
self,
|
|
628
|
+
data,
|
|
629
|
+
plot=plot,
|
|
630
|
+
method=method,
|
|
631
|
+
n_permute=n_permute,
|
|
632
|
+
metric=metric,
|
|
633
|
+
include_diag=include_diag,
|
|
634
|
+
nan_policy=nan_policy,
|
|
635
|
+
tail=tail,
|
|
636
|
+
return_null=return_null,
|
|
637
|
+
n_jobs=n_jobs,
|
|
638
|
+
random_state=random_state,
|
|
639
|
+
progress_bar=progress_bar,
|
|
640
|
+
)
|
|
641
|
+
|
|
642
|
+
def social_relations_model(self, summarize_results=True, nan_replace=True):
|
|
643
|
+
"""Estimate the social relations model from a matrix for a round-robin design.
|
|
644
|
+
|
|
645
|
+
$$X_{ij} = m + \\alpha_i + \\beta_j + g_{ij} + \\epsilon_{ijl}$$
|
|
646
|
+
|
|
647
|
+
where $X_{ij}$ is the score for person i rating person j, $m$ is the group mean,
|
|
648
|
+
$\\alpha_i$ is person i's actor effect, $\\beta_j$ is person j's partner effect, $g_{ij}$
|
|
649
|
+
is the relationship effect and $\\epsilon_{ijl}$ is the error in measure l for actor i and partner j.
|
|
650
|
+
|
|
651
|
+
This model is primarily concerned with partitioning the variance of the various
|
|
652
|
+
effects. The implementation follows Chapter 8 of Kenny, Kashy, & Cook (2006) and
|
|
653
|
+
the tests replicate the book's examples. Actor scores are rows (lower triangle)
|
|
654
|
+
and partner scores are columns (upper triangle). The minimal sample size to
|
|
655
|
+
estimate these effects is 4.
|
|
656
|
+
|
|
657
|
+
**Model assumptions:** social interactions are exclusively dyadic; people are
|
|
658
|
+
randomly sampled from the population; there are no order effects; the effects
|
|
659
|
+
combine additively and relationships are linear.
|
|
660
|
+
|
|
661
|
+
Args:
|
|
662
|
+
summarize_results (bool): If True, print a formatted summary of model results.
|
|
663
|
+
nan_replace (bool): If True, replace NaN values with row and column means.
|
|
664
|
+
|
|
665
|
+
Returns:
|
|
666
|
+
pd.Series | pd.DataFrame: All of the effects estimated using SRM, as a
|
|
667
|
+
Series (single matrix) or DataFrame (one row per matrix).
|
|
668
|
+
|
|
669
|
+
References:
|
|
670
|
+
Kenny, D. A., Kashy, D. A., & Cook, W. L. (2006). *Dyadic data analysis*.
|
|
671
|
+
Guilford Press.
|
|
672
|
+
"""
|
|
673
|
+
from .modeling import _social_relations_model
|
|
674
|
+
|
|
675
|
+
return _social_relations_model(self, summarize_results, nan_replace)
|
|
676
|
+
|
|
677
|
+
def squareform(self):
|
|
678
|
+
"""Convert adjacency data back to square form.
|
|
679
|
+
|
|
680
|
+
Returns:
|
|
681
|
+
np.ndarray | list[np.ndarray]: Detached square matrix, or a list of
|
|
682
|
+
detached matrices for a stack. Symmetric diagonals are zero.
|
|
683
|
+
"""
|
|
684
|
+
from .state import _to_square
|
|
685
|
+
|
|
686
|
+
return _to_square(self)
|
|
687
|
+
|
|
688
|
+
def stats_label_distance(self, *, labels=None, n_permute=5000, n_jobs=-1):
|
|
689
|
+
"""Calculate permutation tests on within and between label distance.
|
|
690
|
+
|
|
691
|
+
Args:
|
|
692
|
+
labels (np.ndarray, optional): Group label per node; defaults to the
|
|
693
|
+
stored labels.
|
|
694
|
+
n_permute (int): Number of permutations to run. Default 5000.
|
|
695
|
+
n_jobs (int): Number of parallel jobs. Default -1 (all cores).
|
|
696
|
+
|
|
697
|
+
Returns:
|
|
698
|
+
dict: Per-group within-vs-between distance differences and p-values, keyed
|
|
699
|
+
by group label.
|
|
700
|
+
"""
|
|
701
|
+
from .stats import _stats_label_distance
|
|
702
|
+
|
|
703
|
+
return _stats_label_distance(
|
|
704
|
+
self, labels=labels, n_permute=n_permute, n_jobs=n_jobs
|
|
705
|
+
)
|
|
706
|
+
|
|
707
|
+
def std(self, axis=0):
|
|
708
|
+
"""Calculate standard deviation of Adjacency.
|
|
709
|
+
|
|
710
|
+
Args:
|
|
711
|
+
axis (int): Calculate std over matrices (0) or upper triangle (1).
|
|
712
|
+
|
|
713
|
+
Returns:
|
|
714
|
+
float | Adjacency | np.ndarray: A float for a single matrix; an
|
|
715
|
+
Adjacency when `axis=0`; an array when `axis=1`.
|
|
716
|
+
"""
|
|
717
|
+
return _apply_stat(self, np.nanstd, axis)
|
|
718
|
+
|
|
719
|
+
def sum(self, axis=0):
|
|
720
|
+
"""Calculate sum of Adjacency.
|
|
721
|
+
|
|
722
|
+
Args:
|
|
723
|
+
axis (int): Calculate sum over matrices (0) or upper triangle (1).
|
|
724
|
+
|
|
725
|
+
Returns:
|
|
726
|
+
float | Adjacency | np.ndarray: A float for a single matrix; an
|
|
727
|
+
Adjacency when `axis=0`; an array when `axis=1`.
|
|
728
|
+
"""
|
|
729
|
+
return _apply_stat(self, np.nansum, axis)
|
|
730
|
+
|
|
731
|
+
def threshold(self, *, upper=None, lower=None, binarize=False):
|
|
732
|
+
"""Threshold an Adjacency instance.
|
|
733
|
+
|
|
734
|
+
Provide upper and lower values or percentages to perform two-sided
|
|
735
|
+
thresholding. Binarize will return a mask image respecting thresholds
|
|
736
|
+
if provided, otherwise respecting every non-zero value.
|
|
737
|
+
|
|
738
|
+
Args:
|
|
739
|
+
upper (float | str, optional): Upper cutoff. A string such as `'95%'` is
|
|
740
|
+
interpreted as a percentile; None for one-sided thresholding.
|
|
741
|
+
lower (float | str, optional): Lower cutoff. A string such as `'5%'` is
|
|
742
|
+
interpreted as a percentile; None for one-sided thresholding.
|
|
743
|
+
binarize (bool): Return a binarized matrix respecting the thresholds if
|
|
744
|
+
provided, otherwise binarize on every non-zero value. Default False.
|
|
745
|
+
|
|
746
|
+
Returns:
|
|
747
|
+
Adjacency: Thresholded Adjacency instance.
|
|
748
|
+
"""
|
|
749
|
+
from .stats import _threshold
|
|
750
|
+
|
|
751
|
+
return _threshold(self, upper=upper, lower=lower, binarize=binarize)
|
|
752
|
+
|
|
753
|
+
def to_graph(self):
|
|
754
|
+
"""Convert a single Adjacency matrix into a NetworkX graph.
|
|
755
|
+
|
|
756
|
+
This currently works only when `is_single_matrix` is True.
|
|
757
|
+
|
|
758
|
+
Returns:
|
|
759
|
+
networkx.Graph | networkx.DiGraph: `DiGraph` for directed matrices,
|
|
760
|
+
`Graph` otherwise; nodes are relabeled with `labels` when set.
|
|
761
|
+
"""
|
|
762
|
+
from .io import _to_graph
|
|
763
|
+
|
|
764
|
+
return _to_graph(self)
|
|
765
|
+
|
|
766
|
+
def to_square(self):
|
|
767
|
+
"""Convert adjacency back to square matrix format.
|
|
768
|
+
|
|
769
|
+
This is an alias for `squareform`.
|
|
770
|
+
|
|
771
|
+
Returns:
|
|
772
|
+
np.ndarray | list[np.ndarray]: Square matrix representation, or a list
|
|
773
|
+
of them if this object contains multiple adjacency matrices.
|
|
774
|
+
"""
|
|
775
|
+
return self.squareform()
|
|
776
|
+
|
|
777
|
+
def ttest(
|
|
778
|
+
self,
|
|
779
|
+
*,
|
|
780
|
+
popmean=0.0,
|
|
781
|
+
permutation=False,
|
|
782
|
+
n_permute=5000,
|
|
783
|
+
tail=2,
|
|
784
|
+
return_null=False,
|
|
785
|
+
n_jobs=-1,
|
|
786
|
+
random_state=None,
|
|
787
|
+
progress_bar: bool = False,
|
|
788
|
+
):
|
|
789
|
+
"""Run a one-sample t-test across stacked matrices.
|
|
790
|
+
|
|
791
|
+
Tests every stored edge against `popmean` across the matrices in the
|
|
792
|
+
stack.
|
|
793
|
+
|
|
794
|
+
Args:
|
|
795
|
+
popmean (float): Population mean to test against. Default 0.0.
|
|
796
|
+
permutation (bool): If True, take p from a sign-flip permutation
|
|
797
|
+
test on `matrices - popmean`. The reported `t` stays the
|
|
798
|
+
observed parametric statistic. Default False.
|
|
799
|
+
n_permute (int): Number of permutations, used only when
|
|
800
|
+
`permutation=True`. Default 5000.
|
|
801
|
+
tail (int | str): `2`/`'two'` (two-tailed, default) or `1`/`'one'`
|
|
802
|
+
(one-tailed: mean > `popmean`). Applies to both paths.
|
|
803
|
+
return_null (bool): If True, also return the permutation null. Has
|
|
804
|
+
no effect on the parametric path, which computes no null.
|
|
805
|
+
Default False.
|
|
806
|
+
n_jobs (int): Number of parallel jobs. Default -1 (all cores).
|
|
807
|
+
random_state (int, optional): Random seed for reproducibility.
|
|
808
|
+
progress_bar (bool): If True, show a progress bar. Default False.
|
|
809
|
+
|
|
810
|
+
Returns:
|
|
811
|
+
dict: `'mean'`, `'t'`, `'z'` and `'p'` as independent single-matrix
|
|
812
|
+
`Adjacency` results that retain the node count, storage kind
|
|
813
|
+
(including directed) and shared node labels, with matrix
|
|
814
|
+
metadata cleared. `'mean'` is the edgewise mean minus `popmean`;
|
|
815
|
+
`'t'` is the observed one-sample t-statistic on both paths;
|
|
816
|
+
`'p'` is parametric, or the empirical sign-flip p-value when
|
|
817
|
+
`permutation=True`; `'z'` is the tail-aware normal score of `p`.
|
|
818
|
+
With `permutation=True` and `return_null=True` the dict also
|
|
819
|
+
holds `'null_dist'`, an owned `(n_permute, n_edges)` array of
|
|
820
|
+
centered means in flat storage order and in the units of
|
|
821
|
+
`'mean'`. Maps are unthresholded. Apply a cutoff or a
|
|
822
|
+
multiple-comparison correction afterwards.
|
|
823
|
+
|
|
824
|
+
Raises:
|
|
825
|
+
ValueError: If this Adjacency holds fewer than two matrices.
|
|
826
|
+
|
|
827
|
+
Examples:
|
|
828
|
+
```python
|
|
829
|
+
result = stacked.ttest()
|
|
830
|
+
result["mean"] # effect size per edge
|
|
831
|
+
result["t"].squareform() # back to a node-by-node matrix
|
|
832
|
+
|
|
833
|
+
# Threshold after testing, never inside it
|
|
834
|
+
import numpy as np
|
|
835
|
+
|
|
836
|
+
significant = result["t"].copy()
|
|
837
|
+
significant.data = np.where(result["p"].data < 0.05, result["t"].data, 0.0)
|
|
838
|
+
```
|
|
839
|
+
"""
|
|
840
|
+
from .stats import _ttest
|
|
841
|
+
|
|
842
|
+
return _ttest(
|
|
843
|
+
self,
|
|
844
|
+
popmean=popmean,
|
|
845
|
+
permutation=permutation,
|
|
846
|
+
n_permute=n_permute,
|
|
847
|
+
tail=tail,
|
|
848
|
+
return_null=return_null,
|
|
849
|
+
n_jobs=n_jobs,
|
|
850
|
+
random_state=random_state,
|
|
851
|
+
progress_bar=progress_bar,
|
|
852
|
+
)
|
|
853
|
+
|
|
854
|
+
def write(self, file_name, method="long"):
|
|
855
|
+
"""Write the Adjacency to a `.csv` or `.h5` file.
|
|
856
|
+
|
|
857
|
+
HDF5 is the round-trip format: values, matrix kind, node labels, and
|
|
858
|
+
`Y`. CSV stores values only, so a CSV read back loses the labels, `Y`,
|
|
859
|
+
and the matrix kind, and needs an explicit `matrix_type` wherever the
|
|
860
|
+
flat layout is ambiguous. Square CSV output is single-matrix only.
|
|
861
|
+
|
|
862
|
+
Args:
|
|
863
|
+
file_name (str | Path): Output path; an `.h5`/`.hdf5` suffix writes HDF5.
|
|
864
|
+
method (str): Layout for CSV output, `'long'` (vectorized rows) or
|
|
865
|
+
`'square'` (single matrix only).
|
|
866
|
+
"""
|
|
867
|
+
from .io import _write
|
|
868
|
+
|
|
869
|
+
return _write(self, file_name, method)
|
|
870
|
+
|
|
871
|
+
def z_to_r(self):
|
|
872
|
+
"""Convert each z score back into an r value."""
|
|
873
|
+
from .stats import _z_to_r
|
|
874
|
+
|
|
875
|
+
return _z_to_r(self)
|