Aluode/PerceptionLabPortable
0
1# Authors: The MNE-Python contributors.2# License: BSD-3-Clause3# Copyright the MNE-Python contributors.4 5import collections.abc as abc6from functools import partial7 8import numpy as np9 10from .._fiff.meas_info import Info11from ..cov import Covariance12from ..decoding._covs_ged import _xdawn_estimate13from ..decoding._mod_ged import _xdawn_mod14from ..decoding.base import _GEDTransformer15from ..utils import _validate_type, fill_doc16 17 18@fill_doc19class XdawnTransformer(_GEDTransformer):20 """Implementation of the Xdawn Algorithm compatible with scikit-learn.21 22 Xdawn is a spatial filtering method designed to improve the signal23 to signal + noise ratio (SSNR) of the event related responses. Xdawn was24 originally designed for P300 evoked potential by enhancing the target25 response with respect to the non-target response. This implementation is a26 generalization to any type of event related response.27 28 .. note:: XdawnTransformer does not correct for epochs overlap. To correct29 overlaps see `mne.preprocessing.Xdawn`.30 31 Parameters32 ----------33 n_components : int (default 2)34 The number of components to decompose the signals.35 reg : float | str | None (default None)36 If not None (same as ``'empirical'``, default), allow37 regularization for covariance estimation.38 If float, shrinkage is used (0 <= shrinkage <= 1).39 For str options, ``reg`` will be passed to ``method`` to40 :func:`mne.compute_covariance`.41 signal_cov : None | Covariance | array, shape (n_channels, n_channels)42 The signal covariance used for whitening of the data.43 if None, the covariance is estimated from the epochs signal.44 cov_method_params : dict | None45 Parameters to pass to :func:`mne.compute_covariance`.46 47 .. versionadded:: 0.1648 restr_type : "restricting" | "whitening" | None49 Restricting transformation for covariance matrices before performing50 generalized eigendecomposition.51 If "restricting" only restriction to the principal subspace of signal_cov52 will be performed.53 If "whitening", covariance matrices will be additionally rescaled according54 to the whitening for the signal_cov.55 If None, no restriction will be applied. Defaults to None.56 57 .. versionadded:: 1.1158 info : mne.Info | None59 The mne.Info object with information about the sensors and methods of60 measurement used for covariance estimation and generalized61 eigendecomposition.62 If None, one channel type and no projections will be assumed and if63 rank is dict, it will be sum of ranks per channel type.64 Defaults to None.65 66 .. versionadded:: 1.1167 %(rank_full)s68 69 .. versionadded:: 1.1170 71 Attributes72 ----------73 classes_ : array, shape (n_classes)74 The event indices of the classes.75 filters_ : array, shape (n_channels, n_channels)76 The Xdawn components used to decompose the data for each event type.77 patterns_ : array, shape (n_channels, n_channels)78 The Xdawn patterns used to restore the signals for each event type.79 80 See Also81 --------82 CSP, SPoC, SSD83 """84 85 def __init__(86 self,87 n_components=2,88 reg=None,89 signal_cov=None,90 cov_method_params=None,91 *,92 restr_type=None,93 info=None,94 rank="full",95 ):96 self.n_components = n_components97 self.signal_cov = signal_cov98 self.reg = reg99 self.cov_method_params = cov_method_params100 self.restr_type = restr_type101 self.info = info102 self.rank = rank103 104 cov_callable = partial(105 _xdawn_estimate,106 reg=reg,107 cov_method_params=cov_method_params,108 R=signal_cov,109 info=info,110 rank=rank,111 )112 super().__init__(113 n_components=n_components,114 cov_callable=cov_callable,115 mod_ged_callable=_xdawn_mod,116 dec_type="multi",117 restr_type=restr_type,118 )119 120 def __sklearn_tags__(self):121 """Tag the transformer."""122 tags = super().__sklearn_tags__()123 tags.target_tags.required = True124 return tags125 126 def _validate_params(self, X):127 _validate_type(self.n_components, int, "n_components")128 129 # reg is validated in _regularized_covariance130 131 if self.signal_cov is not None:132 if isinstance(self.signal_cov, Covariance):133 self.signal_cov = self.signal_cov.data134 elif not isinstance(self.signal_cov, np.ndarray):135 raise ValueError("signal_cov should be mne.Covariance or np.ndarray")136 if not np.array_equal(self.signal_cov.shape, np.tile(X.shape[1], 2)):137 raise ValueError(138 "signal_cov data should be of shape (n_channels, n_channels)"139 )140 _validate_type(self.cov_method_params, (abc.Mapping, None), "cov_method_params")141 _validate_type(self.info, (Info, None), "info")142 143 def fit(self, X, y=None):144 """Fit Xdawn spatial filters.145 146 Parameters147 ----------148 X : array, shape (n_epochs, n_channels, n_samples)149 The target data.150 y : array, shape (n_epochs,) | None151 The target labels. If None, Xdawn fit on the average evoked.152 153 Returns154 -------155 self : Xdawn instance156 The Xdawn instance.157 """158 X, y = self._check_data(X, y=y, fit=True, return_y=True)159 # For test purposes160 if y is None:161 y = np.ones(len(X))162 self._validate_params(X)163 164 super().fit(X, y)165 166 return self167 168 def transform(self, X):169 """Transform data with spatial filters.170 171 Parameters172 ----------173 X : array, shape (n_epochs, n_channels, n_samples)174 The target data.175 176 Returns177 -------178 X : array, shape (n_epochs, n_components * n_classes, n_samples)179 The transformed data.180 """181 X = self._check_data(X)182 X = super().transform(X)183 return X184 185 def inverse_transform(self, X):186 """Remove selected components from the signal.187 188 Given the unmixing matrix, transform data, zero out components,189 and inverse transform the data. This procedure will reconstruct190 the signals from which the dynamics described by the excluded191 components is subtracted.192 193 Parameters194 ----------195 X : array, shape (n_epochs, n_components * n_classes, n_times)196 The transformed data.197 198 Returns199 -------200 X : array, shape (n_epochs, n_channels * n_classes, n_times)201 The inverse transform data.202 """203 # Check size204 X = self._check_data(X, check_n_features=False)205 n_epochs, n_comp, n_times = X.shape206 if n_comp != (self.n_components * len(self.classes_)):207 raise ValueError(208 f"X must have {self.n_components * len(self.classes_)} components, "209 f"got {n_comp} instead."210 )211 pick_patterns = self._subset_multi_components(name="patterns")212 # Transform213 return np.dot(pick_patterns.T, X).transpose(1, 0, 2)214 