conninfpy.glm_stats

GLM-based statistical testing for brain connectivity networks.

Implements edge-wise General Linear Model with Freedman-Lane permutation for confound-aware inference on connectivity matrices. Supports all enhancement methods (TFNBS, NBS, cNBS, NI-TFNBS, FBC-TFNBS).

Main Functions

compute_glm_stat : Compute GLM t-statistics for connectivity data compute_p_val_glm : Full GLM pipeline with permutation testing build_design_matrix : Convenience builder for design matrix + contrast

References

Freedman & Lane (1983). A nonstochastic interpretation of reported significance levels. Anderson & Legendre (1999). An empirical comparison of permutation methods. Winkler et al. (2014). Permutation inference for the general linear model.

class conninfpy.glm_stats.GLMStatType(value)[source]

Bases: str, Enum

Statistic type for GLM inference.

TSTAT = 'tstat'

beta / SE(beta). Scale-invariant, start_thres=1.65 valid.

Type:

t-statistic

BETA = 'beta'

Raw regression coefficient. Interpretable, needs adapted threshold.

FSTAT = 'fstat'

F-statistic for an omnibus (multi-row) contrast.

Non-negative by construction — the enhancement pipeline sees a single 'omnibus' key instead of a positive/negative split. For a single-row contrast, F == t² (same rejection regions, same rankings).

conninfpy.glm_stats.compute_glm_stat(Y: ndarray[tuple[Any, ...], dtype[float64]], X: ndarray[tuple[Any, ...], dtype[float64]], contrast: ndarray[tuple[Any, ...], dtype[float64]], stat_type: str | GLMStatType = GLMStatType.TSTAT, X_pinv: ndarray[tuple[Any, ...], dtype[float64]] | None = None, XtX_inv_diag: ndarray[tuple[Any, ...], dtype[float64]] | None = None, XtX_inv: ndarray[tuple[Any, ...], dtype[float64]] | None = None) Dict[str, ndarray[tuple[Any, ...], dtype[float64]]][source]

Compute edge-wise GLM statistics for connectivity matrices.

For each edge (i,j): Y_ij = X @ beta_ij + epsilon_ij.

  • tstat/beta: single-column contrast, returns {positive, negative}.

  • fstat: multi-row contrast (omnibus F), returns {omnibus} — F is non-negative by construction, so there is no direction to split.

Parameters:
  • Y (ndarray of shape (n_subjects, N, N)) – Connectivity matrices (symmetric, zero diagonal).

  • X (ndarray of shape (n_subjects, p)) – Design matrix (should include intercept column if needed).

  • contrast (ndarray of shape (p,) or (r, p)) – Contrast vector (for tstat/beta: 1D) or contrast matrix (for fstat: 2D with r rows). A 1D contrast passed with stat_type ='fstat' is treated as a 1×p matrix (F == t² at each edge).

  • stat_type ({'tstat', 'beta', 'fstat'} or GLMStatType, default='tstat') – Type of statistic to compute.

  • X_pinv (ndarray of shape (p, n_subjects), optional) – Precomputed Moore-Penrose pseudoinverse. If None, computed internally by _precompute_ols().

  • XtX_inv_diag (ndarray of shape (p,), optional) – Precomputed diagonal of the generalized inverse of X'X. Required when stat_type='tstat' and X_pinv is provided.

  • XtX_inv (ndarray of shape (p, p), optional) – Generalized inverse of X'X. Required for contrast standard errors when X_pinv is provided.

Returns:

For tstat/beta: {'positive': (N, N), 'negative': (N, N)}, both non-negative. For fstat: {'omnibus': (N, N)}, non-negative.

Return type:

dict

conninfpy.glm_stats.compute_p_val_glm(Y: ndarray[tuple[Any, ...], dtype[float64]], design_matrix: ndarray[tuple[Any, ...], dtype[float64]] | None = None, contrast: ndarray[tuple[Any, ...], dtype[float64]] | None = None, interest: ndarray[tuple[Any, ...], dtype[float64]] | None = None, confounds: ndarray[tuple[Any, ...], dtype[float64]] | None = None, stat_type: str | GLMStatType = GLMStatType.TSTAT, method: str | StatMethod = StatMethod.TFNBS, n_permutations: int = 1000, two_tailed: bool = False, acceleration: str | None = None, use_mp: bool = True, rng: None | int | Generator | RandomState = None, random_state: int | None = None, n_processes: int | None = None, verbose: bool = False, net_labels: ndarray[tuple[Any, ...], dtype[int64]] | None = None, threshold: float = 2.0, nbs_stat: str = 'extent', e: float | List[float] = 0.3, h: float | List[float] = 3.0, n: int = 10, start_thres: float = 1.65, min_cluster_size: int = 3, normalization: str = 'sqrt', strata: ndarray[tuple[Any, ...], dtype[Any]] | None = None) InferenceResult | OmnibusInferenceResult[source]

Compute p-values for connectivity data using GLM with Freedman-Lane permutation.

Supports two APIs that share the same core engine:

  • Advanced API: provide design_matrix and contrast directly.

  • Convenience API: provide interest (and optional confounds); the design matrix and contrast are built automatically.

Parameters:
  • Y (ndarray of shape (n_subjects, N, N)) – Connectivity matrices (symmetric, zero diagonal).

  • design_matrix (ndarray of shape (n_subjects, p), optional) – Full design matrix (advanced API). Mutually exclusive with interest.

  • contrast (ndarray of shape (p,) or (r, p), optional) – Contrast vector (1D, t/beta) or contrast matrix (2D, F-stat). Required with design_matrix. For stat_type='fstat', pass a 2D matrix whose rows encode the linear combinations being tested jointly (e.g., [[1, -1, 0], [1, 0, -1]] tests β₁=β₂=β₃).

  • interest (ndarray of shape (n_subjects,), optional) – Variable of interest (convenience API). Mutually exclusive with design_matrix. Produces a single-column contrast — use the advanced API for multi-row F-contrasts.

  • confounds (ndarray of shape (n_subjects,) or (n_subjects, q), optional) – Confound variables (convenience API).

  • stat_type ({'tstat', 'beta', 'fstat'} or GLMStatType, default='tstat') – Type of statistic to compute. 'fstat' enables an omnibus F-test for a multi-row contrast matrix and returns a single 'omnibus' p-value map (no positive/negative split).

  • method (str or StatMethod, default='tfnbs') – Enhancement method.

  • n_permutations (int, default=1000) – Number of permutations for null distribution.

  • two_tailed (bool, default=False) – If False (default), per-tail FWER control (separate null for positive and negative). If True, joint null from max(max_positive, max_negative).

  • acceleration ({'gpd', 'gamma'} or None, default=None) – Permutation acceleration method (Winkler et al., 2016). If None, use standard empirical p-values. ‘gpd’ fits a Generalized Pareto Distribution to the tail of the null distribution. ‘gamma’ fits a gamma distribution using method of moments. Both are approximation accelerators with empirical fallback; use acceleration=None for exact empirical finite-permutation p-values.

  • use_mp (bool, default=True) – Use multiprocessing for permutation testing.

  • random_state (int, optional) – Random seed for reproducibility.

  • n_processes (int, optional) – Number of CPU cores for parallel computing.

  • net_labels (ndarray of shape (N,), optional) – Network labels (required for cnbs, ni_tfnbs, fbc_tfnbs).

  • threshold – Method-specific parameters (see compute_p_val docstring).

  • nbs_stat – Method-specific parameters (see compute_p_val docstring).

  • n – Method-specific parameters (see compute_p_val docstring).

  • start_thres – Method-specific parameters (see compute_p_val docstring).

  • min_cluster_size – Method-specific parameters (see compute_p_val docstring).

  • normalization – Method-specific parameters (see compute_p_val docstring).

  • e (float or sequence of float) – TFNBS extent and height exponents. Pass equal-length sequences to evaluate a whole (E, H) grid in one permutation pass. In grid mode the returned InferenceResult carries the parameter axis (result.is_grid, result.e_grid, result.h_grid); use result.select(param_idx) or pass param_idx= to significant_edges / to_csv to project to a single cell.

  • h (float or sequence of float) – TFNBS extent and height exponents. Pass equal-length sequences to evaluate a whole (E, H) grid in one permutation pass. In grid mode the returned InferenceResult carries the parameter axis (result.is_grid, result.e_grid, result.h_grid); use result.select(param_idx) or pass param_idx= to significant_edges / to_csv to project to a single cell.

Returns:

For stat_type in {'tstat', 'beta'}: an InferenceResult with positive and negative p-value maps of shape (N, N) or (N, N, K) in grid mode. For stat_type='fstat': an OmnibusInferenceResult with a single omnibus map of shape (N, N).

Return type:

InferenceResult or OmnibusInferenceResult

Raises:

ValueError – If API arguments are inconsistent or contrast is invalid.

conninfpy.glm_stats.compute_p_val_paired_glm(Y_A: ndarray[tuple[Any, ...], dtype[float64]], Y_B: ndarray[tuple[Any, ...], dtype[float64]], confounds_A: ndarray[tuple[Any, ...], dtype[float64]] | None = None, confounds_B: ndarray[tuple[Any, ...], dtype[float64]] | None = None, **kwargs) InferenceResult | Dict[str, ndarray[tuple[Any, ...], dtype[float64]]][source]

Paired-difference GLM: test Y_A vs Y_B within-subject, optionally controlling for per-subject differences in confounds.

Two routes depending on confounds_*:

  • No confounds → delegates to conninfpy.compute_p_val() with test_type='paired' (sign-flip permutation). This is numerically equivalent to a one-sample GLM on the differences and avoids the Freedman-Lane degeneracy that occurs when the contrast targets the only column in the design matrix.

  • With confounds → builds Δ_Y = Y_A Y_B and Δ_C = confounds_A confounds_B, then calls compute_p_val_glm() with design_matrix = [1, Δ_C], contrast = [1, 0, ..., 0] (intercept as the effect of interest).

Use this when the same subjects are measured under two conditions (task A vs task B, pre vs post, open vs close) and a confound whose value differs between the two conditions for the same subject (e.g., motion, arousal, response time) needs to be partialled out.

Parameters:
  • Y_A (ndarray of shape (n_subjects, N, N)) – Aligned per-subject connectivity matrices for the two conditions. Y_A[s] and Y_B[s] must correspond to the same subject.

  • Y_B (ndarray of shape (n_subjects, N, N)) – Aligned per-subject connectivity matrices for the two conditions. Y_A[s] and Y_B[s] must correspond to the same subject.

  • confounds_A (ndarray of shape (n_subjects,) or (n_subjects, k), optional) – Aligned per-subject confound values for the two conditions. Either pass both or neither. If passed, the difference confounds_A - confounds_B enters the GLM as a nuisance regressor.

  • confounds_B (ndarray of shape (n_subjects,) or (n_subjects, k), optional) – Aligned per-subject confound values for the two conditions. Either pass both or neither. If passed, the difference confounds_A - confounds_B enters the GLM as a nuisance regressor.

  • **kwargs – Forwarded to the downstream call (compute_p_val or compute_p_val_glm). test_type is fixed to 'paired' when routing to the t-test pipeline and must not be supplied.

Returns:

{'positive', 'negative'} regardless of routing. For the no-confound path, positive corresponds to Y_B > Y_A (B has greater connectivity); for the with-confound path it corresponds to the sign of the Y_A - Y_B intercept adjusted for Δ_C. Legacy keys 'g2>g1' / 'g1>g2' remain accessible with a DeprecationWarning until v2.1.

Return type:

dict

Raises:

ValueError – If Y_A and Y_B shapes mismatch, only one of the confound arrays is supplied, or confound shapes mismatch.

conninfpy.glm_stats.build_design_matrix(interest: ndarray[tuple[Any, ...], dtype[float64]], confounds: ndarray[tuple[Any, ...], dtype[float64]] | None = None) Tuple[ndarray[tuple[Any, ...], dtype[float64]], ndarray[tuple[Any, ...], dtype[float64]]][source]

Build design matrix and contrast vector from interest and confound variables.

Constructs X = [intercept, confounds, interest] and contrast = [0, …, 0, 1] targeting the last column (interest variable).

Parameters:
  • interest (ndarray of shape (n_subjects,)) – Variable of interest (continuous or binary).

  • confounds (ndarray of shape (n_subjects,) or (n_subjects, q), optional) – Confound variables. If 1D, treated as single confound.

Returns:

  • X (ndarray of shape (n_subjects, p)) – Design matrix with intercept, confounds, and interest.

  • contrast (ndarray of shape (p,)) – Contrast vector [0, …, 0, 1] targeting the interest column.