mne_connectivity.learn_graph#
- mne_connectivity.learn_graph(data, *, names=None, indices='lower', alpha=0.5, beta=0.5, metric='sqeuclidean', normalize=True, max_iter=1000, tol=0.0001, step_size=None, n_jobs=1, verbose=None)[source]#
Learn a sparse graph from smooth signals.
Estimates a symmetric, non-negative, zero-diagonal weighted adjacency matrix directly from signal smoothness, rather than from pairwise similarity/coherence computed independently per edge. All edge weights are learned jointly by solving
\[\min_{w \geq 0} \; 2 w^\top z - \alpha \mathbf{1}^\top \log(Sw) + \beta \|w\|^2\]where \(z\) is the vector of pairwise distances between nodes (rows of
data) and \(S\) maps an edge-weight vector to the corresponding vector of node degrees. This is the model proposed in [1], and is the same model used on real MEG data (with \(\alpha\), \(\beta\) named \(\sigma\), \(\rho\)) in [2], where it was found to be more robust than Phase Lag Index for short recordings and to better capture individual-specific connectivity. The defaultalpha=0.5, beta=0.5is one of the parameter combinations swept in the robustness analysis of [2]. See Notes for details.- Parameters:
- dataarray_like, shape ([n_epochs,] n_nodes, n_times) |
Epochs| generator The data from which to learn a graph. Can be a single 2D array of shape
(n_nodes, n_times), a 3D array of shape(n_epochs, n_nodes, n_times), amne.Epochsobject, or a list/generator of 2D arrays ormne.SourceEstimate/mne.VolSourceEstimateobjects. Formne.Epochs, channels marked as bad are not used to learn the graph; they are kept as nodes, with their connections set toNaN.- namesarray_like |
None The names of the nodes of the dataset used to compute connectivity. If
None(default), then names will be a list of integers from 0 ton_nodes. If a list of names, then it must be equal in length ton_nodes. Ignored (and overridden bydata.ch_names) ifdatais anmne.Epochsobject.- indices
'lower'|'upper'|'all' Which part of the symmetric graph to store. If
'lower'or'upper', only the lower- or upper-triangular part is stored, and the rest is filled in when requestingget_data(output='dense'). If'all', the full matrix (including the zero diagonal) is stored. The graph itself is always learned over all pairs of nodes. Default is'lower'.- alpha
float Controls how strongly node degrees are pulled away from zero via the log-barrier term. Must be strictly positive. Larger values yield more connected (higher-degree) graphs; every node is guaranteed at least one edge for any
alpha > 0. Default0.5.- beta
float Controls the \(\|w\|^2\) penalty on edge weights. Must be non-negative. Larger values yield denser graphs.
beta=0yields the sparsest graph consistent with keeping every node connected, but lacks a strongly-convex term and so converges markedly more slowly (seemax_iter); the defaultbeta=0.5gives fast, reliable convergence while still yielding a moderately sparse graph. See Notes.- metric
str|callable() Distance metric passed to
scipy.spatial.distance.pdist()to build the pairwise dissimilarity vector between nodes. Must yield only non-negative values. Default'sqeuclidean'(squared Euclidean distance), matching [1] and [2].- normalizebool
If
True(default), rescale the pairwise-distance vector by its mean before solving, so that the defaultalpha/betabehave consistently regardless of the input’s physical units or amplitude scale. See Notes.- max_iter
int Maximum number of primal-dual iterations. Default
1000. Sparser settings (smallbeta, in particularbeta=0) may require more iterations to converge. See Notes.- tol
float Relative convergence tolerance on both the edge-weight and node-degree updates. Default
1e-4.- step_size
float|None Override the closed-form step size
1 / (1 + 2 * beta + sqrt(2 * (n_nodes - 1))). Must be strictly positive. Useful for matching the step size used by another implementation (e.g. for validation) or for trading off convergence speed against stability. DefaultNone.- n_jobs
int The number of jobs to run in parallel (default 1). Requires the joblib package. Each epoch’s graph is learned independently, so this parallelizes across epochs; for small numbers of nodes/iterations the joblib dispatch overhead may outweigh the benefit.
- verbosebool |
str|int|None If not
None, override default verbose level (seemne.verbose()for more info). If used, it should be passed as a keyword-argument only.
- dataarray_like, shape ([n_epochs,] n_nodes, n_times) |
- Returns:
- graphinstance of
ConnectivityorEpochConnectivity The learned graph(s): a symmetric, zero-diagonal, non-negative weighted adjacency, stored as the raveled values of the part of the matrix selected by
indices. A singleConnectivityis returned ifdatawas a bare 2D array; otherwise anEpochConnectivityis returned with one graph per epoch.
- graphinstance of
Notes
This implements the model of eq. 12 in [1] (their \(\alpha\), \(\beta\)), identical to the model used in [2] (that paper’s \(\sigma\), \(\rho\)). The log-barrier term on node degrees (rather than on individual edge weights) is what distinguishes this model from a plain Gaussian-kernel graph construction: it guarantees every node has at least one edge, without preventing individual edges from being exactly zero, so sparse and fully connected graphs can be learned simultaneously.
Because \(z\) (the pairwise-distance vector) scales with the physical units/amplitude of
data, andalpha/betainteract multiplicatively with that scale,normalize=Truedivides \(z\) by its mean before solving so that the defaultalpha=0.5, beta=0.5are reasonable starting points regardless of the input’s scale. Usenormalize=Falsefor a literal, unscaled port of the optimization problem as stated above.When
beta=0, the learned graph is the sparsest one consistent with keeping every node connected, and changingalphaalone only rescales the overall magnitude of the learned weights, not the sparsity pattern (see Proposition 2 of [1]). However,beta=0removes the only strongly-convex term in the objective, so this primal-dual solver converges much more slowly in that regime (often thousands of iterations) and the relative-change stopping criterion (tol) is a weaker guarantee of closeness to the true optimum than it is forbeta > 0. For most uses, prefer sweepingbetaaway from0(as the default does) for both faster and more reliable convergence.The optimization is solved per epoch using a forward-backward-forward primal-dual splitting with per-iteration complexity
O(n_nodes**2).References