matrix¶
Matrix permutation test implementations (Mantel test).
This module provides CPU-parallel implementations of matrix permutation tests for testing correlation between two square matrices, as well as matrix utility functions for distance correlation and matrix centering operations.
Attributes:
| Name | Type | Description |
|---|---|---|
MAX_INT |
Methods:
| Name | Description |
|---|---|
distance_correlation | Compute the distance correlation between 2 arrays to test for multivariate dependence (linear or non-linear). |
double_center | Double center a 2d array. |
matrix_permutation_test | Matrix permutation test (Mantel test) for correlating two square matrices. |
u_center | U-center a 2d array. U-centering is a bias-corrected form of double-centering. |
Methods¶
distance_correlation¶
distance_correlation(x: np.ndarray, y: np.ndarray, bias_corrected: bool = True, ttest: bool = False) -> dictCompute the distance correlation between 2 arrays to test for multivariate dependence (linear or non-linear).
Arrays must match on their first dimension. It’s almost always preferable to compute the bias_corrected version which can also optionally perform a ttest. This ttest operates on a statistic thats ~dcorr^2 and will be also returned.
Explanation: Distance correlation involves computing the normalized covariance of two centered euclidean distance matrices. Each distance matrix is the euclidean distance between rows (if x or y are 2d) or scalars (if x or y are 1d). Each matrix is centered prior to computing the covariance either using double-centering or u-centering, which corrects for bias as the number of dimensions increases. U-centering is almost always preferred in all cases. It also permits inference of the normalized covariance between each distance matrix using a one-tailed directional t-test. (Szekely & Rizzo, 2013). While distance correlation is normally bounded between 0 and 1, u-centering can produce negative estimates, which are never significant.
Validated against the dcor and dcor.ttest functions in the ‘energy’ R package and the dcor.distance_correlation, dcor.udistance_correlation_sqr, and dcor.independence.distance_correlation_t_test functions in the dcor Python package.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
x | ndarray | 1d or 2d numpy array of observations by features | required |
y | ndarray | 1d or 2d numpy array of observations by features | required |
bias_corrected | bool | if false use double-centering which produces a biased-estimate that converges to 1 as the number of dimensions increase. Otherwise used u-centering to correct this bias. Note this must be True if ttest=True; default True | True |
ttest | bool | perform a ttest using the bias_corrected distance correlation; default False | False |
Returns:
| Name | Type | Description |
|---|---|---|
results | dict | dictionary of results (correlation, t, p, and df.) Optionally, covariance, x variance, and y variance |
Examples:
>>> import numpy as np
>>> x = np.random.randn(20, 3)
>>> y = x + np.random.randn(20, 3) * 0.1 # Strongly correlated
>>> result = distance_correlation(x, y, bias_corrected=True)
>>> 'dcorr' in result
True
>>> 0 <= result['dcorr'] <= 1
Truedouble_center¶
double_center(mat: np.ndarray) -> np.ndarrayDouble center a 2d array.
Double-centering subtracts row means, column means, and adds the grand mean. This centers both rows and columns around zero.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
mat | ndarray | 2d numpy array | required |
Returns:
| Name | Type | Description |
|---|---|---|
mat | ndarray | double-centered version of input |
Examples:
>>> mat = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]], dtype=float)
>>> result = double_center(mat)
>>> np.allclose(result.mean(axis=0), 0)
True
>>> np.allclose(result.mean(axis=1), 0)
Truematrix_permutation_test¶
matrix_permutation_test(data1: np.ndarray, data2: np.ndarray, *, n_permute: int = 5000, metric: str = 'pearson', how: str = 'upper', include_diag: bool = False, tail: int | str = 2, return_null: bool = False, device: str | None = 'cpu', n_jobs: int = -1, random_state: int | None = None, progress_bar: bool = False) -> dictMatrix permutation test (Mantel test) for correlating two square matrices.
Tests whether the correlation between elements of two matrices is significant by permuting rows and columns of one matrix symmetrically while keeping the other fixed.
Statistical Method:
For each permutation, create random permutation perm, then apply:
matrix1[perm][:, perm]. This preserves matrix structure while destroying
correlation. Count how often permuted correlation is as extreme as observed.
Assumptions:
Matrices are square and same size
Under H₀, row/column ordering is exchangeable
Symmetric permutation preserves matrix properties (e.g., symmetry)
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
data1 | ndarray | First square matrix (n×n) | required |
data2 | ndarray | Second square matrix (n×n) | required |
n_permute | int | Number of permutations (default: 5000) | 5000 |
metric | str | Correlation metric [‘pearson’ | ‘spearman’ |
how | str | Which elements to compare [‘upper’ | ‘lower’ |
include_diag | bool | Include diagonal elements (only applies if how=‘full’) (default: False) | False |
tail | int | str | Test type — 2 | ‘two’ (two-tailed, default) or 1 |
return_null | bool | Return null distribution (default: False) | False |
device | str | Parallelization method (default: ‘cpu’) - None: Single-threaded NumPy (for debugging/small problems) - ‘cpu’: CPU parallelization via joblib (default, 4-8× speedup) | ‘cpu’ |
n_jobs | int | Number of parallel workers, -1 = all cores (default: -1) Only used when device=‘cpu’ | -1 |
random_state | int | Random seed for reproducibility | None |
progress_bar | bool | Show a progress bar over permutations (default: False) | False |
Returns:
| Name | Type | Description |
|---|---|---|
dict | dict | Dictionary with keys: - ‘correlation’ (float): Observed correlation coefficient - ‘p’ (float): P-value using Phipson-Smyth correction - ‘device’ (str): Parallelization method used (‘cpu’ or None) - ‘null_dist’ (np.ndarray): Null distribution (if return_null=True) |
References
Chen, G. et al. (2016). Untangling the relatedness among correlations, part I: nonparametric approaches to inter-subject correlation analysis at the group level. NeuroImage, 142, 248-259.
Mantel, N. (1967). The detection of disease clustering and a generalized regression approach. Cancer Research, 27(2), 209-220.
Examples:
>>> import numpy as np
>>> from nltools.algorithms.inference import matrix_permutation_test
>>>
>>> # Create two correlated similarity matrices
>>> np.random.seed(42)
>>> n = 50
>>> true_pattern = np.random.randn(n)
>>> data1 = np.corrcoef(true_pattern + np.random.randn(n) * 0.1)
>>> data2 = np.corrcoef(true_pattern + np.random.randn(n) * 0.1)
>>>
>>> # Test if matrices are correlated
>>> result = matrix_permutation_test(data1, data2, n_permute=1000)
>>> print(f"Correlation: {result['correlation']:.3f}, p = {result['p']:.4f}")u_center¶
u_center(mat: np.ndarray) -> np.ndarrayU-center a 2d array. U-centering is a bias-corrected form of double-centering.
U-centering corrects for bias that occurs with double-centering as the number of dimensions increases. The diagonal is explicitly set to zero.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
mat | ndarray | 2d numpy array | required |
Returns:
| Name | Type | Description |
|---|---|---|
mat | ndarray | u-centered version of input |
Examples:
>>> mat = np.random.randn(5, 5)
>>> result = u_center(mat)
>>> np.allclose(np.diag(result), 0)
True