Source code for syntropy.gaussian.utils
import numpy as np
import scipy.stats as stats
from numpy.typing import NDArray
# %% LIBRARY
[docs]
def check_cov(
cov: NDArray[np.floating] | None, data: NDArray[np.floating]
) -> NDArray[np.floating]:
if cov is None:
cov_ = np.cov(data, ddof=0)
else:
assert cov.shape[0] == data.shape[0], (
"The data and given covariance matrix must have the same dimensionality"
)
cov_ = cov.copy()
return cov_
[docs]
def correlation_to_mutual_information(
cov: NDArray[np.floating],
) -> NDArray[np.floating]:
"""
Converts a Pearson correlation matrix to a Guassian mutual
information matrix based on the identity:
:math:`I(X;Y) = \\frac{-\\log(1-(r_{XY})^2)}{2}`
Where :math:`r_{XY}` is the Pearson correlation coefficient between :math:`X` and :math:`Y`.
Also works for a covariance matrix if the processes have 0 mean
and unit variance.
Parameters
----------
cov : NDArray[np.floating]
A covariance matrix.
Returns
-------
NDArray[np.floating]
The equivalent mutual information matrix.
"""
mi = -np.log(1 - (cov**2)) / 2.0
np.fill_diagonal(mi, np.nan)
return mi
[docs]
def copula_transform(
X: NDArray[np.floating],
) -> tuple[NDArray[np.floating], ...]:
"""
Transform data to Gaussian copula space and compute the correlation matrix. Useful for copula-based information estimators.
The resulting data can be plugged into any local or expected information estimator.
Parameters
----------
X : ndarray, shape (n_channels, n_samples)
Input data (channels x samples)
Returns
-------
Z : NDArray[np.floating]
Gaussianized copula data (zero-mean, unit-variance)
R : NDArray[np.floating]
Copula correlation matrix
References
----------
Ince, R. A. A., Giordano, B. L., Kayser, C., Rousselet, G. A., Gross, J., & Schyns, P. G. (2016).
A statistical framework for neuroimaging data analysis based on mutual information estimated via a gaussian copula.
Human Brain Mapping, 38(3), 1541–1573.
https://doi.org/10.1002/hbm.23471
"""
N0: int
N1: int
N0, N1 = X.shape
# Step 1: rank transform to uniforms
U: NDArray[np.floating] = np.zeros_like(X)
for i in range(N0):
ranks = stats.rankdata(X[i, :], method="average")
U[i, :] = (ranks - 0.5) / N1 # rescale to (0,1)
# Step 2: map uniforms to standard normal
Z: NDArray[np.floating] = stats.norm.ppf(U)
# Step 3: correlation matrix of transformed data
R: NDArray[np.floating] = np.corrcoef(Z)
return Z, R
[docs]
def covariance_to_correlation(cov: NDArray[np.floating]) -> NDArray[np.floating]:
"""
Converts a non-standardized covariance matrix to a correlation matrix.
Parameters
----------
cov : NDArray[np.floating]
The covariance matrix.
Returns
-------
NDArray[np.floating]
The correlation matrix.
"""
diag: NDArray[np.floating] = np.sqrt(np.diag(cov))
d_inv: NDArray[np.floating] = np.diag(1.0 / diag)
return d_inv @ cov @ d_inv