confusius.decoding¶
decoding ¶
Pattern decoding for fUSI DataArrays.
This package provides decoders in the spirit of
nilearn.decoding:
SearchLight: per-voxel local decoding, also known as "spotlight" decoding.
Portions of this package are inspired by nilearn.decoding, which is licensed under
the BSD-3-Clause License. See NOTICE for details.
Modules:
-
searchlight–Searchlight decoding for
(time, ...)fUSI DataArrays.
Classes:
-
SearchLight–Searchlight decoder for fUSI data.
SearchLight ¶
Bases: BaseEstimator
Searchlight decoder for fUSI data.
For every voxel of process_mask, fit gathers the mask voxels lying within
radius, cross-validates estimator on that neighborhood, and stores the mean
score.
This estimator wraps scikit-learn while keeping xarray metadata:
- Input data are expected as
(time, ...)where...are spatial dimensions. - The
timedimension is the sample axis. It need not be temporally ordered. For trial-averaged data, rename the trial dimension with.rename(trial="time"). scores_is returned in the spatial geometry ofprocess_mask.
Parameters:
-
(estimator¶BaseEstimator) –Estimator or
Pipeline. -
(mask¶DataArray, default:None) –Boolean spatial mask selecting the voxels that may act as features. If not provided, every voxel of the input data is used as a feature voxel. Every spatial dimension must carry a numeric coordinate, because
radiusis measured in coordinate units. -
(radius¶float, default:1.0) –Neighborhood radius, in the units of the data's spatial coordinates. Check
X[dim].attrs.get("units")if unsure. Radii are measured in physical coordinates rather than voxel indices, so anisotropic voxels behave correctly. -
(process_mask¶DataArray, default:None) –Boolean mask selecting the voxels that act as neighborhood centers. Must be a subset of
mask. If not provided, a score is computed at everymaskvoxel. Use it to restrict the searchlight to a region of interest while still drawing features from the surrounding tissue. -
(cv¶int or BaseCrossValidator, default:5) –Cross-validation strategy. An integer builds a
KFoldfor regressors, whose folds are contiguous blocks of time, or aStratifiedKFoldfor classifiers, which keeps folds class-balanced but interleaves time. Both useshuffle=False. Any scikit-learn splitter is accepted. -
(scoring¶str or callable, default:None) –Scorer passed to
cross_val_score. If not provided, the estimator's ownscoreis used, which is accuracy for classifiers and the coefficient of determination for regressors. -
(n_jobs¶int, default:1) –Number of joblib workers. Centers are dispatched in batches, not one task each.
-
(show_progress¶bool, default:True) –Whether to display a progress bar during fit.
Attributes:
-
scores_((...) xarray.DataArray) –Mean cross-validation score at each
process_maskcenter, in the spatial geometry ofprocess_mask. Voxels outsideprocess_maskarenumpy.nan. The input's attributes are carried over, including anyaffines, so the map stays in the same physical space.long_nameis set to"Searchlight CV score"andunitsto the metric implied byscoring: the scorer string when one is given, otherwise"accuracy"for a classifier or"R²"for a regressor. A callable scorer leavesunitsunset.
Warns:
-
UserWarning–If
radiusis small enough that the median neighborhood holds a single voxel. The run still produces a valid map, but it has silently become a univariate analysis rather than a multivariate one. Also ifprocess_maskselects no voxels at all, which yields an entirely NaN map.
Notes
Consecutive fUSI volumes are strongly autocorrelated. Passing a splitter with
shuffle=True places near-duplicate neighboring volumes in both the training and
test sets, which inflates scores. This is why an integer cv builds KFold folds
with shuffle=False for regressors. Classifiers instead get StratifiedKFold, which
balances classes across folds but interleaves time rather than keeping contiguous
blocks, so on its own it does not prevent this leakage. For data with a run or block
structure, or to keep classification folds contiguous, prefer
LeaveOneGroupOut with groups.
References
-
Kriegeskorte, N., Goebel, R., and Bandettini, P. (2006). "Information-based functional brain mapping". PNAS, 103(10), 3863-3868. ↩
Examples:
>>> import numpy as np
>>> import xarray as xr
>>> from sklearn.linear_model import Ridge
>>> from confusius.decoding import SearchLight
>>>
>>> rng = np.random.default_rng(0)
>>> data = xr.DataArray(
... rng.standard_normal((40, 1, 5, 5)),
... dims=["time", "z", "y", "x"],
... coords={
... "time": np.arange(40) * 0.5,
... "z": [0.0],
... "y": np.arange(5) * 0.2,
... "x": np.arange(5) * 0.2,
... },
... )
>>> speed = rng.standard_normal(40)
>>>
>>> searchlight = SearchLight(
... estimator=Ridge(), radius=0.25, cv=3, show_progress=False
... )
>>> searchlight.fit(data, speed).scores_.dims
('z', 'y', 'x')
Methods:
-
fit–Run searchlight decoding.
-
get_metadata_routing–Get metadata routing of this object.
-
get_params–Get parameters for this estimator.
-
score–Refuse to produce a single score.
-
set_params–Set the parameters of this estimator.
fit ¶
Run searchlight decoding.
Parameters:
-
(X¶(time, ...) xarray.DataArray) –Functional ultrasound data. The
timedimension is the sample axis. -
(y¶(n_samples,) array-like or xarray.DataArray) –Targets aligned with
X'stimeaxis. -
(groups¶(n_samples,) array-like, default:None) –Group labels forwarded to the cross-validator. Required by
LeaveOneGroupOut.
Returns:
-
SearchLight–The fitted estimator.
Raises:
-
ValueError–If
Xis h5py-backed, ifradiusis negative, ifprocess_maskis not a subset ofmask, ifyorgroupsdo not align withX, if a spatial dimension lacks a numeric coordinate, or if the masked data contains non-finite values.
Warns:
-
UserWarning–If the median neighborhood holds a single voxel, either because
radiusis below the voxel spacing or becausemaskis very sparse. The run still produces a valid map, but it has silently become a univariate analysis rather than a multivariate one. Also ifprocess_maskselects no voxels at all, which yields an entirely NaN map.
get_metadata_routing ¶
Get metadata routing of this object.
Please check :ref:User Guide <metadata_routing> on how the routing
mechanism works.
Returns:
-
routing(MetadataRequest) –A :class:
~sklearn.utils.metadata_routing.MetadataRequestencapsulating routing information.
score ¶
Refuse to produce a single score.
Parameters:
-
(X¶DataArray) –Ignored. SearchLight does not refit a single model.
-
(y¶array - like) –Ignored. SearchLight does not refit a single model.
Returns:
-
float–Never returns.
Raises:
-
NotImplementedError–Always. A searchlight produces one score per voxel, not one per model, so there is no single number to report. Read
scores_instead.
set_params ¶
set_params(**params)
Set the parameters of this estimator.
The method works on simple estimators as well as on nested objects
(such as :class:~sklearn.pipeline.Pipeline). The latter have
parameters of the form <component>__<parameter> so that it's
possible to update each component of a nested object.
Parameters:
Returns:
-
self(estimator instance) –Estimator instance.