Edge Selection
Edge selection: which edges enter the model.
The statistics themselves live in statistics.py. This module is the policy
layer on top of them -- the significance thresholding (PThreshold), the two
structural filters (presence, connected components), and the
UnivariateEdgeSelection facade that expands a user's configuration into the
parameter grid the inner CV iterates over.
EdgeStatistic
Bases: BaseEstimator
The per-edge statistic used to rank and threshold edges.
Two independent choices:
selection_statistic
'pearson' or 'spearman'. A binary 0/1 target through the Pearson
path is the point-biserial correlation, so it needs no separate value.
selection_input
'raw' ignores the covariates. 'residualized' controls for them:
one regression per edge, y ~ 1 + Z + edge, reporting the semipartial
correlation as the effect size and the coefficient's p-value with
df = N - 2 - C.
On 'residualized': the effect size is reported as the semipartial
correlation -- the edge's unique contribution as a share of the total
variance of y -- because that denominator stays comparable across analyses.
The partial correlation is the same effect on a denominator that shrinks
with how confounded y is. They are monotone transforms of each other within
a fold (verified: rank correlation exactly 1.0), so the choice affects what
is printed, never which edges are selected. Both come from one regression,
which is where the p-value comes from too.
For Spearman the ranking happens first, including on the confounds, and the residualisation follows -- the conventional "rank, then partial" definition. The reverse order does not work: ranking is nonlinear, so ranking a residualised edge puts the confound signal back in (measured: 11.9 versus 6.5e-13 of residual confound signal).
PThreshold
Bases: BaseEdgeSelector
Select edges whose correlation with the target is significant at a p-value threshold, optionally after multiple-comparison correction.
Pass a list of thresholds (and/or corrections) to search over them with an inner cross-validation loop.
__init__(threshold=0.05, correction=None)
:param threshold: p-value threshold(s); edges with p below the threshold
are selected. A single value (e.g. 0.05) or a list
(e.g. [0.01, 0.05]) to tune via inner CV.
:param correction: multiple-comparison correction, or None for no
correction. Can be one of statsmodels' methods:
bonferroni : one-step correction
sidak : one-step correction
holm-sidak : step down method using Sidak adjustments
holm : step-down method using Bonferroni adjustments
simes-hochberg : step-up method (independent)
hommel : closed method based on Simes tests (non-negative)
fdr_bh : Benjamini/Hochberg (non-negative)
fdr_by : Benjamini/Yekutieli (negative)
fdr_tsbh : two stage fdr correction (non-negative)
fdr_tsbky : two stage fdr correction (non-negative)
select(r, t, df, thresholds=None)
Select edges whose (optionally corrected) p-value falls below each threshold, split into positive- and negative-correlation networks.
Selection is exact without computing a p-value per edge: for fixed df the
two-sided p-value is strictly decreasing in |t|, so p < alpha is
|t| > critical_t(alpha, df) -- one scalar scipy call per threshold,
with the comparison on the device. Step-wise corrections (Holm, FDR, ...)
need the p-values themselves and compute them exactly on the CPU.
The correction is applied per run: each column of t is one
analysis (the real target, or one permutation) with N_features tests
of its own. A permuted run must be thresholded exactly like the real one,
or the null distribution is not a null of the same procedure.
Args:
r: [N_features, rest] effect sizes; their sign picks the network.
t: [N_features, rest] t statistics, rest being any batch axes
already present (in practice the runs/permutations axis).
df: degrees of freedom of t.
thresholds: sequence of p-value thresholds. Defaults to
self.threshold, which is always a list.
Returns: Boolean tensor [N_features, 2, N_params, *rest], where dim 1 is [positive, negative] and N_params == len(thresholds).
UnivariateEdgeSelection
Bases: BaseEstimator
Univariate edge selection for CPM.
Correlates each edge with the target using the chosen statistic and selects edges with one or more selection strategies (e.g. a p-value threshold). When several configurations are supplied, they form a hyperparameter grid that the inner cross-validation loop searches over.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
selection_statistic
|
str
|
Correlation used to relate each edge to the target: |
'spearman'
|
selection_input
|
str
|
Whether edge selection controls for the covariates. |
'raw'
|
presence_filter
|
Union[bool, float]
|
Optional pre-filter that keeps only edges which are nonzero in at least a
given fraction of subjects, dropping structural/near-zero edges before
selection. |
False
|
connected_components
|
Union[bool, int]
|
If set, keep only selected edges that belong to a connected component
with at least this many edges (per positive/negative network), dropping
isolated edges — this can improve edge stability. |
False
|
edge_selection
|
Union[list, None, PThreshold]
|
One or more selection strategies. Provide a list of multiple configurations to tune them via an inner CV. |
None
|
return_selected_edges(thresholds=None)
Edge masks [Features, 2, N_params, *runs] for the fitted statistics.
filter_connected_components(mask, min_edges)
Keep only selected edges that belong to a connected component with at least
min_edges edges; drop the rest.
A graph is built independently for each (network, *batch) slice from that
slice's selected edges, treating edges sharing a node as connected. Isolated
single edges form a one-edge component and are removed when
min_edges >= 2.
mask is [Features, 2, *batch] (dim 1 = positive/negative; batch is
typically params x runs). The returned tensor has the same shape and dtype,
with dropped edges set to 0.
This is CPU/networkx work and is not vectorised -- it runs once per (network, *batch) slice.
resolve_min_component_size(connected_components)
Resolve the connected_components argument to a minimum component size
(in edges), or None when the filter is off (True -> 2, i.e. drop
lone single edges).
resolve_presence_threshold(presence_filter)
Resolve the presence_filter argument to a nonzero-fraction threshold.
Returns None when the filter is off, otherwise the fraction of subjects
that must have a nonzero value for an edge to be kept (True -> 0.5).
resolve_selection_spec(selection_statistic, selection_input)
Validate the edge-selection specification.
Returns (selection_statistic, selection_input).