profile
viewpoint
Denis A. Engemann dengemann INRIA Paris, France http://denis-engemann.de I'm a psychologist and PhD who works at the intersection of Psychology, Neuroscience, Statistics & Computer Science. Sometimes more in one than the other camp.

autoreject/autoreject 82

Automated rejection and repair of bad trials/sensors in M/EEG

agramfort/mne_pratical_meeg 8

Materials for MNE tutorials at Practical MEEG workshop Paris 2019

dengemann/meeg-preprocessing 6

Preprocessing tools for MEG/EEG

agramfort/mne-python 4

MNE scripting with Python

agramfort/mne-python-notebooks 1

IPython notebooks for EEG/MEG data processing using mne-python

dengemann/ggplot 1

ggplot for python

deep-introspection/Udgan 0

MNE-Python Analysis Pipeline for Uncommon EEG Recordings

Pull request review commentdengemann/mne-python

added option to handle epoched data

 import mne from mne import Epochs from mne.datasets.fieldtrip_cmc import data_path-from mne.utils import _time_mask from mne.channels import read_layout from mne.decoding import TransformerMixin, BaseEstimator +from mne.io.base import BaseRaw+from mne.epochs import BaseEpochs+from mne.utils import _time_mask+from mne.cov import (_regularized_covariance, compute_raw_covariance)+from mne.filter import filter_data+from mne.time_frequency import psd_array_welch+import locale+locale.setlocale(locale.LC_ALL, "en_US.UTF-8")+  def freq_mask(freqs, fmin, fmax):     """convenience function to select frequencies"""     return _time_mask(freqs, fmin, fmax) + # Define parameters fname = data_path() + '/SubjectCMC.ds' raw = mne.io.read_raw_ctf(fname) raw.crop(50., 250.).load_data()  # crop for memory purposes+picks = mne.pick_types(raw.info, meg=True, eeg=False, ref_meg=False)+sf = raw.info['sfreq']  freqs_sig = 9, 12 freqs_noise = 8, 13   class SSD(BaseEstimator, TransformerMixin):-    """Implement Spatio-Spectral Decomposision+    """+    This is a Python Implementation of Spatio Spectral Decomposition (SSD)+    method [1],[2] for both raw and epoched data. This source code is  based on+    the matlab implementation available at+    https://github.com/svendaehne/matlab_SPoC/tree/master/SSD and the+    PR MNE-based implementation of Denis A. Engemann <denis.engemann@gmail.com>++    SSD seeks at maximizing the power at a frequency band of interest while+    simultaneously minimizing it at the flanking (surrounding) frequency bins+    (considered noise). It extremizes the covariance matrices associated to+    signal and noise.++    Cosidering f as the freq. of interest, noise signals can be calculated+    either by filtering the signals in the frequency range [f−Δfb:f+Δfb]+    and then performing band-stop filtering around frequency f [f−Δfs:f+Δfs],+    where Δfb and Δfs generally are set equal to 2 and 1 Hz, or by filtering+    in the frequency range [f−Δf:f+Δf] with the following subtraction of+    the filtered signal around f [1].++    SSD can either be used as a dimentionality reduction method or a denoised+    ‘denoised’ low rank factorization method [2].      Parameters     ----------     filt_params_signal : dict         Filtering for the frequencies of interst.     filt_params_noise  : dict         Filtering for the frequencies of non-interest.-    estimator : str-        Which covariance estimator to use. Defaults to "oas".-    n_components  : int, None-        How many components to keep. Default to 5.-    subtract_signal : bool-        Whether to subtract the noise from the signal to enhcane-        sptial filter.-    sort_by_spectral_ratio : bool-        Whether to sort by the spectral ratio. Defaults to True.-+    sampling_freq : float+        sampling frequency (in Hz) of the recordings.+    estimator : float | str | None (default 'oas')+        Which covariance estimator to use+        If not None (same as 'empirical'), allow regularization for+        covariance estimation. If float, shrinkage is used+        (0 <= shrinkage <= 1). For str options, estimator will be passed to+        method to mne.compute_covariance().+    n_components : int| None (default None)+        The number of components to decompose the signals.+        If n_components is None no dimentionality reduction is made, and the+        transformed data is projected in the whole source space.+   picks: array| int | None  (default None)+       Indeces of good-channels. Can be the output of mne.pick_types++   sort_by_spectral_ratio: bool (default True)+       if set to True, the components are sorted according+       to the spectral ratio+       See [1] Nikulin 2011, Eq. (24)++   return_filtered : bool (default False)+        If return_filtered is True, data is bandpassed and projected onto+        the SSD components.++   n_fft: int (default None)+       if sort_by_spectral_ratio is set to True, then the sources will be+       sorted accordinly to their spectral ratio which is calculated based on+       "psd_array_welch" function. the n_fft set the length of FFT used.+       See mne.time_frequency.psd_array_welch for more information++   cov_method_params : TYPE, optional+        As in mne.decoding.SPoC+        The default is None.+   rank : None | dict | ‘info’ | ‘full’+        As in mne.decoding.SPoC+        This controls the rank computation that can be read from the+        measurement info or estimated from the data.+        See Notes of mne.compute_rank() for details.The default is None.+        The default is None.++    REFERENCES:+    [1] Nikulin, V. V., Nolte, G., & Curio, G. (2011). A novel method for+    reliable and fast extraction of neuronal EEG/MEG oscillations on the basis+    of spatio-spectral decomposition. NeuroImage, 55(4), 1528-1535.+    [2] Haufe, S., Dähne, S., & Nikulin, V. V. (2014). Dimensionality reduction+    for the analysis of brain oscillations. NeuroImage, 101, 583-597.

Check it out, you should have access to doc/references.bib

vpeterson

comment created time in 2 days

PullRequestReviewEvent

Pull request review commentdengemann/mne-python

added option to handle epoched data

 import mne from mne import Epochs from mne.datasets.fieldtrip_cmc import data_path-from mne.utils import _time_mask from mne.channels import read_layout from mne.decoding import TransformerMixin, BaseEstimator +from mne.io.base import BaseRaw+from mne.epochs import BaseEpochs+from mne.utils import _time_mask+from mne.cov import (_regularized_covariance, compute_raw_covariance)+from mne.filter import filter_data+from mne.time_frequency import psd_array_welch+import locale+locale.setlocale(locale.LC_ALL, "en_US.UTF-8")+  def freq_mask(freqs, fmin, fmax):     """convenience function to select frequencies"""     return _time_mask(freqs, fmin, fmax) + # Define parameters fname = data_path() + '/SubjectCMC.ds' raw = mne.io.read_raw_ctf(fname) raw.crop(50., 250.).load_data()  # crop for memory purposes+picks = mne.pick_types(raw.info, meg=True, eeg=False, ref_meg=False)+sf = raw.info['sfreq']  freqs_sig = 9, 12 freqs_noise = 8, 13   class SSD(BaseEstimator, TransformerMixin):-    """Implement Spatio-Spectral Decomposision+    """+    This is a Python Implementation of Spatio Spectral Decomposition (SSD)+    method [1],[2] for both raw and epoched data. This source code is  based on+    the matlab implementation available at+    https://github.com/svendaehne/matlab_SPoC/tree/master/SSD and the+    PR MNE-based implementation of Denis A. Engemann <denis.engemann@gmail.com>++    SSD seeks at maximizing the power at a frequency band of interest while+    simultaneously minimizing it at the flanking (surrounding) frequency bins+    (considered noise). It extremizes the covariance matrices associated to+    signal and noise.++    Cosidering f as the freq. of interest, noise signals can be calculated+    either by filtering the signals in the frequency range [f−Δfb:f+Δfb]+    and then performing band-stop filtering around frequency f [f−Δfs:f+Δfs],+    where Δfb and Δfs generally are set equal to 2 and 1 Hz, or by filtering+    in the frequency range [f−Δf:f+Δf] with the following subtraction of+    the filtered signal around f [1].++    SSD can either be used as a dimentionality reduction method or a denoised+    ‘denoised’ low rank factorization method [2].      Parameters     ----------     filt_params_signal : dict         Filtering for the frequencies of interst.     filt_params_noise  : dict         Filtering for the frequencies of non-interest.-    estimator : str-        Which covariance estimator to use. Defaults to "oas".-    n_components  : int, None-        How many components to keep. Default to 5.-    subtract_signal : bool-        Whether to subtract the noise from the signal to enhcane-        sptial filter.-    sort_by_spectral_ratio : bool-        Whether to sort by the spectral ratio. Defaults to True.-+    sampling_freq : float+        sampling frequency (in Hz) of the recordings.+    estimator : float | str | None (default 'oas')+        Which covariance estimator to use+        If not None (same as 'empirical'), allow regularization for+        covariance estimation. If float, shrinkage is used+        (0 <= shrinkage <= 1). For str options, estimator will be passed to+        method to mne.compute_covariance().+    n_components : int| None (default None)+        The number of components to decompose the signals.+        If n_components is None no dimentionality reduction is made, and the+        transformed data is projected in the whole source space.+   picks: array| int | None  (default None)+       Indeces of good-channels. Can be the output of mne.pick_types++   sort_by_spectral_ratio: bool (default True)+       if set to True, the components are sorted according+       to the spectral ratio+       See [1] Nikulin 2011, Eq. (24)++   return_filtered : bool (default False)+        If return_filtered is True, data is bandpassed and projected onto+        the SSD components.++   n_fft: int (default None)+       if sort_by_spectral_ratio is set to True, then the sources will be+       sorted accordinly to their spectral ratio which is calculated based on+       "psd_array_welch" function. the n_fft set the length of FFT used.+       See mne.time_frequency.psd_array_welch for more information++   cov_method_params : TYPE, optional+        As in mne.decoding.SPoC+        The default is None.+   rank : None | dict | ‘info’ | ‘full’+        As in mne.decoding.SPoC+        This controls the rank computation that can be read from the+        measurement info or estimated from the data.+        See Notes of mne.compute_rank() for details.The default is None.+        The default is None.++    REFERENCES:+    [1] Nikulin, V. V., Nolte, G., & Curio, G. (2011). A novel method for+    reliable and fast extraction of neuronal EEG/MEG oscillations on the basis+    of spatio-spectral decomposition. NeuroImage, 55(4), 1528-1535.+    [2] Haufe, S., Dähne, S., & Nikulin, V. V. (2014). Dimensionality reduction+    for the analysis of brain oscillations. NeuroImage, 101, 583-597.     """ -    def __init__(self, filt_params_signal, filt_params_noise,-                 estimator='oas', n_components=None,-                 subtract_signal=True,-                 reject=None,-                 flat=None,-                 picks=None,-                 sort_by_spectral_ratio=True):+    def __init__(self, filt_params_signal, filt_params_noise, sampling_freq,+                 estimator='oas', n_components=None, picks=None,+                 sort_by_spectral_ratio=True, return_filtered=False,+                 n_fft=None, cov_method_params=None, rank=None):         """Initialize instance"""          dicts = {"signal": filt_params_signal, "noise": filt_params_noise}         for param, dd in [('l', 0), ('h', 0), ('l', 1), ('h', 1)]:             key = ('signal', 'noise')[dd]-            if  param + '_freq' not in dicts[key]:+            if param + '_freq' not in dicts[key]:                 raise ValueError(-                    "'%' must be defined in filter parameters for %s" % key)+                    "'%%' must be defined in filter parameters for %s" % key)             val = dicts[key][param + '_freq']             if not isinstance(val, (int, float)):                 raise ValueError(                     "Frequencies must be numbers, got %s" % type(val))+        # check freq bands+        if (filt_params_noise['l_freq'] > filt_params_signal['l_freq'] or+                filt_params_signal['h_freq'] > filt_params_noise['h_freq']):+            raise ValueError('Wrongly specified frequency bands!\n \+                The signal band-pass must be within the t noise band-pass!')

Ahh I was not looking properly. You can try something like this:

raise ValueError('Wrongly specified frequency bands!\n'
                            'The signal band-pass must be within the t noise band-pass!')
vpeterson

comment created time in 2 days

PullRequestReviewEvent

pull request commentmne-tools/mne-python

DOC: add literature reference for apply_inverse_cov

I think we do not necessarily have to wait for a reply from John Mosher.

Once we have more info, we can amend.

If you do not have other concerns @larsoner @drammock I'm happy to merge in principle.

I see some CI's have been failing. Do you think this is related to the changes proposed?

dengemann

comment created time in 2 days

pull request commentdengemann/mne-python

added option to handle epoched data

@vpeterson are you happy -- in principle with your PR ? We could merge it to move on and then discuss what's next.

I nevertheless found a few points. I suggest we merge once you have addressed those.

vpeterson

comment created time in 2 days

Pull request review commentdengemann/mne-python

added option to handle epoched data

 import mne from mne import Epochs from mne.datasets.fieldtrip_cmc import data_path-from mne.utils import _time_mask from mne.channels import read_layout from mne.decoding import TransformerMixin, BaseEstimator +from mne.io.base import BaseRaw+from mne.epochs import BaseEpochs+from mne.utils import _time_mask+from mne.cov import (_regularized_covariance, compute_raw_covariance)+from mne.filter import filter_data+from mne.time_frequency import psd_array_welch+import locale+locale.setlocale(locale.LC_ALL, "en_US.UTF-8")+  def freq_mask(freqs, fmin, fmax):     """convenience function to select frequencies"""     return _time_mask(freqs, fmin, fmax) + # Define parameters fname = data_path() + '/SubjectCMC.ds' raw = mne.io.read_raw_ctf(fname) raw.crop(50., 250.).load_data()  # crop for memory purposes+picks = mne.pick_types(raw.info, meg=True, eeg=False, ref_meg=False)+sf = raw.info['sfreq']  freqs_sig = 9, 12 freqs_noise = 8, 13   class SSD(BaseEstimator, TransformerMixin):-    """Implement Spatio-Spectral Decomposision+    """+    This is a Python Implementation of Spatio Spectral Decomposition (SSD)+    method [1],[2] for both raw and epoched data. This source code is  based on+    the matlab implementation available at+    https://github.com/svendaehne/matlab_SPoC/tree/master/SSD and the+    PR MNE-based implementation of Denis A. Engemann <denis.engemann@gmail.com>++    SSD seeks at maximizing the power at a frequency band of interest while+    simultaneously minimizing it at the flanking (surrounding) frequency bins+    (considered noise). It extremizes the covariance matrices associated to+    signal and noise.++    Cosidering f as the freq. of interest, noise signals can be calculated+    either by filtering the signals in the frequency range [f−Δfb:f+Δfb]+    and then performing band-stop filtering around frequency f [f−Δfs:f+Δfs],+    where Δfb and Δfs generally are set equal to 2 and 1 Hz, or by filtering+    in the frequency range [f−Δf:f+Δf] with the following subtraction of+    the filtered signal around f [1].++    SSD can either be used as a dimentionality reduction method or a denoised+    ‘denoised’ low rank factorization method [2].      Parameters     ----------     filt_params_signal : dict         Filtering for the frequencies of interst.     filt_params_noise  : dict         Filtering for the frequencies of non-interest.-    estimator : str-        Which covariance estimator to use. Defaults to "oas".-    n_components  : int, None-        How many components to keep. Default to 5.-    subtract_signal : bool-        Whether to subtract the noise from the signal to enhcane-        sptial filter.-    sort_by_spectral_ratio : bool-        Whether to sort by the spectral ratio. Defaults to True.-+    sampling_freq : float+        sampling frequency (in Hz) of the recordings.+    estimator : float | str | None (default 'oas')+        Which covariance estimator to use+        If not None (same as 'empirical'), allow regularization for+        covariance estimation. If float, shrinkage is used+        (0 <= shrinkage <= 1). For str options, estimator will be passed to+        method to mne.compute_covariance().+    n_components : int| None (default None)+        The number of components to decompose the signals.+        If n_components is None no dimentionality reduction is made, and the+        transformed data is projected in the whole source space.+   picks: array| int | None  (default None)+       Indeces of good-channels. Can be the output of mne.pick_types++   sort_by_spectral_ratio: bool (default True)+       if set to True, the components are sorted according+       to the spectral ratio+       See [1] Nikulin 2011, Eq. (24)++   return_filtered : bool (default False)+        If return_filtered is True, data is bandpassed and projected onto+        the SSD components.++   n_fft: int (default None)+       if sort_by_spectral_ratio is set to True, then the sources will be+       sorted accordinly to their spectral ratio which is calculated based on+       "psd_array_welch" function. the n_fft set the length of FFT used.+       See mne.time_frequency.psd_array_welch for more information++   cov_method_params : TYPE, optional+        As in mne.decoding.SPoC+        The default is None.+   rank : None | dict | ‘info’ | ‘full’+        As in mne.decoding.SPoC+        This controls the rank computation that can be read from the+        measurement info or estimated from the data.+        See Notes of mne.compute_rank() for details.The default is None.+        The default is None.++    REFERENCES:+    [1] Nikulin, V. V., Nolte, G., & Curio, G. (2011). A novel method for+    reliable and fast extraction of neuronal EEG/MEG oscillations on the basis+    of spatio-spectral decomposition. NeuroImage, 55(4), 1528-1535.+    [2] Haufe, S., Dähne, S., & Nikulin, V. V. (2014). Dimensionality reduction+    for the analysis of brain oscillations. NeuroImage, 101, 583-597.     """ -    def __init__(self, filt_params_signal, filt_params_noise,-                 estimator='oas', n_components=None,-                 subtract_signal=True,-                 reject=None,-                 flat=None,-                 picks=None,-                 sort_by_spectral_ratio=True):+    def __init__(self, filt_params_signal, filt_params_noise, sampling_freq,+                 estimator='oas', n_components=None, picks=None,+                 sort_by_spectral_ratio=True, return_filtered=False,+                 n_fft=None, cov_method_params=None, rank=None):         """Initialize instance"""          dicts = {"signal": filt_params_signal, "noise": filt_params_noise}         for param, dd in [('l', 0), ('h', 0), ('l', 1), ('h', 1)]:             key = ('signal', 'noise')[dd]-            if  param + '_freq' not in dicts[key]:+            if param + '_freq' not in dicts[key]:                 raise ValueError(-                    "'%' must be defined in filter parameters for %s" % key)+                    "'%%' must be defined in filter parameters for %s" % key)             val = dicts[key][param + '_freq']             if not isinstance(val, (int, float)):                 raise ValueError(                     "Frequencies must be numbers, got %s" % type(val))+        # check freq bands+        if (filt_params_noise['l_freq'] > filt_params_signal['l_freq'] or+                filt_params_signal['h_freq'] > filt_params_noise['h_freq']):+            raise ValueError('Wrongly specified frequency bands!\n \+                The signal band-pass must be within the t noise band-pass!')          self.freqs_signal = (filt_params_signal['l_freq'],                              filt_params_signal['h_freq'])         self.freqs_noise = (filt_params_noise['l_freq'],                             filt_params_noise['h_freq'])         self.filt_params_signal = filt_params_signal         self.filt_params_noise = filt_params_noise-        self.subtract_signal = subtract_signal-        self.picks = picks+        self.sort_by_spectral_ratio = sort_by_spectral_ratio+        if n_fft is None:+            self.n_fft = int(sampling_freq)+        else:+            self.n_fft = int(n_fft)+        self.picks_ = picks+        self.return_filtered = return_filtered         self.estimator = estimator         self.n_components = n_components--    def fit(self, inst):-        """Fit"""-        if self.picks == None:-            self.picks_ = mne.pick_types(inst.info, meg=True, eeg=False, ref_meg=False)-        else:-            self.picks_ = self.picks-        if isinstance(inst, mne.io.base.BaseRaw):+        self.rank = rank+        self.sampling_freq = sampling_freq+        self.cov_method_params = cov_method_params++    def _check_X(self, inst):+        """Check input data."""+        if not isinstance(inst, np.ndarray):+            raise ValueError("X should be of type ndarray (got %s)."+                             % type(inst))+        if inst.ndim < 3:+            raise ValueError('X must have at least 3 dimensions.')++    def filter_data(self, inst):+        if isinstance(inst, BaseRaw):             inst_signal = inst.copy()             inst_signal.filter(picks=self.picks_, **self.filt_params_signal)-+            # noise             inst_noise = inst.copy()             inst_noise.filter(picks=self.picks_, **self.filt_params_noise)-            if self.subtract_signal:-                inst_noise._data[self.picks_] -= inst_signal._data[self.picks_]-            cov_signal = mne.compute_raw_covariance(-                inst_signal, picks=self.picks_, method=self.estimator)-            cov_noise = mne.compute_raw_covariance(inst_noise, picks=self.picks_,-                method=self.estimator)+            # subtract signal:+            inst_noise._data[self.picks_] -= inst_signal._data[self.picks_]+        else:+            if isinstance(inst, BaseEpochs) or isinstance(inst, np.ndarray):+                # data X is epoched+                # part of the following code is copied from mne csp+                n_epochs, n_channels, n_samples = inst.shape+                self.max_components = n_channels+                # reshape for filtering+                X_aux = np.reshape(inst, [n_epochs, n_channels*n_samples])+                inst_signal = filter_data(+                    X_aux, self.sampling_freq, **self.filt_params_signal)+                # rephase for filtering+                X_aux = np.reshape(inst, [n_epochs, n_channels*n_samples])+                inst_noise = filter_data(+                    X_aux, self.sampling_freq, **self.filt_params_noise)+                # subtract signal:+                inst_noise -= inst_signal+                # Estimate single trial covariance+                # reshape to original shape+                inst_signal = np.reshape(+                    inst_signal, [n_epochs, n_channels, n_samples])+                # reshape to original shape+                inst_noise = np.reshape(+                    inst_noise, [n_epochs, n_channels, n_samples])+        return inst_signal, inst_noise++    def fit(self, inst):+        """Fit"""+        if isinstance(inst, BaseRaw):+            if self.picks_ is None:+                raise ValueError('picks should be provided')+            self.max_components = len(self.picks_)+            inst_signal, inst_noise = self.filter_data(inst)+            cov_signal = compute_raw_covariance(+                inst_signal, picks=self.picks_,+                method=self.estimator, rank=self.rank)+            cov_noise = compute_raw_covariance(+                inst_noise, picks=self.picks_,+                method=self.estimator, rank=self.rank)             del inst_noise             del inst_signal         else:-            raise NotImplementedError()--        self.eigvals_, self.filters_ = eigh(cov_signal.data, cov_noise.data)+            if not isinstance(inst, np.ndarray):+                raise NotImplementedError()+            self._check_X(inst)++            # data X is epoched+            # part of the following code is copied from mne csp+            n_epochs, n_channels, n_samples = inst.shape+            self.max_components = n_channels+            X_s, X_n = self.filter_data(inst)+            covs = np.empty((n_epochs, n_channels, n_channels))+            for ii, epoch in enumerate(X_s):+                covs[ii] = _regularized_covariance(+                    epoch, reg=self.estimator,+                    method_params=self.cov_method_params, rank=self.rank)+            cov_signal = covs.mean(0)+            # Covariance matrix for the flanking frequencies (noise)+            # Estimate single trial covariance+            covs_n = np.empty((n_epochs, n_channels, n_channels))+            for ii, epoch in enumerate(X_n):+                covs_n[ii] = _regularized_covariance(+                    epoch, reg=self.estimator,+                    method_params=self.cov_method_params,+                    rank=self.rank)+            cov_noise = covs_n.mean(0)+        eigvals_, eigvects_ = eigh(cov_signal.data, cov_noise.data)+        # sort in descencing order+        ix = np.argsort(eigvals_)[::-1]+        self.eigvals_ = eigvals_[ix]+        self.filters_ = eigvects_[:, ix]         self.patterns_ = np.linalg.pinv(self.filters_)--    def transform(self, data):-        if self.n_components is None:-            n_components = len(self.picks_)+        return self++    def spectral_ratio_ssd(self, ssd_sources):+        """Spectral ratio measure for best n_components selection+        See Nikulin 2011, Eq. (24)+        Parameters+        ----------+        ssd_sources : data projected on the SSD space.+        output of transform+        """+        psd, freqs = psd_array_welch(+            ssd_sources, sfreq=self.sampling_freq, n_fft=self.n_fft)+        sig_idx = _time_mask(freqs, *self.freqs_signal)+        noise_idx = _time_mask(freqs, *self.freqs_noise)+        if psd.ndim == 3:+            mean_sig = psd[:, :, sig_idx].mean(axis=2).mean(axis=0)+            mean_noise = psd[:, :, noise_idx].mean(axis=2).mean(axis=0)+            spec_ratio = mean_sig / mean_noise+        else:+            mean_sig = psd[:, sig_idx].mean(axis=1)+            mean_noise = psd[:, noise_idx].mean(axis=1)+            spec_ratio = mean_sig / mean_noise+        sorter_spec = spec_ratio.argsort()[::-1]+        return spec_ratio, sorter_spec++    def transform(self, inst):+        """Estimate epochs sources given the SSD filters.++        Parameters+        ----------+        inst : instance of Raw or Epochs (n_epochs, n_channels, n_times)+            The data to be processed. The instance is modified inplace.+        Returns+        -------+        out : instance of Raw or Epochs+            The processed data.+        """+        if self.filters_ is None:+            raise RuntimeError('No filters available. Please first call fit')+        if self.return_filtered:+            inst, _ = self.filter_data(inst)+        if isinstance(inst, BaseRaw):+            data = inst.get_data()+            X_ssd = np.dot(self.filters_.T, data[self.picks_])         else:-            n_components = self.n_components-        return np.dot(self.filters_.T[:n_components], data[self.picks_])+            if not isinstance(inst, np.ndarray):+                raise NotImplementedError()+            self._check_X(inst)+            data = inst+            # project data on source space+            X_ssd = np.asarray(+                    [np.dot(self.filters_.T, epoch) for epoch in data])+        if self.sort_by_spectral_ratio:+            self.spec_ratio, self.sorter_spec = self.spectral_ratio_ssd(+                ssd_sources=X_ssd)+            self.filters_ = self.filters_[:, self.sorter_spec]+            self.patterns_ = self.patterns_[self.sorter_spec]++            if isinstance(inst, BaseRaw):+                X_ssd = X_ssd[self.sorter_spec]+            else:+                if not isinstance(inst, np.ndarray):+                    raise NotImplementedError()+                X_ssd = X_ssd[:, self.sorter_spec, :]+            if self.n_components is None:+                n_components = self.max_components+                return X_ssd+            else:+                n_components = self.n_components+                if isinstance(inst, BaseRaw):+                    X_ssd = X_ssd[:n_components]+                else:+                    if not isinstance(inst, np.ndarray):+                        raise NotImplementedError()+                    X_ssd = X_ssd[:, :n_components, :]+                return X_ssd++    def apply(self, inst):+        """+        Remove selected components from the signal.+        This procedure will reconstruct M/EEG signals from which the dynamics+        described by the excluded components is subtracted+        (denoised by low-rank factorization).+        See [2]  Haufe et al. for more information.++        The data is processed in place.++        Parameters+        ----------+        inst : instance of Raw or Epochs+            The data to be processed. The instance is modified inplace.+++        Returns+        -------+        out : instance of Raw or Epochs+            The processed data.+        """+        X = np.empty_like(inst)+        X_ssd = self.transform(inst)+        pick_patterns = self.patterns_[:self.n_components].T+        if isinstance(inst, BaseRaw):+            X = np.dot(pick_patterns, X_ssd) -    def apply(self, instance):-        pass+        else:+            if not isinstance(inst, np.ndarray):+                raise NotImplementedError()+            self._check_X(inst)+            X = np.asarray(+                    [np.dot(pick_patterns, epoch) for epoch in X_ssd])

I guess this goes in 1 line ?

vpeterson

comment created time in 2 days

PullRequestReviewEvent

Pull request review commentdengemann/mne-python

added option to handle epoched data

 import mne from mne import Epochs from mne.datasets.fieldtrip_cmc import data_path-from mne.utils import _time_mask from mne.channels import read_layout from mne.decoding import TransformerMixin, BaseEstimator +from mne.io.base import BaseRaw+from mne.epochs import BaseEpochs+from mne.utils import _time_mask+from mne.cov import (_regularized_covariance, compute_raw_covariance)+from mne.filter import filter_data+from mne.time_frequency import psd_array_welch+import locale+locale.setlocale(locale.LC_ALL, "en_US.UTF-8")+  def freq_mask(freqs, fmin, fmax):     """convenience function to select frequencies"""     return _time_mask(freqs, fmin, fmax) + # Define parameters fname = data_path() + '/SubjectCMC.ds' raw = mne.io.read_raw_ctf(fname) raw.crop(50., 250.).load_data()  # crop for memory purposes+picks = mne.pick_types(raw.info, meg=True, eeg=False, ref_meg=False)+sf = raw.info['sfreq']  freqs_sig = 9, 12 freqs_noise = 8, 13   class SSD(BaseEstimator, TransformerMixin):-    """Implement Spatio-Spectral Decomposision+    """+    This is a Python Implementation of Spatio Spectral Decomposition (SSD)+    method [1],[2] for both raw and epoched data. This source code is  based on+    the matlab implementation available at+    https://github.com/svendaehne/matlab_SPoC/tree/master/SSD and the+    PR MNE-based implementation of Denis A. Engemann <denis.engemann@gmail.com>++    SSD seeks at maximizing the power at a frequency band of interest while+    simultaneously minimizing it at the flanking (surrounding) frequency bins+    (considered noise). It extremizes the covariance matrices associated to+    signal and noise.++    Cosidering f as the freq. of interest, noise signals can be calculated+    either by filtering the signals in the frequency range [f−Δfb:f+Δfb]+    and then performing band-stop filtering around frequency f [f−Δfs:f+Δfs],+    where Δfb and Δfs generally are set equal to 2 and 1 Hz, or by filtering+    in the frequency range [f−Δf:f+Δf] with the following subtraction of+    the filtered signal around f [1].++    SSD can either be used as a dimentionality reduction method or a denoised+    ‘denoised’ low rank factorization method [2].      Parameters     ----------     filt_params_signal : dict         Filtering for the frequencies of interst.     filt_params_noise  : dict         Filtering for the frequencies of non-interest.-    estimator : str-        Which covariance estimator to use. Defaults to "oas".-    n_components  : int, None-        How many components to keep. Default to 5.-    subtract_signal : bool-        Whether to subtract the noise from the signal to enhcane-        sptial filter.-    sort_by_spectral_ratio : bool-        Whether to sort by the spectral ratio. Defaults to True.-+    sampling_freq : float+        sampling frequency (in Hz) of the recordings.+    estimator : float | str | None (default 'oas')+        Which covariance estimator to use+        If not None (same as 'empirical'), allow regularization for+        covariance estimation. If float, shrinkage is used+        (0 <= shrinkage <= 1). For str options, estimator will be passed to+        method to mne.compute_covariance().+    n_components : int| None (default None)+        The number of components to decompose the signals.+        If n_components is None no dimentionality reduction is made, and the+        transformed data is projected in the whole source space.+   picks: array| int | None  (default None)+       Indeces of good-channels. Can be the output of mne.pick_types++   sort_by_spectral_ratio: bool (default True)+       if set to True, the components are sorted according+       to the spectral ratio+       See [1] Nikulin 2011, Eq. (24)++   return_filtered : bool (default False)+        If return_filtered is True, data is bandpassed and projected onto+        the SSD components.++   n_fft: int (default None)+       if sort_by_spectral_ratio is set to True, then the sources will be+       sorted accordinly to their spectral ratio which is calculated based on+       "psd_array_welch" function. the n_fft set the length of FFT used.+       See mne.time_frequency.psd_array_welch for more information++   cov_method_params : TYPE, optional+        As in mne.decoding.SPoC+        The default is None.+   rank : None | dict | ‘info’ | ‘full’+        As in mne.decoding.SPoC+        This controls the rank computation that can be read from the+        measurement info or estimated from the data.+        See Notes of mne.compute_rank() for details.The default is None.+        The default is None.++    REFERENCES:+    [1] Nikulin, V. V., Nolte, G., & Curio, G. (2011). A novel method for+    reliable and fast extraction of neuronal EEG/MEG oscillations on the basis+    of spatio-spectral decomposition. NeuroImage, 55(4), 1528-1535.+    [2] Haufe, S., Dähne, S., & Nikulin, V. V. (2014). Dimensionality reduction+    for the analysis of brain oscillations. NeuroImage, 101, 583-597.     """ -    def __init__(self, filt_params_signal, filt_params_noise,-                 estimator='oas', n_components=None,-                 subtract_signal=True,-                 reject=None,-                 flat=None,-                 picks=None,-                 sort_by_spectral_ratio=True):+    def __init__(self, filt_params_signal, filt_params_noise, sampling_freq,+                 estimator='oas', n_components=None, picks=None,+                 sort_by_spectral_ratio=True, return_filtered=False,+                 n_fft=None, cov_method_params=None, rank=None):         """Initialize instance"""          dicts = {"signal": filt_params_signal, "noise": filt_params_noise}         for param, dd in [('l', 0), ('h', 0), ('l', 1), ('h', 1)]:             key = ('signal', 'noise')[dd]-            if  param + '_freq' not in dicts[key]:+            if param + '_freq' not in dicts[key]:                 raise ValueError(-                    "'%' must be defined in filter parameters for %s" % key)+                    "'%%' must be defined in filter parameters for %s" % key)             val = dicts[key][param + '_freq']             if not isinstance(val, (int, float)):                 raise ValueError(                     "Frequencies must be numbers, got %s" % type(val))+        # check freq bands+        if (filt_params_noise['l_freq'] > filt_params_signal['l_freq'] or+                filt_params_signal['h_freq'] > filt_params_noise['h_freq']):+            raise ValueError('Wrongly specified frequency bands!\n \+                The signal band-pass must be within the t noise band-pass!')          self.freqs_signal = (filt_params_signal['l_freq'],                              filt_params_signal['h_freq'])         self.freqs_noise = (filt_params_noise['l_freq'],                             filt_params_noise['h_freq'])         self.filt_params_signal = filt_params_signal         self.filt_params_noise = filt_params_noise-        self.subtract_signal = subtract_signal-        self.picks = picks+        self.sort_by_spectral_ratio = sort_by_spectral_ratio+        if n_fft is None:+            self.n_fft = int(sampling_freq)+        else:+            self.n_fft = int(n_fft)+        self.picks_ = picks+        self.return_filtered = return_filtered         self.estimator = estimator         self.n_components = n_components--    def fit(self, inst):-        """Fit"""-        if self.picks == None:-            self.picks_ = mne.pick_types(inst.info, meg=True, eeg=False, ref_meg=False)-        else:-            self.picks_ = self.picks-        if isinstance(inst, mne.io.base.BaseRaw):+        self.rank = rank+        self.sampling_freq = sampling_freq+        self.cov_method_params = cov_method_params++    def _check_X(self, inst):+        """Check input data."""+        if not isinstance(inst, np.ndarray):+            raise ValueError("X should be of type ndarray (got %s)."+                             % type(inst))+        if inst.ndim < 3:+            raise ValueError('X must have at least 3 dimensions.')++    def filter_data(self, inst):+        if isinstance(inst, BaseRaw):             inst_signal = inst.copy()             inst_signal.filter(picks=self.picks_, **self.filt_params_signal)-+            # noise             inst_noise = inst.copy()             inst_noise.filter(picks=self.picks_, **self.filt_params_noise)-            if self.subtract_signal:-                inst_noise._data[self.picks_] -= inst_signal._data[self.picks_]-            cov_signal = mne.compute_raw_covariance(-                inst_signal, picks=self.picks_, method=self.estimator)-            cov_noise = mne.compute_raw_covariance(inst_noise, picks=self.picks_,-                method=self.estimator)+            # subtract signal:+            inst_noise._data[self.picks_] -= inst_signal._data[self.picks_]+        else:+            if isinstance(inst, BaseEpochs) or isinstance(inst, np.ndarray):+                # data X is epoched+                # part of the following code is copied from mne csp+                n_epochs, n_channels, n_samples = inst.shape+                self.max_components = n_channels+                # reshape for filtering+                X_aux = np.reshape(inst, [n_epochs, n_channels*n_samples])+                inst_signal = filter_data(+                    X_aux, self.sampling_freq, **self.filt_params_signal)+                # rephase for filtering+                X_aux = np.reshape(inst, [n_epochs, n_channels*n_samples])+                inst_noise = filter_data(+                    X_aux, self.sampling_freq, **self.filt_params_noise)+                # subtract signal:+                inst_noise -= inst_signal+                # Estimate single trial covariance+                # reshape to original shape+                inst_signal = np.reshape(+                    inst_signal, [n_epochs, n_channels, n_samples])+                # reshape to original shape+                inst_noise = np.reshape(+                    inst_noise, [n_epochs, n_channels, n_samples])+        return inst_signal, inst_noise++    def fit(self, inst):+        """Fit"""+        if isinstance(inst, BaseRaw):+            if self.picks_ is None:+                raise ValueError('picks should be provided')+            self.max_components = len(self.picks_)+            inst_signal, inst_noise = self.filter_data(inst)+            cov_signal = compute_raw_covariance(+                inst_signal, picks=self.picks_,+                method=self.estimator, rank=self.rank)+            cov_noise = compute_raw_covariance(+                inst_noise, picks=self.picks_,+                method=self.estimator, rank=self.rank)             del inst_noise             del inst_signal         else:-            raise NotImplementedError()--        self.eigvals_, self.filters_ = eigh(cov_signal.data, cov_noise.data)+            if not isinstance(inst, np.ndarray):+                raise NotImplementedError()+            self._check_X(inst)++            # data X is epoched+            # part of the following code is copied from mne csp+            n_epochs, n_channels, n_samples = inst.shape+            self.max_components = n_channels+            X_s, X_n = self.filter_data(inst)+            covs = np.empty((n_epochs, n_channels, n_channels))+            for ii, epoch in enumerate(X_s):+                covs[ii] = _regularized_covariance(+                    epoch, reg=self.estimator,+                    method_params=self.cov_method_params, rank=self.rank)+            cov_signal = covs.mean(0)+            # Covariance matrix for the flanking frequencies (noise)+            # Estimate single trial covariance+            covs_n = np.empty((n_epochs, n_channels, n_channels))+            for ii, epoch in enumerate(X_n):+                covs_n[ii] = _regularized_covariance(+                    epoch, reg=self.estimator,+                    method_params=self.cov_method_params,+                    rank=self.rank)+            cov_noise = covs_n.mean(0)+        eigvals_, eigvects_ = eigh(cov_signal.data, cov_noise.data)+        # sort in descencing order+        ix = np.argsort(eigvals_)[::-1]+        self.eigvals_ = eigvals_[ix]+        self.filters_ = eigvects_[:, ix]         self.patterns_ = np.linalg.pinv(self.filters_)--    def transform(self, data):-        if self.n_components is None:-            n_components = len(self.picks_)+        return self++    def spectral_ratio_ssd(self, ssd_sources):+        """Spectral ratio measure for best n_components selection+        See Nikulin 2011, Eq. (24)+        Parameters+        ----------+        ssd_sources : data projected on the SSD space.+        output of transform+        """+        psd, freqs = psd_array_welch(+            ssd_sources, sfreq=self.sampling_freq, n_fft=self.n_fft)+        sig_idx = _time_mask(freqs, *self.freqs_signal)+        noise_idx = _time_mask(freqs, *self.freqs_noise)+        if psd.ndim == 3:+            mean_sig = psd[:, :, sig_idx].mean(axis=2).mean(axis=0)+            mean_noise = psd[:, :, noise_idx].mean(axis=2).mean(axis=0)+            spec_ratio = mean_sig / mean_noise+        else:+            mean_sig = psd[:, sig_idx].mean(axis=1)+            mean_noise = psd[:, noise_idx].mean(axis=1)+            spec_ratio = mean_sig / mean_noise+        sorter_spec = spec_ratio.argsort()[::-1]+        return spec_ratio, sorter_spec++    def transform(self, inst):+        """Estimate epochs sources given the SSD filters.++        Parameters+        ----------+        inst : instance of Raw or Epochs (n_epochs, n_channels, n_times)+            The data to be processed. The instance is modified inplace.+        Returns+        -------+        out : instance of Raw or Epochs+            The processed data.+        """+        if self.filters_ is None:+            raise RuntimeError('No filters available. Please first call fit')+        if self.return_filtered:+            inst, _ = self.filter_data(inst)+        if isinstance(inst, BaseRaw):+            data = inst.get_data()+            X_ssd = np.dot(self.filters_.T, data[self.picks_])         else:-            n_components = self.n_components-        return np.dot(self.filters_.T[:n_components], data[self.picks_])+            if not isinstance(inst, np.ndarray):+                raise NotImplementedError()+            self._check_X(inst)+            data = inst+            # project data on source space+            X_ssd = np.asarray(+                    [np.dot(self.filters_.T, epoch) for epoch in data])+        if self.sort_by_spectral_ratio:+            self.spec_ratio, self.sorter_spec = self.spectral_ratio_ssd(+                ssd_sources=X_ssd)+            self.filters_ = self.filters_[:, self.sorter_spec]+            self.patterns_ = self.patterns_[self.sorter_spec]++            if isinstance(inst, BaseRaw):+                X_ssd = X_ssd[self.sorter_spec]+            else:+                if not isinstance(inst, np.ndarray):+                    raise NotImplementedError()+                X_ssd = X_ssd[:, self.sorter_spec, :]+            if self.n_components is None:+                n_components = self.max_components+                return X_ssd+            else:+                n_components = self.n_components+                if isinstance(inst, BaseRaw):+                    X_ssd = X_ssd[:n_components]+                else:+                    if not isinstance(inst, np.ndarray):+                        raise NotImplementedError()+                    X_ssd = X_ssd[:, :n_components, :]+                return X_ssd++    def apply(self, inst):+        """+        Remove selected components from the signal.+        This procedure will reconstruct M/EEG signals from which the dynamics+        described by the excluded components is subtracted+        (denoised by low-rank factorization).+        See [2]  Haufe et al. for more information.++        The data is processed in place.++        Parameters+        ----------+        inst : instance of Raw or Epochs+            The data to be processed. The instance is modified inplace.+

remove extra blank line

vpeterson

comment created time in 2 days

PullRequestReviewEvent

Pull request review commentdengemann/mne-python

added option to handle epoched data

 import mne from mne import Epochs from mne.datasets.fieldtrip_cmc import data_path-from mne.utils import _time_mask from mne.channels import read_layout from mne.decoding import TransformerMixin, BaseEstimator +from mne.io.base import BaseRaw+from mne.epochs import BaseEpochs+from mne.utils import _time_mask+from mne.cov import (_regularized_covariance, compute_raw_covariance)+from mne.filter import filter_data+from mne.time_frequency import psd_array_welch+import locale+locale.setlocale(locale.LC_ALL, "en_US.UTF-8")+  def freq_mask(freqs, fmin, fmax):     """convenience function to select frequencies"""     return _time_mask(freqs, fmin, fmax) + # Define parameters fname = data_path() + '/SubjectCMC.ds' raw = mne.io.read_raw_ctf(fname) raw.crop(50., 250.).load_data()  # crop for memory purposes+picks = mne.pick_types(raw.info, meg=True, eeg=False, ref_meg=False)+sf = raw.info['sfreq']  freqs_sig = 9, 12 freqs_noise = 8, 13   class SSD(BaseEstimator, TransformerMixin):-    """Implement Spatio-Spectral Decomposision+    """+    This is a Python Implementation of Spatio Spectral Decomposition (SSD)+    method [1],[2] for both raw and epoched data. This source code is  based on+    the matlab implementation available at+    https://github.com/svendaehne/matlab_SPoC/tree/master/SSD and the+    PR MNE-based implementation of Denis A. Engemann <denis.engemann@gmail.com>++    SSD seeks at maximizing the power at a frequency band of interest while+    simultaneously minimizing it at the flanking (surrounding) frequency bins+    (considered noise). It extremizes the covariance matrices associated to+    signal and noise.++    Cosidering f as the freq. of interest, noise signals can be calculated+    either by filtering the signals in the frequency range [f−Δfb:f+Δfb]+    and then performing band-stop filtering around frequency f [f−Δfs:f+Δfs],+    where Δfb and Δfs generally are set equal to 2 and 1 Hz, or by filtering+    in the frequency range [f−Δf:f+Δf] with the following subtraction of+    the filtered signal around f [1].++    SSD can either be used as a dimentionality reduction method or a denoised+    ‘denoised’ low rank factorization method [2].      Parameters     ----------     filt_params_signal : dict         Filtering for the frequencies of interst.     filt_params_noise  : dict         Filtering for the frequencies of non-interest.-    estimator : str-        Which covariance estimator to use. Defaults to "oas".-    n_components  : int, None-        How many components to keep. Default to 5.-    subtract_signal : bool-        Whether to subtract the noise from the signal to enhcane-        sptial filter.-    sort_by_spectral_ratio : bool-        Whether to sort by the spectral ratio. Defaults to True.-+    sampling_freq : float+        sampling frequency (in Hz) of the recordings.+    estimator : float | str | None (default 'oas')+        Which covariance estimator to use+        If not None (same as 'empirical'), allow regularization for+        covariance estimation. If float, shrinkage is used+        (0 <= shrinkage <= 1). For str options, estimator will be passed to+        method to mne.compute_covariance().+    n_components : int| None (default None)+        The number of components to decompose the signals.+        If n_components is None no dimentionality reduction is made, and the+        transformed data is projected in the whole source space.+   picks: array| int | None  (default None)+       Indeces of good-channels. Can be the output of mne.pick_types++   sort_by_spectral_ratio: bool (default True)+       if set to True, the components are sorted according+       to the spectral ratio+       See [1] Nikulin 2011, Eq. (24)++   return_filtered : bool (default False)+        If return_filtered is True, data is bandpassed and projected onto+        the SSD components.++   n_fft: int (default None)+       if sort_by_spectral_ratio is set to True, then the sources will be+       sorted accordinly to their spectral ratio which is calculated based on+       "psd_array_welch" function. the n_fft set the length of FFT used.+       See mne.time_frequency.psd_array_welch for more information++   cov_method_params : TYPE, optional+        As in mne.decoding.SPoC+        The default is None.+   rank : None | dict | ‘info’ | ‘full’+        As in mne.decoding.SPoC+        This controls the rank computation that can be read from the+        measurement info or estimated from the data.+        See Notes of mne.compute_rank() for details.The default is None.+        The default is None.++    REFERENCES:+    [1] Nikulin, V. V., Nolte, G., & Curio, G. (2011). A novel method for+    reliable and fast extraction of neuronal EEG/MEG oscillations on the basis+    of spatio-spectral decomposition. NeuroImage, 55(4), 1528-1535.+    [2] Haufe, S., Dähne, S., & Nikulin, V. V. (2014). Dimensionality reduction+    for the analysis of brain oscillations. NeuroImage, 101, 583-597.     """ -    def __init__(self, filt_params_signal, filt_params_noise,-                 estimator='oas', n_components=None,-                 subtract_signal=True,-                 reject=None,-                 flat=None,-                 picks=None,-                 sort_by_spectral_ratio=True):+    def __init__(self, filt_params_signal, filt_params_noise, sampling_freq,+                 estimator='oas', n_components=None, picks=None,+                 sort_by_spectral_ratio=True, return_filtered=False,+                 n_fft=None, cov_method_params=None, rank=None):         """Initialize instance"""          dicts = {"signal": filt_params_signal, "noise": filt_params_noise}         for param, dd in [('l', 0), ('h', 0), ('l', 1), ('h', 1)]:             key = ('signal', 'noise')[dd]-            if  param + '_freq' not in dicts[key]:+            if param + '_freq' not in dicts[key]:                 raise ValueError(-                    "'%' must be defined in filter parameters for %s" % key)+                    "'%%' must be defined in filter parameters for %s" % key)             val = dicts[key][param + '_freq']             if not isinstance(val, (int, float)):                 raise ValueError(                     "Frequencies must be numbers, got %s" % type(val))+        # check freq bands+        if (filt_params_noise['l_freq'] > filt_params_signal['l_freq'] or+                filt_params_signal['h_freq'] > filt_params_noise['h_freq']):+            raise ValueError('Wrongly specified frequency bands!\n \+                The signal band-pass must be within the t noise band-pass!')          self.freqs_signal = (filt_params_signal['l_freq'],                              filt_params_signal['h_freq'])         self.freqs_noise = (filt_params_noise['l_freq'],                             filt_params_noise['h_freq'])         self.filt_params_signal = filt_params_signal         self.filt_params_noise = filt_params_noise-        self.subtract_signal = subtract_signal-        self.picks = picks+        self.sort_by_spectral_ratio = sort_by_spectral_ratio+        if n_fft is None:+            self.n_fft = int(sampling_freq)+        else:+            self.n_fft = int(n_fft)+        self.picks_ = picks+        self.return_filtered = return_filtered         self.estimator = estimator         self.n_components = n_components--    def fit(self, inst):-        """Fit"""-        if self.picks == None:-            self.picks_ = mne.pick_types(inst.info, meg=True, eeg=False, ref_meg=False)-        else:-            self.picks_ = self.picks-        if isinstance(inst, mne.io.base.BaseRaw):+        self.rank = rank+        self.sampling_freq = sampling_freq+        self.cov_method_params = cov_method_params++    def _check_X(self, inst):+        """Check input data."""+        if not isinstance(inst, np.ndarray):+            raise ValueError("X should be of type ndarray (got %s)."+                             % type(inst))+        if inst.ndim < 3:+            raise ValueError('X must have at least 3 dimensions.')++    def filter_data(self, inst):+        if isinstance(inst, BaseRaw):             inst_signal = inst.copy()             inst_signal.filter(picks=self.picks_, **self.filt_params_signal)-+            # noise             inst_noise = inst.copy()             inst_noise.filter(picks=self.picks_, **self.filt_params_noise)-            if self.subtract_signal:-                inst_noise._data[self.picks_] -= inst_signal._data[self.picks_]-            cov_signal = mne.compute_raw_covariance(-                inst_signal, picks=self.picks_, method=self.estimator)-            cov_noise = mne.compute_raw_covariance(inst_noise, picks=self.picks_,-                method=self.estimator)+            # subtract signal:+            inst_noise._data[self.picks_] -= inst_signal._data[self.picks_]+        else:+            if isinstance(inst, BaseEpochs) or isinstance(inst, np.ndarray):+                # data X is epoched+                # part of the following code is copied from mne csp+                n_epochs, n_channels, n_samples = inst.shape+                self.max_components = n_channels+                # reshape for filtering+                X_aux = np.reshape(inst, [n_epochs, n_channels*n_samples])+                inst_signal = filter_data(+                    X_aux, self.sampling_freq, **self.filt_params_signal)+                # rephase for filtering+                X_aux = np.reshape(inst, [n_epochs, n_channels*n_samples])+                inst_noise = filter_data(+                    X_aux, self.sampling_freq, **self.filt_params_noise)+                # subtract signal:+                inst_noise -= inst_signal+                # Estimate single trial covariance+                # reshape to original shape+                inst_signal = np.reshape(+                    inst_signal, [n_epochs, n_channels, n_samples])+                # reshape to original shape+                inst_noise = np.reshape(+                    inst_noise, [n_epochs, n_channels, n_samples])+        return inst_signal, inst_noise++    def fit(self, inst):+        """Fit"""+        if isinstance(inst, BaseRaw):+            if self.picks_ is None:+                raise ValueError('picks should be provided')+            self.max_components = len(self.picks_)+            inst_signal, inst_noise = self.filter_data(inst)+            cov_signal = compute_raw_covariance(+                inst_signal, picks=self.picks_,+                method=self.estimator, rank=self.rank)+            cov_noise = compute_raw_covariance(+                inst_noise, picks=self.picks_,+                method=self.estimator, rank=self.rank)             del inst_noise             del inst_signal         else:-            raise NotImplementedError()--        self.eigvals_, self.filters_ = eigh(cov_signal.data, cov_noise.data)+            if not isinstance(inst, np.ndarray):+                raise NotImplementedError()+            self._check_X(inst)++            # data X is epoched+            # part of the following code is copied from mne csp+            n_epochs, n_channels, n_samples = inst.shape+            self.max_components = n_channels+            X_s, X_n = self.filter_data(inst)+            covs = np.empty((n_epochs, n_channels, n_channels))+            for ii, epoch in enumerate(X_s):+                covs[ii] = _regularized_covariance(+                    epoch, reg=self.estimator,+                    method_params=self.cov_method_params, rank=self.rank)+            cov_signal = covs.mean(0)+            # Covariance matrix for the flanking frequencies (noise)+            # Estimate single trial covariance+            covs_n = np.empty((n_epochs, n_channels, n_channels))+            for ii, epoch in enumerate(X_n):+                covs_n[ii] = _regularized_covariance(+                    epoch, reg=self.estimator,+                    method_params=self.cov_method_params,+                    rank=self.rank)+            cov_noise = covs_n.mean(0)+        eigvals_, eigvects_ = eigh(cov_signal.data, cov_noise.data)+        # sort in descencing order+        ix = np.argsort(eigvals_)[::-1]+        self.eigvals_ = eigvals_[ix]+        self.filters_ = eigvects_[:, ix]         self.patterns_ = np.linalg.pinv(self.filters_)--    def transform(self, data):-        if self.n_components is None:-            n_components = len(self.picks_)+        return self++    def spectral_ratio_ssd(self, ssd_sources):+        """Spectral ratio measure for best n_components selection+        See Nikulin 2011, Eq. (24)+        Parameters+        ----------+        ssd_sources : data projected on the SSD space.+        output of transform+        """+        psd, freqs = psd_array_welch(+            ssd_sources, sfreq=self.sampling_freq, n_fft=self.n_fft)+        sig_idx = _time_mask(freqs, *self.freqs_signal)+        noise_idx = _time_mask(freqs, *self.freqs_noise)+        if psd.ndim == 3:+            mean_sig = psd[:, :, sig_idx].mean(axis=2).mean(axis=0)+            mean_noise = psd[:, :, noise_idx].mean(axis=2).mean(axis=0)+            spec_ratio = mean_sig / mean_noise+        else:+            mean_sig = psd[:, sig_idx].mean(axis=1)+            mean_noise = psd[:, noise_idx].mean(axis=1)+            spec_ratio = mean_sig / mean_noise+        sorter_spec = spec_ratio.argsort()[::-1]+        return spec_ratio, sorter_spec++    def transform(self, inst):+        """Estimate epochs sources given the SSD filters.++        Parameters+        ----------+        inst : instance of Raw or Epochs (n_epochs, n_channels, n_times)+            The data to be processed. The instance is modified inplace.+        Returns+        -------+        out : instance of Raw or Epochs+            The processed data.+        """+        if self.filters_ is None:+            raise RuntimeError('No filters available. Please first call fit')+        if self.return_filtered:+            inst, _ = self.filter_data(inst)+        if isinstance(inst, BaseRaw):+            data = inst.get_data()+            X_ssd = np.dot(self.filters_.T, data[self.picks_])         else:-            n_components = self.n_components-        return np.dot(self.filters_.T[:n_components], data[self.picks_])+            if not isinstance(inst, np.ndarray):+                raise NotImplementedError()+            self._check_X(inst)+            data = inst+            # project data on source space+            X_ssd = np.asarray(+                    [np.dot(self.filters_.T, epoch) for epoch in data])+        if self.sort_by_spectral_ratio:+            self.spec_ratio, self.sorter_spec = self.spectral_ratio_ssd(+                ssd_sources=X_ssd)+            self.filters_ = self.filters_[:, self.sorter_spec]+            self.patterns_ = self.patterns_[self.sorter_spec]++            if isinstance(inst, BaseRaw):+                X_ssd = X_ssd[self.sorter_spec]+            else:+                if not isinstance(inst, np.ndarray):+                    raise NotImplementedError()+                X_ssd = X_ssd[:, self.sorter_spec, :]+            if self.n_components is None:+                n_components = self.max_components+                return X_ssd+            else:+                n_components = self.n_components+                if isinstance(inst, BaseRaw):+                    X_ssd = X_ssd[:n_components]+                else:+                    if not isinstance(inst, np.ndarray):+                        raise NotImplementedError()+                    X_ssd = X_ssd[:, :n_components, :]+                return X_ssd++    def apply(self, inst):+        """

This doc string looks not standard, first line has a short title followed by a blank line. Have a look at a bunch of docstring from common MNE functions/classes.

vpeterson

comment created time in 2 days

PullRequestReviewEvent

Pull request review commentdengemann/mne-python

added option to handle epoched data

 import mne from mne import Epochs from mne.datasets.fieldtrip_cmc import data_path-from mne.utils import _time_mask from mne.channels import read_layout from mne.decoding import TransformerMixin, BaseEstimator +from mne.io.base import BaseRaw+from mne.epochs import BaseEpochs+from mne.utils import _time_mask+from mne.cov import (_regularized_covariance, compute_raw_covariance)+from mne.filter import filter_data+from mne.time_frequency import psd_array_welch+import locale+locale.setlocale(locale.LC_ALL, "en_US.UTF-8")+  def freq_mask(freqs, fmin, fmax):     """convenience function to select frequencies"""     return _time_mask(freqs, fmin, fmax) + # Define parameters fname = data_path() + '/SubjectCMC.ds' raw = mne.io.read_raw_ctf(fname) raw.crop(50., 250.).load_data()  # crop for memory purposes+picks = mne.pick_types(raw.info, meg=True, eeg=False, ref_meg=False)+sf = raw.info['sfreq']  freqs_sig = 9, 12 freqs_noise = 8, 13   class SSD(BaseEstimator, TransformerMixin):-    """Implement Spatio-Spectral Decomposision+    """+    This is a Python Implementation of Spatio Spectral Decomposition (SSD)+    method [1],[2] for both raw and epoched data. This source code is  based on+    the matlab implementation available at+    https://github.com/svendaehne/matlab_SPoC/tree/master/SSD and the+    PR MNE-based implementation of Denis A. Engemann <denis.engemann@gmail.com>++    SSD seeks at maximizing the power at a frequency band of interest while+    simultaneously minimizing it at the flanking (surrounding) frequency bins+    (considered noise). It extremizes the covariance matrices associated to+    signal and noise.++    Cosidering f as the freq. of interest, noise signals can be calculated+    either by filtering the signals in the frequency range [f−Δfb:f+Δfb]+    and then performing band-stop filtering around frequency f [f−Δfs:f+Δfs],+    where Δfb and Δfs generally are set equal to 2 and 1 Hz, or by filtering+    in the frequency range [f−Δf:f+Δf] with the following subtraction of+    the filtered signal around f [1].++    SSD can either be used as a dimentionality reduction method or a denoised+    ‘denoised’ low rank factorization method [2].      Parameters     ----------     filt_params_signal : dict         Filtering for the frequencies of interst.     filt_params_noise  : dict         Filtering for the frequencies of non-interest.-    estimator : str-        Which covariance estimator to use. Defaults to "oas".-    n_components  : int, None-        How many components to keep. Default to 5.-    subtract_signal : bool-        Whether to subtract the noise from the signal to enhcane-        sptial filter.-    sort_by_spectral_ratio : bool-        Whether to sort by the spectral ratio. Defaults to True.-+    sampling_freq : float+        sampling frequency (in Hz) of the recordings.+    estimator : float | str | None (default 'oas')+        Which covariance estimator to use+        If not None (same as 'empirical'), allow regularization for+        covariance estimation. If float, shrinkage is used+        (0 <= shrinkage <= 1). For str options, estimator will be passed to+        method to mne.compute_covariance().+    n_components : int| None (default None)+        The number of components to decompose the signals.+        If n_components is None no dimentionality reduction is made, and the+        transformed data is projected in the whole source space.+   picks: array| int | None  (default None)+       Indeces of good-channels. Can be the output of mne.pick_types++   sort_by_spectral_ratio: bool (default True)+       if set to True, the components are sorted according+       to the spectral ratio+       See [1] Nikulin 2011, Eq. (24)++   return_filtered : bool (default False)+        If return_filtered is True, data is bandpassed and projected onto+        the SSD components.++   n_fft: int (default None)+       if sort_by_spectral_ratio is set to True, then the sources will be+       sorted accordinly to their spectral ratio which is calculated based on+       "psd_array_welch" function. the n_fft set the length of FFT used.+       See mne.time_frequency.psd_array_welch for more information++   cov_method_params : TYPE, optional+        As in mne.decoding.SPoC+        The default is None.+   rank : None | dict | ‘info’ | ‘full’+        As in mne.decoding.SPoC+        This controls the rank computation that can be read from the+        measurement info or estimated from the data.+        See Notes of mne.compute_rank() for details.The default is None.+        The default is None.++    REFERENCES:+    [1] Nikulin, V. V., Nolte, G., & Curio, G. (2011). A novel method for+    reliable and fast extraction of neuronal EEG/MEG oscillations on the basis+    of spatio-spectral decomposition. NeuroImage, 55(4), 1528-1535.+    [2] Haufe, S., Dähne, S., & Nikulin, V. V. (2014). Dimensionality reduction+    for the analysis of brain oscillations. NeuroImage, 101, 583-597.     """ -    def __init__(self, filt_params_signal, filt_params_noise,-                 estimator='oas', n_components=None,-                 subtract_signal=True,-                 reject=None,-                 flat=None,-                 picks=None,-                 sort_by_spectral_ratio=True):+    def __init__(self, filt_params_signal, filt_params_noise, sampling_freq,+                 estimator='oas', n_components=None, picks=None,+                 sort_by_spectral_ratio=True, return_filtered=False,+                 n_fft=None, cov_method_params=None, rank=None):         """Initialize instance"""          dicts = {"signal": filt_params_signal, "noise": filt_params_noise}         for param, dd in [('l', 0), ('h', 0), ('l', 1), ('h', 1)]:             key = ('signal', 'noise')[dd]-            if  param + '_freq' not in dicts[key]:+            if param + '_freq' not in dicts[key]:                 raise ValueError(-                    "'%' must be defined in filter parameters for %s" % key)+                    "'%%' must be defined in filter parameters for %s" % key)             val = dicts[key][param + '_freq']             if not isinstance(val, (int, float)):                 raise ValueError(                     "Frequencies must be numbers, got %s" % type(val))+        # check freq bands+        if (filt_params_noise['l_freq'] > filt_params_signal['l_freq'] or+                filt_params_signal['h_freq'] > filt_params_noise['h_freq']):+            raise ValueError('Wrongly specified frequency bands!\n \+                The signal band-pass must be within the t noise band-pass!')          self.freqs_signal = (filt_params_signal['l_freq'],                              filt_params_signal['h_freq'])         self.freqs_noise = (filt_params_noise['l_freq'],                             filt_params_noise['h_freq'])         self.filt_params_signal = filt_params_signal         self.filt_params_noise = filt_params_noise-        self.subtract_signal = subtract_signal-        self.picks = picks+        self.sort_by_spectral_ratio = sort_by_spectral_ratio+        if n_fft is None:+            self.n_fft = int(sampling_freq)+        else:+            self.n_fft = int(n_fft)+        self.picks_ = picks+        self.return_filtered = return_filtered         self.estimator = estimator         self.n_components = n_components--    def fit(self, inst):-        """Fit"""-        if self.picks == None:-            self.picks_ = mne.pick_types(inst.info, meg=True, eeg=False, ref_meg=False)-        else:-            self.picks_ = self.picks-        if isinstance(inst, mne.io.base.BaseRaw):+        self.rank = rank+        self.sampling_freq = sampling_freq+        self.cov_method_params = cov_method_params++    def _check_X(self, inst):+        """Check input data."""+        if not isinstance(inst, np.ndarray):+            raise ValueError("X should be of type ndarray (got %s)."+                             % type(inst))+        if inst.ndim < 3:+            raise ValueError('X must have at least 3 dimensions.')++    def filter_data(self, inst):+        if isinstance(inst, BaseRaw):             inst_signal = inst.copy()             inst_signal.filter(picks=self.picks_, **self.filt_params_signal)-+            # noise             inst_noise = inst.copy()             inst_noise.filter(picks=self.picks_, **self.filt_params_noise)-            if self.subtract_signal:-                inst_noise._data[self.picks_] -= inst_signal._data[self.picks_]-            cov_signal = mne.compute_raw_covariance(-                inst_signal, picks=self.picks_, method=self.estimator)-            cov_noise = mne.compute_raw_covariance(inst_noise, picks=self.picks_,-                method=self.estimator)+            # subtract signal:+            inst_noise._data[self.picks_] -= inst_signal._data[self.picks_]+        else:+            if isinstance(inst, BaseEpochs) or isinstance(inst, np.ndarray):+                # data X is epoched+                # part of the following code is copied from mne csp+                n_epochs, n_channels, n_samples = inst.shape+                self.max_components = n_channels+                # reshape for filtering+                X_aux = np.reshape(inst, [n_epochs, n_channels*n_samples])+                inst_signal = filter_data(+                    X_aux, self.sampling_freq, **self.filt_params_signal)+                # rephase for filtering+                X_aux = np.reshape(inst, [n_epochs, n_channels*n_samples])+                inst_noise = filter_data(+                    X_aux, self.sampling_freq, **self.filt_params_noise)+                # subtract signal:+                inst_noise -= inst_signal+                # Estimate single trial covariance+                # reshape to original shape+                inst_signal = np.reshape(+                    inst_signal, [n_epochs, n_channels, n_samples])+                # reshape to original shape+                inst_noise = np.reshape(+                    inst_noise, [n_epochs, n_channels, n_samples])+        return inst_signal, inst_noise++    def fit(self, inst):+        """Fit"""+        if isinstance(inst, BaseRaw):+            if self.picks_ is None:+                raise ValueError('picks should be provided')+            self.max_components = len(self.picks_)+            inst_signal, inst_noise = self.filter_data(inst)+            cov_signal = compute_raw_covariance(+                inst_signal, picks=self.picks_,+                method=self.estimator, rank=self.rank)+            cov_noise = compute_raw_covariance(+                inst_noise, picks=self.picks_,+                method=self.estimator, rank=self.rank)             del inst_noise             del inst_signal         else:-            raise NotImplementedError()--        self.eigvals_, self.filters_ = eigh(cov_signal.data, cov_noise.data)+            if not isinstance(inst, np.ndarray):+                raise NotImplementedError()+            self._check_X(inst)++            # data X is epoched+            # part of the following code is copied from mne csp+            n_epochs, n_channels, n_samples = inst.shape+            self.max_components = n_channels+            X_s, X_n = self.filter_data(inst)+            covs = np.empty((n_epochs, n_channels, n_channels))+            for ii, epoch in enumerate(X_s):+                covs[ii] = _regularized_covariance(+                    epoch, reg=self.estimator,+                    method_params=self.cov_method_params, rank=self.rank)+            cov_signal = covs.mean(0)+            # Covariance matrix for the flanking frequencies (noise)+            # Estimate single trial covariance+            covs_n = np.empty((n_epochs, n_channels, n_channels))+            for ii, epoch in enumerate(X_n):+                covs_n[ii] = _regularized_covariance(+                    epoch, reg=self.estimator,+                    method_params=self.cov_method_params,+                    rank=self.rank)+            cov_noise = covs_n.mean(0)+        eigvals_, eigvects_ = eigh(cov_signal.data, cov_noise.data)+        # sort in descencing order+        ix = np.argsort(eigvals_)[::-1]+        self.eigvals_ = eigvals_[ix]+        self.filters_ = eigvects_[:, ix]         self.patterns_ = np.linalg.pinv(self.filters_)--    def transform(self, data):-        if self.n_components is None:-            n_components = len(self.picks_)+        return self++    def spectral_ratio_ssd(self, ssd_sources):+        """Spectral ratio measure for best n_components selection+        See Nikulin 2011, Eq. (24)+        Parameters+        ----------+        ssd_sources : data projected on the SSD space.+        output of transform

Indent this line

vpeterson

comment created time in 2 days

PullRequestReviewEvent

Pull request review commentdengemann/mne-python

added option to handle epoched data

 import mne from mne import Epochs from mne.datasets.fieldtrip_cmc import data_path-from mne.utils import _time_mask from mne.channels import read_layout from mne.decoding import TransformerMixin, BaseEstimator +from mne.io.base import BaseRaw+from mne.epochs import BaseEpochs+from mne.utils import _time_mask+from mne.cov import (_regularized_covariance, compute_raw_covariance)+from mne.filter import filter_data+from mne.time_frequency import psd_array_welch+import locale+locale.setlocale(locale.LC_ALL, "en_US.UTF-8")+  def freq_mask(freqs, fmin, fmax):     """convenience function to select frequencies"""     return _time_mask(freqs, fmin, fmax) + # Define parameters fname = data_path() + '/SubjectCMC.ds' raw = mne.io.read_raw_ctf(fname) raw.crop(50., 250.).load_data()  # crop for memory purposes+picks = mne.pick_types(raw.info, meg=True, eeg=False, ref_meg=False)+sf = raw.info['sfreq']  freqs_sig = 9, 12 freqs_noise = 8, 13   class SSD(BaseEstimator, TransformerMixin):-    """Implement Spatio-Spectral Decomposision+    """+    This is a Python Implementation of Spatio Spectral Decomposition (SSD)+    method [1],[2] for both raw and epoched data. This source code is  based on+    the matlab implementation available at+    https://github.com/svendaehne/matlab_SPoC/tree/master/SSD and the+    PR MNE-based implementation of Denis A. Engemann <denis.engemann@gmail.com>++    SSD seeks at maximizing the power at a frequency band of interest while+    simultaneously minimizing it at the flanking (surrounding) frequency bins+    (considered noise). It extremizes the covariance matrices associated to+    signal and noise.++    Cosidering f as the freq. of interest, noise signals can be calculated+    either by filtering the signals in the frequency range [f−Δfb:f+Δfb]+    and then performing band-stop filtering around frequency f [f−Δfs:f+Δfs],+    where Δfb and Δfs generally are set equal to 2 and 1 Hz, or by filtering+    in the frequency range [f−Δf:f+Δf] with the following subtraction of+    the filtered signal around f [1].++    SSD can either be used as a dimentionality reduction method or a denoised+    ‘denoised’ low rank factorization method [2].      Parameters     ----------     filt_params_signal : dict         Filtering for the frequencies of interst.     filt_params_noise  : dict         Filtering for the frequencies of non-interest.-    estimator : str-        Which covariance estimator to use. Defaults to "oas".-    n_components  : int, None-        How many components to keep. Default to 5.-    subtract_signal : bool-        Whether to subtract the noise from the signal to enhcane-        sptial filter.-    sort_by_spectral_ratio : bool-        Whether to sort by the spectral ratio. Defaults to True.-+    sampling_freq : float+        sampling frequency (in Hz) of the recordings.+    estimator : float | str | None (default 'oas')+        Which covariance estimator to use+        If not None (same as 'empirical'), allow regularization for+        covariance estimation. If float, shrinkage is used+        (0 <= shrinkage <= 1). For str options, estimator will be passed to+        method to mne.compute_covariance().+    n_components : int| None (default None)+        The number of components to decompose the signals.+        If n_components is None no dimentionality reduction is made, and the+        transformed data is projected in the whole source space.+   picks: array| int | None  (default None)+       Indeces of good-channels. Can be the output of mne.pick_types++   sort_by_spectral_ratio: bool (default True)+       if set to True, the components are sorted according+       to the spectral ratio+       See [1] Nikulin 2011, Eq. (24)++   return_filtered : bool (default False)+        If return_filtered is True, data is bandpassed and projected onto+        the SSD components.++   n_fft: int (default None)+       if sort_by_spectral_ratio is set to True, then the sources will be+       sorted accordinly to their spectral ratio which is calculated based on+       "psd_array_welch" function. the n_fft set the length of FFT used.+       See mne.time_frequency.psd_array_welch for more information++   cov_method_params : TYPE, optional+        As in mne.decoding.SPoC+        The default is None.+   rank : None | dict | ‘info’ | ‘full’+        As in mne.decoding.SPoC+        This controls the rank computation that can be read from the+        measurement info or estimated from the data.+        See Notes of mne.compute_rank() for details.The default is None.+        The default is None.++    REFERENCES:+    [1] Nikulin, V. V., Nolte, G., & Curio, G. (2011). A novel method for+    reliable and fast extraction of neuronal EEG/MEG oscillations on the basis+    of spatio-spectral decomposition. NeuroImage, 55(4), 1528-1535.+    [2] Haufe, S., Dähne, S., & Nikulin, V. V. (2014). Dimensionality reduction+    for the analysis of brain oscillations. NeuroImage, 101, 583-597.     """ -    def __init__(self, filt_params_signal, filt_params_noise,-                 estimator='oas', n_components=None,-                 subtract_signal=True,-                 reject=None,-                 flat=None,-                 picks=None,-                 sort_by_spectral_ratio=True):+    def __init__(self, filt_params_signal, filt_params_noise, sampling_freq,+                 estimator='oas', n_components=None, picks=None,+                 sort_by_spectral_ratio=True, return_filtered=False,+                 n_fft=None, cov_method_params=None, rank=None):         """Initialize instance"""          dicts = {"signal": filt_params_signal, "noise": filt_params_noise}         for param, dd in [('l', 0), ('h', 0), ('l', 1), ('h', 1)]:             key = ('signal', 'noise')[dd]-            if  param + '_freq' not in dicts[key]:+            if param + '_freq' not in dicts[key]:                 raise ValueError(-                    "'%' must be defined in filter parameters for %s" % key)+                    "'%%' must be defined in filter parameters for %s" % key)             val = dicts[key][param + '_freq']             if not isinstance(val, (int, float)):                 raise ValueError(                     "Frequencies must be numbers, got %s" % type(val))+        # check freq bands+        if (filt_params_noise['l_freq'] > filt_params_signal['l_freq'] or+                filt_params_signal['h_freq'] > filt_params_noise['h_freq']):+            raise ValueError('Wrongly specified frequency bands!\n \+                The signal band-pass must be within the t noise band-pass!')          self.freqs_signal = (filt_params_signal['l_freq'],                              filt_params_signal['h_freq'])         self.freqs_noise = (filt_params_noise['l_freq'],                             filt_params_noise['h_freq'])         self.filt_params_signal = filt_params_signal         self.filt_params_noise = filt_params_noise-        self.subtract_signal = subtract_signal-        self.picks = picks+        self.sort_by_spectral_ratio = sort_by_spectral_ratio+        if n_fft is None:+            self.n_fft = int(sampling_freq)+        else:+            self.n_fft = int(n_fft)+        self.picks_ = picks+        self.return_filtered = return_filtered         self.estimator = estimator         self.n_components = n_components--    def fit(self, inst):-        """Fit"""-        if self.picks == None:-            self.picks_ = mne.pick_types(inst.info, meg=True, eeg=False, ref_meg=False)-        else:-            self.picks_ = self.picks-        if isinstance(inst, mne.io.base.BaseRaw):+        self.rank = rank+        self.sampling_freq = sampling_freq+        self.cov_method_params = cov_method_params++    def _check_X(self, inst):+        """Check input data."""+        if not isinstance(inst, np.ndarray):+            raise ValueError("X should be of type ndarray (got %s)."+                             % type(inst))+        if inst.ndim < 3:+            raise ValueError('X must have at least 3 dimensions.')++    def filter_data(self, inst):+        if isinstance(inst, BaseRaw):             inst_signal = inst.copy()             inst_signal.filter(picks=self.picks_, **self.filt_params_signal)-+            # noise             inst_noise = inst.copy()             inst_noise.filter(picks=self.picks_, **self.filt_params_noise)-            if self.subtract_signal:-                inst_noise._data[self.picks_] -= inst_signal._data[self.picks_]-            cov_signal = mne.compute_raw_covariance(-                inst_signal, picks=self.picks_, method=self.estimator)-            cov_noise = mne.compute_raw_covariance(inst_noise, picks=self.picks_,-                method=self.estimator)+            # subtract signal:+            inst_noise._data[self.picks_] -= inst_signal._data[self.picks_]+        else:+            if isinstance(inst, BaseEpochs) or isinstance(inst, np.ndarray):+                # data X is epoched+                # part of the following code is copied from mne csp+                n_epochs, n_channels, n_samples = inst.shape+                self.max_components = n_channels+                # reshape for filtering+                X_aux = np.reshape(inst, [n_epochs, n_channels*n_samples])+                inst_signal = filter_data(+                    X_aux, self.sampling_freq, **self.filt_params_signal)+                # rephase for filtering+                X_aux = np.reshape(inst, [n_epochs, n_channels*n_samples])+                inst_noise = filter_data(+                    X_aux, self.sampling_freq, **self.filt_params_noise)+                # subtract signal:+                inst_noise -= inst_signal+                # Estimate single trial covariance+                # reshape to original shape+                inst_signal = np.reshape(+                    inst_signal, [n_epochs, n_channels, n_samples])+                # reshape to original shape+                inst_noise = np.reshape(+                    inst_noise, [n_epochs, n_channels, n_samples])+        return inst_signal, inst_noise++    def fit(self, inst):+        """Fit"""+        if isinstance(inst, BaseRaw):+            if self.picks_ is None:+                raise ValueError('picks should be provided')+            self.max_components = len(self.picks_)+            inst_signal, inst_noise = self.filter_data(inst)+            cov_signal = compute_raw_covariance(+                inst_signal, picks=self.picks_,+                method=self.estimator, rank=self.rank)+            cov_noise = compute_raw_covariance(+                inst_noise, picks=self.picks_,+                method=self.estimator, rank=self.rank)             del inst_noise             del inst_signal         else:-            raise NotImplementedError()--        self.eigvals_, self.filters_ = eigh(cov_signal.data, cov_noise.data)+            if not isinstance(inst, np.ndarray):+                raise NotImplementedError()+            self._check_X(inst)++            # data X is epoched+            # part of the following code is copied from mne csp+            n_epochs, n_channels, n_samples = inst.shape+            self.max_components = n_channels+            X_s, X_n = self.filter_data(inst)+            covs = np.empty((n_epochs, n_channels, n_channels))+            for ii, epoch in enumerate(X_s):+                covs[ii] = _regularized_covariance(+                    epoch, reg=self.estimator,+                    method_params=self.cov_method_params, rank=self.rank)+            cov_signal = covs.mean(0)+            # Covariance matrix for the flanking frequencies (noise)+            # Estimate single trial covariance+            covs_n = np.empty((n_epochs, n_channels, n_channels))+            for ii, epoch in enumerate(X_n):+                covs_n[ii] = _regularized_covariance(+                    epoch, reg=self.estimator,+                    method_params=self.cov_method_params,+                    rank=self.rank)+            cov_noise = covs_n.mean(0)+        eigvals_, eigvects_ = eigh(cov_signal.data, cov_noise.data)+        # sort in descencing order+        ix = np.argsort(eigvals_)[::-1]+        self.eigvals_ = eigvals_[ix]+        self.filters_ = eigvects_[:, ix]         self.patterns_ = np.linalg.pinv(self.filters_)--    def transform(self, data):-        if self.n_components is None:-            n_components = len(self.picks_)+        return self++    def spectral_ratio_ssd(self, ssd_sources):+        """Spectral ratio measure for best n_components selection+        See Nikulin 2011, Eq. (24)

Add blank line below

vpeterson

comment created time in 2 days

PullRequestReviewEvent

Pull request review commentdengemann/mne-python

added option to handle epoched data

 import mne from mne import Epochs from mne.datasets.fieldtrip_cmc import data_path-from mne.utils import _time_mask from mne.channels import read_layout from mne.decoding import TransformerMixin, BaseEstimator +from mne.io.base import BaseRaw+from mne.epochs import BaseEpochs+from mne.utils import _time_mask+from mne.cov import (_regularized_covariance, compute_raw_covariance)+from mne.filter import filter_data+from mne.time_frequency import psd_array_welch+import locale+locale.setlocale(locale.LC_ALL, "en_US.UTF-8")+  def freq_mask(freqs, fmin, fmax):     """convenience function to select frequencies"""     return _time_mask(freqs, fmin, fmax) + # Define parameters fname = data_path() + '/SubjectCMC.ds' raw = mne.io.read_raw_ctf(fname) raw.crop(50., 250.).load_data()  # crop for memory purposes+picks = mne.pick_types(raw.info, meg=True, eeg=False, ref_meg=False)+sf = raw.info['sfreq']  freqs_sig = 9, 12 freqs_noise = 8, 13   class SSD(BaseEstimator, TransformerMixin):-    """Implement Spatio-Spectral Decomposision+    """+    This is a Python Implementation of Spatio Spectral Decomposition (SSD)+    method [1],[2] for both raw and epoched data. This source code is  based on+    the matlab implementation available at+    https://github.com/svendaehne/matlab_SPoC/tree/master/SSD and the+    PR MNE-based implementation of Denis A. Engemann <denis.engemann@gmail.com>++    SSD seeks at maximizing the power at a frequency band of interest while+    simultaneously minimizing it at the flanking (surrounding) frequency bins+    (considered noise). It extremizes the covariance matrices associated to+    signal and noise.++    Cosidering f as the freq. of interest, noise signals can be calculated+    either by filtering the signals in the frequency range [f−Δfb:f+Δfb]+    and then performing band-stop filtering around frequency f [f−Δfs:f+Δfs],+    where Δfb and Δfs generally are set equal to 2 and 1 Hz, or by filtering+    in the frequency range [f−Δf:f+Δf] with the following subtraction of+    the filtered signal around f [1].++    SSD can either be used as a dimentionality reduction method or a denoised+    ‘denoised’ low rank factorization method [2].      Parameters     ----------     filt_params_signal : dict         Filtering for the frequencies of interst.     filt_params_noise  : dict         Filtering for the frequencies of non-interest.-    estimator : str-        Which covariance estimator to use. Defaults to "oas".-    n_components  : int, None-        How many components to keep. Default to 5.-    subtract_signal : bool-        Whether to subtract the noise from the signal to enhcane-        sptial filter.-    sort_by_spectral_ratio : bool-        Whether to sort by the spectral ratio. Defaults to True.-+    sampling_freq : float+        sampling frequency (in Hz) of the recordings.+    estimator : float | str | None (default 'oas')+        Which covariance estimator to use+        If not None (same as 'empirical'), allow regularization for+        covariance estimation. If float, shrinkage is used+        (0 <= shrinkage <= 1). For str options, estimator will be passed to+        method to mne.compute_covariance().+    n_components : int| None (default None)+        The number of components to decompose the signals.+        If n_components is None no dimentionality reduction is made, and the+        transformed data is projected in the whole source space.+   picks: array| int | None  (default None)+       Indeces of good-channels. Can be the output of mne.pick_types++   sort_by_spectral_ratio: bool (default True)+       if set to True, the components are sorted according+       to the spectral ratio+       See [1] Nikulin 2011, Eq. (24)++   return_filtered : bool (default False)+        If return_filtered is True, data is bandpassed and projected onto+        the SSD components.++   n_fft: int (default None)+       if sort_by_spectral_ratio is set to True, then the sources will be+       sorted accordinly to their spectral ratio which is calculated based on+       "psd_array_welch" function. the n_fft set the length of FFT used.+       See mne.time_frequency.psd_array_welch for more information++   cov_method_params : TYPE, optional+        As in mne.decoding.SPoC+        The default is None.+   rank : None | dict | ‘info’ | ‘full’+        As in mne.decoding.SPoC+        This controls the rank computation that can be read from the+        measurement info or estimated from the data.+        See Notes of mne.compute_rank() for details.The default is None.+        The default is None.++    REFERENCES:+    [1] Nikulin, V. V., Nolte, G., & Curio, G. (2011). A novel method for+    reliable and fast extraction of neuronal EEG/MEG oscillations on the basis+    of spatio-spectral decomposition. NeuroImage, 55(4), 1528-1535.+    [2] Haufe, S., Dähne, S., & Nikulin, V. V. (2014). Dimensionality reduction+    for the analysis of brain oscillations. NeuroImage, 101, 583-597.     """ -    def __init__(self, filt_params_signal, filt_params_noise,-                 estimator='oas', n_components=None,-                 subtract_signal=True,-                 reject=None,-                 flat=None,-                 picks=None,-                 sort_by_spectral_ratio=True):+    def __init__(self, filt_params_signal, filt_params_noise, sampling_freq,+                 estimator='oas', n_components=None, picks=None,+                 sort_by_spectral_ratio=True, return_filtered=False,+                 n_fft=None, cov_method_params=None, rank=None):         """Initialize instance"""          dicts = {"signal": filt_params_signal, "noise": filt_params_noise}         for param, dd in [('l', 0), ('h', 0), ('l', 1), ('h', 1)]:             key = ('signal', 'noise')[dd]-            if  param + '_freq' not in dicts[key]:+            if param + '_freq' not in dicts[key]:                 raise ValueError(-                    "'%' must be defined in filter parameters for %s" % key)+                    "'%%' must be defined in filter parameters for %s" % key)             val = dicts[key][param + '_freq']             if not isinstance(val, (int, float)):                 raise ValueError(                     "Frequencies must be numbers, got %s" % type(val))+        # check freq bands+        if (filt_params_noise['l_freq'] > filt_params_signal['l_freq'] or+                filt_params_signal['h_freq'] > filt_params_noise['h_freq']):+            raise ValueError('Wrongly specified frequency bands!\n \+                The signal band-pass must be within the t noise band-pass!')          self.freqs_signal = (filt_params_signal['l_freq'],                              filt_params_signal['h_freq'])         self.freqs_noise = (filt_params_noise['l_freq'],                             filt_params_noise['h_freq'])         self.filt_params_signal = filt_params_signal         self.filt_params_noise = filt_params_noise-        self.subtract_signal = subtract_signal-        self.picks = picks+        self.sort_by_spectral_ratio = sort_by_spectral_ratio+        if n_fft is None:+            self.n_fft = int(sampling_freq)+        else:+            self.n_fft = int(n_fft)+        self.picks_ = picks+        self.return_filtered = return_filtered         self.estimator = estimator         self.n_components = n_components--    def fit(self, inst):-        """Fit"""-        if self.picks == None:-            self.picks_ = mne.pick_types(inst.info, meg=True, eeg=False, ref_meg=False)-        else:-            self.picks_ = self.picks-        if isinstance(inst, mne.io.base.BaseRaw):+        self.rank = rank+        self.sampling_freq = sampling_freq+        self.cov_method_params = cov_method_params++    def _check_X(self, inst):+        """Check input data."""+        if not isinstance(inst, np.ndarray):+            raise ValueError("X should be of type ndarray (got %s)."+                             % type(inst))+        if inst.ndim < 3:+            raise ValueError('X must have at least 3 dimensions.')++    def filter_data(self, inst):+        if isinstance(inst, BaseRaw):             inst_signal = inst.copy()             inst_signal.filter(picks=self.picks_, **self.filt_params_signal)-+            # noise             inst_noise = inst.copy()             inst_noise.filter(picks=self.picks_, **self.filt_params_noise)-            if self.subtract_signal:-                inst_noise._data[self.picks_] -= inst_signal._data[self.picks_]-            cov_signal = mne.compute_raw_covariance(-                inst_signal, picks=self.picks_, method=self.estimator)-            cov_noise = mne.compute_raw_covariance(inst_noise, picks=self.picks_,-                method=self.estimator)+            # subtract signal:+            inst_noise._data[self.picks_] -= inst_signal._data[self.picks_]+        else:+            if isinstance(inst, BaseEpochs) or isinstance(inst, np.ndarray):+                # data X is epoched+                # part of the following code is copied from mne csp+                n_epochs, n_channels, n_samples = inst.shape+                self.max_components = n_channels+                # reshape for filtering+                X_aux = np.reshape(inst, [n_epochs, n_channels*n_samples])+                inst_signal = filter_data(+                    X_aux, self.sampling_freq, **self.filt_params_signal)+                # rephase for filtering+                X_aux = np.reshape(inst, [n_epochs, n_channels*n_samples])+                inst_noise = filter_data(+                    X_aux, self.sampling_freq, **self.filt_params_noise)+                # subtract signal:+                inst_noise -= inst_signal+                # Estimate single trial covariance+                # reshape to original shape+                inst_signal = np.reshape(+                    inst_signal, [n_epochs, n_channels, n_samples])+                # reshape to original shape+                inst_noise = np.reshape(+                    inst_noise, [n_epochs, n_channels, n_samples])+        return inst_signal, inst_noise++    def fit(self, inst):+        """Fit"""+        if isinstance(inst, BaseRaw):+            if self.picks_ is None:+                raise ValueError('picks should be provided')+            self.max_components = len(self.picks_)+            inst_signal, inst_noise = self.filter_data(inst)+            cov_signal = compute_raw_covariance(+                inst_signal, picks=self.picks_,+                method=self.estimator, rank=self.rank)

I think this goes in 2 lines, not three, in principle. Also below 227-229

vpeterson

comment created time in 2 days

PullRequestReviewEvent

Pull request review commentdengemann/mne-python

added option to handle epoched data

 import mne from mne import Epochs from mne.datasets.fieldtrip_cmc import data_path-from mne.utils import _time_mask from mne.channels import read_layout from mne.decoding import TransformerMixin, BaseEstimator +from mne.io.base import BaseRaw+from mne.epochs import BaseEpochs+from mne.utils import _time_mask+from mne.cov import (_regularized_covariance, compute_raw_covariance)+from mne.filter import filter_data+from mne.time_frequency import psd_array_welch+import locale+locale.setlocale(locale.LC_ALL, "en_US.UTF-8")+  def freq_mask(freqs, fmin, fmax):     """convenience function to select frequencies"""     return _time_mask(freqs, fmin, fmax) + # Define parameters fname = data_path() + '/SubjectCMC.ds' raw = mne.io.read_raw_ctf(fname) raw.crop(50., 250.).load_data()  # crop for memory purposes+picks = mne.pick_types(raw.info, meg=True, eeg=False, ref_meg=False)+sf = raw.info['sfreq']  freqs_sig = 9, 12 freqs_noise = 8, 13   class SSD(BaseEstimator, TransformerMixin):-    """Implement Spatio-Spectral Decomposision+    """+    This is a Python Implementation of Spatio Spectral Decomposition (SSD)+    method [1],[2] for both raw and epoched data. This source code is  based on+    the matlab implementation available at+    https://github.com/svendaehne/matlab_SPoC/tree/master/SSD and the+    PR MNE-based implementation of Denis A. Engemann <denis.engemann@gmail.com>++    SSD seeks at maximizing the power at a frequency band of interest while+    simultaneously minimizing it at the flanking (surrounding) frequency bins+    (considered noise). It extremizes the covariance matrices associated to+    signal and noise.++    Cosidering f as the freq. of interest, noise signals can be calculated+    either by filtering the signals in the frequency range [f−Δfb:f+Δfb]+    and then performing band-stop filtering around frequency f [f−Δfs:f+Δfs],+    where Δfb and Δfs generally are set equal to 2 and 1 Hz, or by filtering+    in the frequency range [f−Δf:f+Δf] with the following subtraction of+    the filtered signal around f [1].++    SSD can either be used as a dimentionality reduction method or a denoised+    ‘denoised’ low rank factorization method [2].      Parameters     ----------     filt_params_signal : dict         Filtering for the frequencies of interst.     filt_params_noise  : dict         Filtering for the frequencies of non-interest.-    estimator : str-        Which covariance estimator to use. Defaults to "oas".-    n_components  : int, None-        How many components to keep. Default to 5.-    subtract_signal : bool-        Whether to subtract the noise from the signal to enhcane-        sptial filter.-    sort_by_spectral_ratio : bool-        Whether to sort by the spectral ratio. Defaults to True.-+    sampling_freq : float+        sampling frequency (in Hz) of the recordings.+    estimator : float | str | None (default 'oas')+        Which covariance estimator to use+        If not None (same as 'empirical'), allow regularization for+        covariance estimation. If float, shrinkage is used+        (0 <= shrinkage <= 1). For str options, estimator will be passed to+        method to mne.compute_covariance().+    n_components : int| None (default None)+        The number of components to decompose the signals.+        If n_components is None no dimentionality reduction is made, and the+        transformed data is projected in the whole source space.+   picks: array| int | None  (default None)+       Indeces of good-channels. Can be the output of mne.pick_types++   sort_by_spectral_ratio: bool (default True)+       if set to True, the components are sorted according+       to the spectral ratio+       See [1] Nikulin 2011, Eq. (24)++   return_filtered : bool (default False)+        If return_filtered is True, data is bandpassed and projected onto+        the SSD components.++   n_fft: int (default None)+       if sort_by_spectral_ratio is set to True, then the sources will be+       sorted accordinly to their spectral ratio which is calculated based on+       "psd_array_welch" function. the n_fft set the length of FFT used.+       See mne.time_frequency.psd_array_welch for more information++   cov_method_params : TYPE, optional+        As in mne.decoding.SPoC+        The default is None.+   rank : None | dict | ‘info’ | ‘full’+        As in mne.decoding.SPoC+        This controls the rank computation that can be read from the+        measurement info or estimated from the data.+        See Notes of mne.compute_rank() for details.The default is None.+        The default is None.++    REFERENCES:+    [1] Nikulin, V. V., Nolte, G., & Curio, G. (2011). A novel method for+    reliable and fast extraction of neuronal EEG/MEG oscillations on the basis+    of spatio-spectral decomposition. NeuroImage, 55(4), 1528-1535.+    [2] Haufe, S., Dähne, S., & Nikulin, V. V. (2014). Dimensionality reduction+    for the analysis of brain oscillations. NeuroImage, 101, 583-597.     """ -    def __init__(self, filt_params_signal, filt_params_noise,-                 estimator='oas', n_components=None,-                 subtract_signal=True,-                 reject=None,-                 flat=None,-                 picks=None,-                 sort_by_spectral_ratio=True):+    def __init__(self, filt_params_signal, filt_params_noise, sampling_freq,+                 estimator='oas', n_components=None, picks=None,+                 sort_by_spectral_ratio=True, return_filtered=False,+                 n_fft=None, cov_method_params=None, rank=None):         """Initialize instance"""          dicts = {"signal": filt_params_signal, "noise": filt_params_noise}         for param, dd in [('l', 0), ('h', 0), ('l', 1), ('h', 1)]:             key = ('signal', 'noise')[dd]-            if  param + '_freq' not in dicts[key]:+            if param + '_freq' not in dicts[key]:                 raise ValueError(-                    "'%' must be defined in filter parameters for %s" % key)+                    "'%%' must be defined in filter parameters for %s" % key)             val = dicts[key][param + '_freq']             if not isinstance(val, (int, float)):                 raise ValueError(                     "Frequencies must be numbers, got %s" % type(val))+        # check freq bands+        if (filt_params_noise['l_freq'] > filt_params_signal['l_freq'] or+                filt_params_signal['h_freq'] > filt_params_noise['h_freq']):+            raise ValueError('Wrongly specified frequency bands!\n \+                The signal band-pass must be within the t noise band-pass!')          self.freqs_signal = (filt_params_signal['l_freq'],                              filt_params_signal['h_freq'])         self.freqs_noise = (filt_params_noise['l_freq'],                             filt_params_noise['h_freq'])         self.filt_params_signal = filt_params_signal         self.filt_params_noise = filt_params_noise-        self.subtract_signal = subtract_signal-        self.picks = picks+        self.sort_by_spectral_ratio = sort_by_spectral_ratio+        if n_fft is None:+            self.n_fft = int(sampling_freq)+        else:+            self.n_fft = int(n_fft)+        self.picks_ = picks+        self.return_filtered = return_filtered         self.estimator = estimator         self.n_components = n_components--    def fit(self, inst):-        """Fit"""-        if self.picks == None:-            self.picks_ = mne.pick_types(inst.info, meg=True, eeg=False, ref_meg=False)-        else:-            self.picks_ = self.picks-        if isinstance(inst, mne.io.base.BaseRaw):+        self.rank = rank+        self.sampling_freq = sampling_freq+        self.cov_method_params = cov_method_params++    def _check_X(self, inst):+        """Check input data."""+        if not isinstance(inst, np.ndarray):+            raise ValueError("X should be of type ndarray (got %s)."+                             % type(inst))+        if inst.ndim < 3:+            raise ValueError('X must have at least 3 dimensions.')++    def filter_data(self, inst):+        if isinstance(inst, BaseRaw):             inst_signal = inst.copy()             inst_signal.filter(picks=self.picks_, **self.filt_params_signal)-+            # noise             inst_noise = inst.copy()             inst_noise.filter(picks=self.picks_, **self.filt_params_noise)-            if self.subtract_signal:-                inst_noise._data[self.picks_] -= inst_signal._data[self.picks_]-            cov_signal = mne.compute_raw_covariance(-                inst_signal, picks=self.picks_, method=self.estimator)-            cov_noise = mne.compute_raw_covariance(inst_noise, picks=self.picks_,-                method=self.estimator)+            # subtract signal:+            inst_noise._data[self.picks_] -= inst_signal._data[self.picks_]+        else:+            if isinstance(inst, BaseEpochs) or isinstance(inst, np.ndarray):+                # data X is epoched+                # part of the following code is copied from mne csp+                n_epochs, n_channels, n_samples = inst.shape+                self.max_components = n_channels+                # reshape for filtering+                X_aux = np.reshape(inst, [n_epochs, n_channels*n_samples])+                inst_signal = filter_data(+                    X_aux, self.sampling_freq, **self.filt_params_signal)+                # rephase for filtering+                X_aux = np.reshape(inst, [n_epochs, n_channels*n_samples])+                inst_noise = filter_data(+                    X_aux, self.sampling_freq, **self.filt_params_noise)+                # subtract signal:+                inst_noise -= inst_signal+                # Estimate single trial covariance+                # reshape to original shape+                inst_signal = np.reshape(+                    inst_signal, [n_epochs, n_channels, n_samples])+                # reshape to original shape+                inst_noise = np.reshape(+                    inst_noise, [n_epochs, n_channels, n_samples])+        return inst_signal, inst_noise++    def fit(self, inst):+        """Fit"""

This needs a docstring similar to the other classes in the decoding module. We can look into it later though.

vpeterson

comment created time in 2 days

PullRequestReviewEvent

Pull request review commentdengemann/mne-python

added option to handle epoched data

 import mne from mne import Epochs from mne.datasets.fieldtrip_cmc import data_path-from mne.utils import _time_mask from mne.channels import read_layout from mne.decoding import TransformerMixin, BaseEstimator +from mne.io.base import BaseRaw+from mne.epochs import BaseEpochs+from mne.utils import _time_mask+from mne.cov import (_regularized_covariance, compute_raw_covariance)+from mne.filter import filter_data+from mne.time_frequency import psd_array_welch+import locale+locale.setlocale(locale.LC_ALL, "en_US.UTF-8")+  def freq_mask(freqs, fmin, fmax):     """convenience function to select frequencies"""     return _time_mask(freqs, fmin, fmax) + # Define parameters fname = data_path() + '/SubjectCMC.ds' raw = mne.io.read_raw_ctf(fname) raw.crop(50., 250.).load_data()  # crop for memory purposes+picks = mne.pick_types(raw.info, meg=True, eeg=False, ref_meg=False)+sf = raw.info['sfreq']  freqs_sig = 9, 12 freqs_noise = 8, 13   class SSD(BaseEstimator, TransformerMixin):-    """Implement Spatio-Spectral Decomposision+    """+    This is a Python Implementation of Spatio Spectral Decomposition (SSD)+    method [1],[2] for both raw and epoched data. This source code is  based on+    the matlab implementation available at+    https://github.com/svendaehne/matlab_SPoC/tree/master/SSD and the+    PR MNE-based implementation of Denis A. Engemann <denis.engemann@gmail.com>++    SSD seeks at maximizing the power at a frequency band of interest while+    simultaneously minimizing it at the flanking (surrounding) frequency bins+    (considered noise). It extremizes the covariance matrices associated to+    signal and noise.++    Cosidering f as the freq. of interest, noise signals can be calculated+    either by filtering the signals in the frequency range [f−Δfb:f+Δfb]+    and then performing band-stop filtering around frequency f [f−Δfs:f+Δfs],+    where Δfb and Δfs generally are set equal to 2 and 1 Hz, or by filtering+    in the frequency range [f−Δf:f+Δf] with the following subtraction of+    the filtered signal around f [1].++    SSD can either be used as a dimentionality reduction method or a denoised+    ‘denoised’ low rank factorization method [2].      Parameters     ----------     filt_params_signal : dict         Filtering for the frequencies of interst.     filt_params_noise  : dict         Filtering for the frequencies of non-interest.-    estimator : str-        Which covariance estimator to use. Defaults to "oas".-    n_components  : int, None-        How many components to keep. Default to 5.-    subtract_signal : bool-        Whether to subtract the noise from the signal to enhcane-        sptial filter.-    sort_by_spectral_ratio : bool-        Whether to sort by the spectral ratio. Defaults to True.-+    sampling_freq : float+        sampling frequency (in Hz) of the recordings.+    estimator : float | str | None (default 'oas')+        Which covariance estimator to use+        If not None (same as 'empirical'), allow regularization for+        covariance estimation. If float, shrinkage is used+        (0 <= shrinkage <= 1). For str options, estimator will be passed to+        method to mne.compute_covariance().+    n_components : int| None (default None)+        The number of components to decompose the signals.+        If n_components is None no dimentionality reduction is made, and the+        transformed data is projected in the whole source space.+   picks: array| int | None  (default None)+       Indeces of good-channels. Can be the output of mne.pick_types++   sort_by_spectral_ratio: bool (default True)+       if set to True, the components are sorted according+       to the spectral ratio+       See [1] Nikulin 2011, Eq. (24)++   return_filtered : bool (default False)+        If return_filtered is True, data is bandpassed and projected onto+        the SSD components.++   n_fft: int (default None)+       if sort_by_spectral_ratio is set to True, then the sources will be+       sorted accordinly to their spectral ratio which is calculated based on+       "psd_array_welch" function. the n_fft set the length of FFT used.+       See mne.time_frequency.psd_array_welch for more information++   cov_method_params : TYPE, optional+        As in mne.decoding.SPoC+        The default is None.+   rank : None | dict | ‘info’ | ‘full’+        As in mne.decoding.SPoC+        This controls the rank computation that can be read from the+        measurement info or estimated from the data.+        See Notes of mne.compute_rank() for details.The default is None.+        The default is None.++    REFERENCES:+    [1] Nikulin, V. V., Nolte, G., & Curio, G. (2011). A novel method for+    reliable and fast extraction of neuronal EEG/MEG oscillations on the basis+    of spatio-spectral decomposition. NeuroImage, 55(4), 1528-1535.+    [2] Haufe, S., Dähne, S., & Nikulin, V. V. (2014). Dimensionality reduction+    for the analysis of brain oscillations. NeuroImage, 101, 583-597.     """ -    def __init__(self, filt_params_signal, filt_params_noise,-                 estimator='oas', n_components=None,-                 subtract_signal=True,-                 reject=None,-                 flat=None,-                 picks=None,-                 sort_by_spectral_ratio=True):+    def __init__(self, filt_params_signal, filt_params_noise, sampling_freq,+                 estimator='oas', n_components=None, picks=None,+                 sort_by_spectral_ratio=True, return_filtered=False,+                 n_fft=None, cov_method_params=None, rank=None):         """Initialize instance"""          dicts = {"signal": filt_params_signal, "noise": filt_params_noise}         for param, dd in [('l', 0), ('h', 0), ('l', 1), ('h', 1)]:             key = ('signal', 'noise')[dd]-            if  param + '_freq' not in dicts[key]:+            if param + '_freq' not in dicts[key]:                 raise ValueError(-                    "'%' must be defined in filter parameters for %s" % key)+                    "'%%' must be defined in filter parameters for %s" % key)             val = dicts[key][param + '_freq']             if not isinstance(val, (int, float)):                 raise ValueError(                     "Frequencies must be numbers, got %s" % type(val))+        # check freq bands+        if (filt_params_noise['l_freq'] > filt_params_signal['l_freq'] or+                filt_params_signal['h_freq'] > filt_params_noise['h_freq']):+            raise ValueError('Wrongly specified frequency bands!\n \+                The signal band-pass must be within the t noise band-pass!')          self.freqs_signal = (filt_params_signal['l_freq'],                              filt_params_signal['h_freq'])         self.freqs_noise = (filt_params_noise['l_freq'],                             filt_params_noise['h_freq'])         self.filt_params_signal = filt_params_signal         self.filt_params_noise = filt_params_noise-        self.subtract_signal = subtract_signal-        self.picks = picks+        self.sort_by_spectral_ratio = sort_by_spectral_ratio+        if n_fft is None:+            self.n_fft = int(sampling_freq)+        else:+            self.n_fft = int(n_fft)+        self.picks_ = picks+        self.return_filtered = return_filtered         self.estimator = estimator         self.n_components = n_components--    def fit(self, inst):-        """Fit"""-        if self.picks == None:-            self.picks_ = mne.pick_types(inst.info, meg=True, eeg=False, ref_meg=False)-        else:-            self.picks_ = self.picks-        if isinstance(inst, mne.io.base.BaseRaw):+        self.rank = rank+        self.sampling_freq = sampling_freq+        self.cov_method_params = cov_method_params++    def _check_X(self, inst):+        """Check input data."""+        if not isinstance(inst, np.ndarray):+            raise ValueError("X should be of type ndarray (got %s)."+                             % type(inst))+        if inst.ndim < 3:+            raise ValueError('X must have at least 3 dimensions.')++    def filter_data(self, inst):+        if isinstance(inst, BaseRaw):             inst_signal = inst.copy()             inst_signal.filter(picks=self.picks_, **self.filt_params_signal)-+            # noise             inst_noise = inst.copy()             inst_noise.filter(picks=self.picks_, **self.filt_params_noise)-            if self.subtract_signal:-                inst_noise._data[self.picks_] -= inst_signal._data[self.picks_]-            cov_signal = mne.compute_raw_covariance(-                inst_signal, picks=self.picks_, method=self.estimator)-            cov_noise = mne.compute_raw_covariance(inst_noise, picks=self.picks_,-                method=self.estimator)+            # subtract signal:+            inst_noise._data[self.picks_] -= inst_signal._data[self.picks_]+        else:+            if isinstance(inst, BaseEpochs) or isinstance(inst, np.ndarray):+                # data X is epoched+                # part of the following code is copied from mne csp+                n_epochs, n_channels, n_samples = inst.shape+                self.max_components = n_channels+                # reshape for filtering+                X_aux = np.reshape(inst, [n_epochs, n_channels*n_samples])+                inst_signal = filter_data(+                    X_aux, self.sampling_freq, **self.filt_params_signal)+                # rephase for filtering+                X_aux = np.reshape(inst, [n_epochs, n_channels*n_samples])+                inst_noise = filter_data(+                    X_aux, self.sampling_freq, **self.filt_params_noise)+                # subtract signal:+                inst_noise -= inst_signal+                # Estimate single trial covariance+                # reshape to original shape+                inst_signal = np.reshape(+                    inst_signal, [n_epochs, n_channels, n_samples])

Are line breaks necessary here in terms of 80 characters? alsop below in 214

vpeterson

comment created time in 2 days

PullRequestReviewEvent

Pull request review commentdengemann/mne-python

added option to handle epoched data

 import mne from mne import Epochs from mne.datasets.fieldtrip_cmc import data_path-from mne.utils import _time_mask from mne.channels import read_layout from mne.decoding import TransformerMixin, BaseEstimator +from mne.io.base import BaseRaw+from mne.epochs import BaseEpochs+from mne.utils import _time_mask+from mne.cov import (_regularized_covariance, compute_raw_covariance)+from mne.filter import filter_data+from mne.time_frequency import psd_array_welch+import locale+locale.setlocale(locale.LC_ALL, "en_US.UTF-8")+  def freq_mask(freqs, fmin, fmax):     """convenience function to select frequencies"""     return _time_mask(freqs, fmin, fmax) + # Define parameters fname = data_path() + '/SubjectCMC.ds' raw = mne.io.read_raw_ctf(fname) raw.crop(50., 250.).load_data()  # crop for memory purposes+picks = mne.pick_types(raw.info, meg=True, eeg=False, ref_meg=False)+sf = raw.info['sfreq']  freqs_sig = 9, 12 freqs_noise = 8, 13   class SSD(BaseEstimator, TransformerMixin):-    """Implement Spatio-Spectral Decomposision+    """+    This is a Python Implementation of Spatio Spectral Decomposition (SSD)+    method [1],[2] for both raw and epoched data. This source code is  based on+    the matlab implementation available at+    https://github.com/svendaehne/matlab_SPoC/tree/master/SSD and the+    PR MNE-based implementation of Denis A. Engemann <denis.engemann@gmail.com>++    SSD seeks at maximizing the power at a frequency band of interest while+    simultaneously minimizing it at the flanking (surrounding) frequency bins+    (considered noise). It extremizes the covariance matrices associated to+    signal and noise.++    Cosidering f as the freq. of interest, noise signals can be calculated+    either by filtering the signals in the frequency range [f−Δfb:f+Δfb]+    and then performing band-stop filtering around frequency f [f−Δfs:f+Δfs],+    where Δfb and Δfs generally are set equal to 2 and 1 Hz, or by filtering+    in the frequency range [f−Δf:f+Δf] with the following subtraction of+    the filtered signal around f [1].++    SSD can either be used as a dimentionality reduction method or a denoised+    ‘denoised’ low rank factorization method [2].      Parameters     ----------     filt_params_signal : dict         Filtering for the frequencies of interst.     filt_params_noise  : dict         Filtering for the frequencies of non-interest.-    estimator : str-        Which covariance estimator to use. Defaults to "oas".-    n_components  : int, None-        How many components to keep. Default to 5.-    subtract_signal : bool-        Whether to subtract the noise from the signal to enhcane-        sptial filter.-    sort_by_spectral_ratio : bool-        Whether to sort by the spectral ratio. Defaults to True.-+    sampling_freq : float+        sampling frequency (in Hz) of the recordings.+    estimator : float | str | None (default 'oas')+        Which covariance estimator to use+        If not None (same as 'empirical'), allow regularization for+        covariance estimation. If float, shrinkage is used+        (0 <= shrinkage <= 1). For str options, estimator will be passed to+        method to mne.compute_covariance().+    n_components : int| None (default None)+        The number of components to decompose the signals.+        If n_components is None no dimentionality reduction is made, and the+        transformed data is projected in the whole source space.+   picks: array| int | None  (default None)+       Indeces of good-channels. Can be the output of mne.pick_types++   sort_by_spectral_ratio: bool (default True)+       if set to True, the components are sorted according+       to the spectral ratio+       See [1] Nikulin 2011, Eq. (24)++   return_filtered : bool (default False)+        If return_filtered is True, data is bandpassed and projected onto+        the SSD components.++   n_fft: int (default None)+       if sort_by_spectral_ratio is set to True, then the sources will be+       sorted accordinly to their spectral ratio which is calculated based on+       "psd_array_welch" function. the n_fft set the length of FFT used.+       See mne.time_frequency.psd_array_welch for more information++   cov_method_params : TYPE, optional+        As in mne.decoding.SPoC+        The default is None.+   rank : None | dict | ‘info’ | ‘full’+        As in mne.decoding.SPoC+        This controls the rank computation that can be read from the+        measurement info or estimated from the data.+        See Notes of mne.compute_rank() for details.The default is None.+        The default is None.++    REFERENCES:+    [1] Nikulin, V. V., Nolte, G., & Curio, G. (2011). A novel method for+    reliable and fast extraction of neuronal EEG/MEG oscillations on the basis+    of spatio-spectral decomposition. NeuroImage, 55(4), 1528-1535.+    [2] Haufe, S., Dähne, S., & Nikulin, V. V. (2014). Dimensionality reduction+    for the analysis of brain oscillations. NeuroImage, 101, 583-597.     """ -    def __init__(self, filt_params_signal, filt_params_noise,-                 estimator='oas', n_components=None,-                 subtract_signal=True,-                 reject=None,-                 flat=None,-                 picks=None,-                 sort_by_spectral_ratio=True):+    def __init__(self, filt_params_signal, filt_params_noise, sampling_freq,+                 estimator='oas', n_components=None, picks=None,+                 sort_by_spectral_ratio=True, return_filtered=False,+                 n_fft=None, cov_method_params=None, rank=None):         """Initialize instance"""          dicts = {"signal": filt_params_signal, "noise": filt_params_noise}         for param, dd in [('l', 0), ('h', 0), ('l', 1), ('h', 1)]:             key = ('signal', 'noise')[dd]-            if  param + '_freq' not in dicts[key]:+            if param + '_freq' not in dicts[key]:                 raise ValueError(-                    "'%' must be defined in filter parameters for %s" % key)+                    "'%%' must be defined in filter parameters for %s" % key)             val = dicts[key][param + '_freq']             if not isinstance(val, (int, float)):                 raise ValueError(                     "Frequencies must be numbers, got %s" % type(val))+        # check freq bands+        if (filt_params_noise['l_freq'] > filt_params_signal['l_freq'] or+                filt_params_signal['h_freq'] > filt_params_noise['h_freq']):+            raise ValueError('Wrongly specified frequency bands!\n \+                The signal band-pass must be within the t noise band-pass!')          self.freqs_signal = (filt_params_signal['l_freq'],                              filt_params_signal['h_freq'])         self.freqs_noise = (filt_params_noise['l_freq'],                             filt_params_noise['h_freq'])         self.filt_params_signal = filt_params_signal         self.filt_params_noise = filt_params_noise-        self.subtract_signal = subtract_signal-        self.picks = picks+        self.sort_by_spectral_ratio = sort_by_spectral_ratio+        if n_fft is None:+            self.n_fft = int(sampling_freq)+        else:+            self.n_fft = int(n_fft)+        self.picks_ = picks+        self.return_filtered = return_filtered         self.estimator = estimator         self.n_components = n_components--    def fit(self, inst):-        """Fit"""-        if self.picks == None:-            self.picks_ = mne.pick_types(inst.info, meg=True, eeg=False, ref_meg=False)-        else:-            self.picks_ = self.picks-        if isinstance(inst, mne.io.base.BaseRaw):+        self.rank = rank+        self.sampling_freq = sampling_freq+        self.cov_method_params = cov_method_params++    def _check_X(self, inst):+        """Check input data."""+        if not isinstance(inst, np.ndarray):+            raise ValueError("X should be of type ndarray (got %s)."+                             % type(inst))+        if inst.ndim < 3:+            raise ValueError('X must have at least 3 dimensions.')++    def filter_data(self, inst):+        if isinstance(inst, BaseRaw):             inst_signal = inst.copy()             inst_signal.filter(picks=self.picks_, **self.filt_params_signal)-+            # noise             inst_noise = inst.copy()             inst_noise.filter(picks=self.picks_, **self.filt_params_noise)-            if self.subtract_signal:-                inst_noise._data[self.picks_] -= inst_signal._data[self.picks_]-            cov_signal = mne.compute_raw_covariance(-                inst_signal, picks=self.picks_, method=self.estimator)-            cov_noise = mne.compute_raw_covariance(inst_noise, picks=self.picks_,-                method=self.estimator)+            # subtract signal:+            inst_noise._data[self.picks_] -= inst_signal._data[self.picks_]+        else:+            if isinstance(inst, BaseEpochs) or isinstance(inst, np.ndarray):+                # data X is epoched+                # part of the following code is copied from mne csp+                n_epochs, n_channels, n_samples = inst.shape+                self.max_components = n_channels+                # reshape for filtering+                X_aux = np.reshape(inst, [n_epochs, n_channels*n_samples])

white space here too

vpeterson

comment created time in 2 days

PullRequestReviewEvent
PullRequestReviewEvent

Pull request review commentdengemann/mne-python

added option to handle epoched data

 import mne from mne import Epochs from mne.datasets.fieldtrip_cmc import data_path-from mne.utils import _time_mask from mne.channels import read_layout from mne.decoding import TransformerMixin, BaseEstimator +from mne.io.base import BaseRaw+from mne.epochs import BaseEpochs+from mne.utils import _time_mask+from mne.cov import (_regularized_covariance, compute_raw_covariance)+from mne.filter import filter_data+from mne.time_frequency import psd_array_welch+import locale+locale.setlocale(locale.LC_ALL, "en_US.UTF-8")+  def freq_mask(freqs, fmin, fmax):     """convenience function to select frequencies"""     return _time_mask(freqs, fmin, fmax) + # Define parameters fname = data_path() + '/SubjectCMC.ds' raw = mne.io.read_raw_ctf(fname) raw.crop(50., 250.).load_data()  # crop for memory purposes+picks = mne.pick_types(raw.info, meg=True, eeg=False, ref_meg=False)+sf = raw.info['sfreq']  freqs_sig = 9, 12 freqs_noise = 8, 13   class SSD(BaseEstimator, TransformerMixin):-    """Implement Spatio-Spectral Decomposision+    """+    This is a Python Implementation of Spatio Spectral Decomposition (SSD)+    method [1],[2] for both raw and epoched data. This source code is  based on+    the matlab implementation available at+    https://github.com/svendaehne/matlab_SPoC/tree/master/SSD and the+    PR MNE-based implementation of Denis A. Engemann <denis.engemann@gmail.com>++    SSD seeks at maximizing the power at a frequency band of interest while+    simultaneously minimizing it at the flanking (surrounding) frequency bins+    (considered noise). It extremizes the covariance matrices associated to+    signal and noise.++    Cosidering f as the freq. of interest, noise signals can be calculated+    either by filtering the signals in the frequency range [f−Δfb:f+Δfb]+    and then performing band-stop filtering around frequency f [f−Δfs:f+Δfs],+    where Δfb and Δfs generally are set equal to 2 and 1 Hz, or by filtering+    in the frequency range [f−Δf:f+Δf] with the following subtraction of+    the filtered signal around f [1].++    SSD can either be used as a dimentionality reduction method or a denoised+    ‘denoised’ low rank factorization method [2].      Parameters     ----------     filt_params_signal : dict         Filtering for the frequencies of interst.     filt_params_noise  : dict         Filtering for the frequencies of non-interest.-    estimator : str-        Which covariance estimator to use. Defaults to "oas".-    n_components  : int, None-        How many components to keep. Default to 5.-    subtract_signal : bool-        Whether to subtract the noise from the signal to enhcane-        sptial filter.-    sort_by_spectral_ratio : bool-        Whether to sort by the spectral ratio. Defaults to True.-+    sampling_freq : float+        sampling frequency (in Hz) of the recordings.+    estimator : float | str | None (default 'oas')+        Which covariance estimator to use+        If not None (same as 'empirical'), allow regularization for+        covariance estimation. If float, shrinkage is used+        (0 <= shrinkage <= 1). For str options, estimator will be passed to+        method to mne.compute_covariance().+    n_components : int| None (default None)+        The number of components to decompose the signals.+        If n_components is None no dimentionality reduction is made, and the+        transformed data is projected in the whole source space.+   picks: array| int | None  (default None)+       Indeces of good-channels. Can be the output of mne.pick_types++   sort_by_spectral_ratio: bool (default True)+       if set to True, the components are sorted according+       to the spectral ratio+       See [1] Nikulin 2011, Eq. (24)++   return_filtered : bool (default False)+        If return_filtered is True, data is bandpassed and projected onto+        the SSD components.++   n_fft: int (default None)+       if sort_by_spectral_ratio is set to True, then the sources will be+       sorted accordinly to their spectral ratio which is calculated based on+       "psd_array_welch" function. the n_fft set the length of FFT used.+       See mne.time_frequency.psd_array_welch for more information++   cov_method_params : TYPE, optional+        As in mne.decoding.SPoC+        The default is None.+   rank : None | dict | ‘info’ | ‘full’+        As in mne.decoding.SPoC+        This controls the rank computation that can be read from the+        measurement info or estimated from the data.+        See Notes of mne.compute_rank() for details.The default is None.+        The default is None.++    REFERENCES:+    [1] Nikulin, V. V., Nolte, G., & Curio, G. (2011). A novel method for+    reliable and fast extraction of neuronal EEG/MEG oscillations on the basis+    of spatio-spectral decomposition. NeuroImage, 55(4), 1528-1535.+    [2] Haufe, S., Dähne, S., & Nikulin, V. V. (2014). Dimensionality reduction+    for the analysis of brain oscillations. NeuroImage, 101, 583-597.     """ -    def __init__(self, filt_params_signal, filt_params_noise,-                 estimator='oas', n_components=None,-                 subtract_signal=True,-                 reject=None,-                 flat=None,-                 picks=None,-                 sort_by_spectral_ratio=True):+    def __init__(self, filt_params_signal, filt_params_noise, sampling_freq,+                 estimator='oas', n_components=None, picks=None,+                 sort_by_spectral_ratio=True, return_filtered=False,+                 n_fft=None, cov_method_params=None, rank=None):         """Initialize instance"""          dicts = {"signal": filt_params_signal, "noise": filt_params_noise}         for param, dd in [('l', 0), ('h', 0), ('l', 1), ('h', 1)]:             key = ('signal', 'noise')[dd]-            if  param + '_freq' not in dicts[key]:+            if param + '_freq' not in dicts[key]:                 raise ValueError(-                    "'%' must be defined in filter parameters for %s" % key)+                    "'%%' must be defined in filter parameters for %s" % key)             val = dicts[key][param + '_freq']             if not isinstance(val, (int, float)):                 raise ValueError(                     "Frequencies must be numbers, got %s" % type(val))+        # check freq bands+        if (filt_params_noise['l_freq'] > filt_params_signal['l_freq'] or+                filt_params_signal['h_freq'] > filt_params_noise['h_freq']):+            raise ValueError('Wrongly specified frequency bands!\n \+                The signal band-pass must be within the t noise band-pass!')          self.freqs_signal = (filt_params_signal['l_freq'],                              filt_params_signal['h_freq'])         self.freqs_noise = (filt_params_noise['l_freq'],                             filt_params_noise['h_freq'])         self.filt_params_signal = filt_params_signal         self.filt_params_noise = filt_params_noise-        self.subtract_signal = subtract_signal-        self.picks = picks+        self.sort_by_spectral_ratio = sort_by_spectral_ratio+        if n_fft is None:+            self.n_fft = int(sampling_freq)+        else:+            self.n_fft = int(n_fft)+        self.picks_ = picks+        self.return_filtered = return_filtered         self.estimator = estimator         self.n_components = n_components--    def fit(self, inst):-        """Fit"""-        if self.picks == None:-            self.picks_ = mne.pick_types(inst.info, meg=True, eeg=False, ref_meg=False)-        else:-            self.picks_ = self.picks-        if isinstance(inst, mne.io.base.BaseRaw):+        self.rank = rank+        self.sampling_freq = sampling_freq+        self.cov_method_params = cov_method_params++    def _check_X(self, inst):+        """Check input data."""+        if not isinstance(inst, np.ndarray):+            raise ValueError("X should be of type ndarray (got %s)."+                             % type(inst))+        if inst.ndim < 3:+            raise ValueError('X must have at least 3 dimensions.')++    def filter_data(self, inst):+        if isinstance(inst, BaseRaw):             inst_signal = inst.copy()             inst_signal.filter(picks=self.picks_, **self.filt_params_signal)-+            # noise             inst_noise = inst.copy()             inst_noise.filter(picks=self.picks_, **self.filt_params_noise)-            if self.subtract_signal:-                inst_noise._data[self.picks_] -= inst_signal._data[self.picks_]-            cov_signal = mne.compute_raw_covariance(-                inst_signal, picks=self.picks_, method=self.estimator)-            cov_noise = mne.compute_raw_covariance(inst_noise, picks=self.picks_,-                method=self.estimator)+            # subtract signal:+            inst_noise._data[self.picks_] -= inst_signal._data[self.picks_]+        else:+            if isinstance(inst, BaseEpochs) or isinstance(inst, np.ndarray):+                # data X is epoched+                # part of the following code is copied from mne csp+                n_epochs, n_channels, n_samples = inst.shape+                self.max_components = n_channels+                # reshape for filtering+                X_aux = np.reshape(inst, [n_epochs, n_channels*n_samples])+                inst_signal = filter_data(+                    X_aux, self.sampling_freq, **self.filt_params_signal)+                # rephase for filtering+                X_aux = np.reshape(inst, [n_epochs, n_channels*n_samples])

white space around operator *

vpeterson

comment created time in 2 days

Pull request review commentdengemann/mne-python

added option to handle epoched data

 import mne from mne import Epochs from mne.datasets.fieldtrip_cmc import data_path-from mne.utils import _time_mask from mne.channels import read_layout from mne.decoding import TransformerMixin, BaseEstimator +from mne.io.base import BaseRaw+from mne.epochs import BaseEpochs+from mne.utils import _time_mask+from mne.cov import (_regularized_covariance, compute_raw_covariance)+from mne.filter import filter_data+from mne.time_frequency import psd_array_welch+import locale+locale.setlocale(locale.LC_ALL, "en_US.UTF-8")+  def freq_mask(freqs, fmin, fmax):     """convenience function to select frequencies"""     return _time_mask(freqs, fmin, fmax) + # Define parameters fname = data_path() + '/SubjectCMC.ds' raw = mne.io.read_raw_ctf(fname) raw.crop(50., 250.).load_data()  # crop for memory purposes+picks = mne.pick_types(raw.info, meg=True, eeg=False, ref_meg=False)+sf = raw.info['sfreq']  freqs_sig = 9, 12 freqs_noise = 8, 13   class SSD(BaseEstimator, TransformerMixin):-    """Implement Spatio-Spectral Decomposision+    """+    This is a Python Implementation of Spatio Spectral Decomposition (SSD)+    method [1],[2] for both raw and epoched data. This source code is  based on+    the matlab implementation available at+    https://github.com/svendaehne/matlab_SPoC/tree/master/SSD and the+    PR MNE-based implementation of Denis A. Engemann <denis.engemann@gmail.com>++    SSD seeks at maximizing the power at a frequency band of interest while+    simultaneously minimizing it at the flanking (surrounding) frequency bins+    (considered noise). It extremizes the covariance matrices associated to+    signal and noise.++    Cosidering f as the freq. of interest, noise signals can be calculated+    either by filtering the signals in the frequency range [f−Δfb:f+Δfb]+    and then performing band-stop filtering around frequency f [f−Δfs:f+Δfs],+    where Δfb and Δfs generally are set equal to 2 and 1 Hz, or by filtering+    in the frequency range [f−Δf:f+Δf] with the following subtraction of+    the filtered signal around f [1].++    SSD can either be used as a dimentionality reduction method or a denoised+    ‘denoised’ low rank factorization method [2].      Parameters     ----------     filt_params_signal : dict         Filtering for the frequencies of interst.     filt_params_noise  : dict         Filtering for the frequencies of non-interest.-    estimator : str-        Which covariance estimator to use. Defaults to "oas".-    n_components  : int, None-        How many components to keep. Default to 5.-    subtract_signal : bool-        Whether to subtract the noise from the signal to enhcane-        sptial filter.-    sort_by_spectral_ratio : bool-        Whether to sort by the spectral ratio. Defaults to True.-+    sampling_freq : float+        sampling frequency (in Hz) of the recordings.+    estimator : float | str | None (default 'oas')+        Which covariance estimator to use+        If not None (same as 'empirical'), allow regularization for+        covariance estimation. If float, shrinkage is used+        (0 <= shrinkage <= 1). For str options, estimator will be passed to+        method to mne.compute_covariance().+    n_components : int| None (default None)+        The number of components to decompose the signals.+        If n_components is None no dimentionality reduction is made, and the+        transformed data is projected in the whole source space.+   picks: array| int | None  (default None)+       Indeces of good-channels. Can be the output of mne.pick_types++   sort_by_spectral_ratio: bool (default True)+       if set to True, the components are sorted according+       to the spectral ratio+       See [1] Nikulin 2011, Eq. (24)++   return_filtered : bool (default False)+        If return_filtered is True, data is bandpassed and projected onto+        the SSD components.++   n_fft: int (default None)+       if sort_by_spectral_ratio is set to True, then the sources will be+       sorted accordinly to their spectral ratio which is calculated based on+       "psd_array_welch" function. the n_fft set the length of FFT used.+       See mne.time_frequency.psd_array_welch for more information++   cov_method_params : TYPE, optional+        As in mne.decoding.SPoC+        The default is None.+   rank : None | dict | ‘info’ | ‘full’+        As in mne.decoding.SPoC+        This controls the rank computation that can be read from the+        measurement info or estimated from the data.+        See Notes of mne.compute_rank() for details.The default is None.+        The default is None.++    REFERENCES:+    [1] Nikulin, V. V., Nolte, G., & Curio, G. (2011). A novel method for+    reliable and fast extraction of neuronal EEG/MEG oscillations on the basis+    of spatio-spectral decomposition. NeuroImage, 55(4), 1528-1535.+    [2] Haufe, S., Dähne, S., & Nikulin, V. V. (2014). Dimensionality reduction+    for the analysis of brain oscillations. NeuroImage, 101, 583-597.     """ -    def __init__(self, filt_params_signal, filt_params_noise,-                 estimator='oas', n_components=None,-                 subtract_signal=True,-                 reject=None,-                 flat=None,-                 picks=None,-                 sort_by_spectral_ratio=True):+    def __init__(self, filt_params_signal, filt_params_noise, sampling_freq,+                 estimator='oas', n_components=None, picks=None,+                 sort_by_spectral_ratio=True, return_filtered=False,+                 n_fft=None, cov_method_params=None, rank=None):         """Initialize instance"""          dicts = {"signal": filt_params_signal, "noise": filt_params_noise}         for param, dd in [('l', 0), ('h', 0), ('l', 1), ('h', 1)]:             key = ('signal', 'noise')[dd]-            if  param + '_freq' not in dicts[key]:+            if param + '_freq' not in dicts[key]:                 raise ValueError(-                    "'%' must be defined in filter parameters for %s" % key)+                    "'%%' must be defined in filter parameters for %s" % key)             val = dicts[key][param + '_freq']             if not isinstance(val, (int, float)):                 raise ValueError(                     "Frequencies must be numbers, got %s" % type(val))+        # check freq bands+        if (filt_params_noise['l_freq'] > filt_params_signal['l_freq'] or+                filt_params_signal['h_freq'] > filt_params_noise['h_freq']):+            raise ValueError('Wrongly specified frequency bands!\n \+                The signal band-pass must be within the t noise band-pass!')

\ is not needed here as you have surrounding round brackets.

vpeterson

comment created time in 2 days

PullRequestReviewEvent

Pull request review commentdengemann/mne-python

added option to handle epoched data

 import mne from mne import Epochs from mne.datasets.fieldtrip_cmc import data_path-from mne.utils import _time_mask from mne.channels import read_layout from mne.decoding import TransformerMixin, BaseEstimator +from mne.io.base import BaseRaw+from mne.epochs import BaseEpochs+from mne.utils import _time_mask+from mne.cov import (_regularized_covariance, compute_raw_covariance)+from mne.filter import filter_data+from mne.time_frequency import psd_array_welch+import locale+locale.setlocale(locale.LC_ALL, "en_US.UTF-8")+  def freq_mask(freqs, fmin, fmax):     """convenience function to select frequencies"""     return _time_mask(freqs, fmin, fmax) + # Define parameters fname = data_path() + '/SubjectCMC.ds' raw = mne.io.read_raw_ctf(fname) raw.crop(50., 250.).load_data()  # crop for memory purposes+picks = mne.pick_types(raw.info, meg=True, eeg=False, ref_meg=False)+sf = raw.info['sfreq']  freqs_sig = 9, 12 freqs_noise = 8, 13   class SSD(BaseEstimator, TransformerMixin):-    """Implement Spatio-Spectral Decomposision+    """+    This is a Python Implementation of Spatio Spectral Decomposition (SSD)+    method [1],[2] for both raw and epoched data. This source code is  based on+    the matlab implementation available at+    https://github.com/svendaehne/matlab_SPoC/tree/master/SSD and the+    PR MNE-based implementation of Denis A. Engemann <denis.engemann@gmail.com>++    SSD seeks at maximizing the power at a frequency band of interest while+    simultaneously minimizing it at the flanking (surrounding) frequency bins+    (considered noise). It extremizes the covariance matrices associated to+    signal and noise.++    Cosidering f as the freq. of interest, noise signals can be calculated+    either by filtering the signals in the frequency range [f−Δfb:f+Δfb]+    and then performing band-stop filtering around frequency f [f−Δfs:f+Δfs],+    where Δfb and Δfs generally are set equal to 2 and 1 Hz, or by filtering+    in the frequency range [f−Δf:f+Δf] with the following subtraction of+    the filtered signal around f [1].++    SSD can either be used as a dimentionality reduction method or a denoised+    ‘denoised’ low rank factorization method [2].      Parameters     ----------     filt_params_signal : dict         Filtering for the frequencies of interst.     filt_params_noise  : dict         Filtering for the frequencies of non-interest.-    estimator : str-        Which covariance estimator to use. Defaults to "oas".-    n_components  : int, None-        How many components to keep. Default to 5.-    subtract_signal : bool-        Whether to subtract the noise from the signal to enhcane-        sptial filter.-    sort_by_spectral_ratio : bool-        Whether to sort by the spectral ratio. Defaults to True.-+    sampling_freq : float+        sampling frequency (in Hz) of the recordings.+    estimator : float | str | None (default 'oas')+        Which covariance estimator to use+        If not None (same as 'empirical'), allow regularization for+        covariance estimation. If float, shrinkage is used+        (0 <= shrinkage <= 1). For str options, estimator will be passed to+        method to mne.compute_covariance().+    n_components : int| None (default None)+        The number of components to decompose the signals.+        If n_components is None no dimentionality reduction is made, and the+        transformed data is projected in the whole source space.+   picks: array| int | None  (default None)+       Indeces of good-channels. Can be the output of mne.pick_types++   sort_by_spectral_ratio: bool (default True)+       if set to True, the components are sorted according+       to the spectral ratio+       See [1] Nikulin 2011, Eq. (24)++   return_filtered : bool (default False)+        If return_filtered is True, data is bandpassed and projected onto+        the SSD components.++   n_fft: int (default None)+       if sort_by_spectral_ratio is set to True, then the sources will be+       sorted accordinly to their spectral ratio which is calculated based on+       "psd_array_welch" function. the n_fft set the length of FFT used.+       See mne.time_frequency.psd_array_welch for more information++   cov_method_params : TYPE, optional+        As in mne.decoding.SPoC+        The default is None.+   rank : None | dict | ‘info’ | ‘full’+        As in mne.decoding.SPoC+        This controls the rank computation that can be read from the+        measurement info or estimated from the data.+        See Notes of mne.compute_rank() for details.The default is None.+        The default is None.++    REFERENCES:+    [1] Nikulin, V. V., Nolte, G., & Curio, G. (2011). A novel method for+    reliable and fast extraction of neuronal EEG/MEG oscillations on the basis+    of spatio-spectral decomposition. NeuroImage, 55(4), 1528-1535.+    [2] Haufe, S., Dähne, S., & Nikulin, V. V. (2014). Dimensionality reduction+    for the analysis of brain oscillations. NeuroImage, 101, 583-597.

Have a look at other functions which print references. These days we use :footcite: to extract the reference from a bib file. See #8268 for example.

vpeterson

comment created time in 2 days

PullRequestReviewEvent

Pull request review commentdengemann/mne-python

added option to handle epoched data

 import mne from mne import Epochs from mne.datasets.fieldtrip_cmc import data_path-from mne.utils import _time_mask from mne.channels import read_layout from mne.decoding import TransformerMixin, BaseEstimator +from mne.io.base import BaseRaw+from mne.epochs import BaseEpochs+from mne.utils import _time_mask+from mne.cov import (_regularized_covariance, compute_raw_covariance)+from mne.filter import filter_data+from mne.time_frequency import psd_array_welch+import locale+locale.setlocale(locale.LC_ALL, "en_US.UTF-8")+  def freq_mask(freqs, fmin, fmax):     """convenience function to select frequencies"""     return _time_mask(freqs, fmin, fmax) + # Define parameters fname = data_path() + '/SubjectCMC.ds' raw = mne.io.read_raw_ctf(fname) raw.crop(50., 250.).load_data()  # crop for memory purposes+picks = mne.pick_types(raw.info, meg=True, eeg=False, ref_meg=False)+sf = raw.info['sfreq']  freqs_sig = 9, 12 freqs_noise = 8, 13   class SSD(BaseEstimator, TransformerMixin):-    """Implement Spatio-Spectral Decomposision+    """+    This is a Python Implementation of Spatio Spectral Decomposition (SSD)+    method [1],[2] for both raw and epoched data. This source code is  based on+    the matlab implementation available at+    https://github.com/svendaehne/matlab_SPoC/tree/master/SSD and the+    PR MNE-based implementation of Denis A. Engemann <denis.engemann@gmail.com>++    SSD seeks at maximizing the power at a frequency band of interest while+    simultaneously minimizing it at the flanking (surrounding) frequency bins+    (considered noise). It extremizes the covariance matrices associated to+    signal and noise.++    Cosidering f as the freq. of interest, noise signals can be calculated+    either by filtering the signals in the frequency range [f−Δfb:f+Δfb]+    and then performing band-stop filtering around frequency f [f−Δfs:f+Δfs],+    where Δfb and Δfs generally are set equal to 2 and 1 Hz, or by filtering+    in the frequency range [f−Δf:f+Δf] with the following subtraction of+    the filtered signal around f [1].++    SSD can either be used as a dimentionality reduction method or a denoised+    ‘denoised’ low rank factorization method [2].      Parameters     ----------     filt_params_signal : dict         Filtering for the frequencies of interst.     filt_params_noise  : dict         Filtering for the frequencies of non-interest.-    estimator : str-        Which covariance estimator to use. Defaults to "oas".-    n_components  : int, None-        How many components to keep. Default to 5.-    subtract_signal : bool-        Whether to subtract the noise from the signal to enhcane-        sptial filter.-    sort_by_spectral_ratio : bool-        Whether to sort by the spectral ratio. Defaults to True.-+    sampling_freq : float+        sampling frequency (in Hz) of the recordings.+    estimator : float | str | None (default 'oas')+        Which covariance estimator to use+        If not None (same as 'empirical'), allow regularization for+        covariance estimation. If float, shrinkage is used+        (0 <= shrinkage <= 1). For str options, estimator will be passed to+        method to mne.compute_covariance().+    n_components : int| None (default None)+        The number of components to decompose the signals.+        If n_components is None no dimentionality reduction is made, and the+        transformed data is projected in the whole source space.+   picks: array| int | None  (default None)+       Indeces of good-channels. Can be the output of mne.pick_types++   sort_by_spectral_ratio: bool (default True)+       if set to True, the components are sorted according+       to the spectral ratio+       See [1] Nikulin 2011, Eq. (24)+

same here and below.

vpeterson

comment created time in 2 days

PullRequestReviewEvent

Pull request review commentdengemann/mne-python

added option to handle epoched data

 import mne from mne import Epochs from mne.datasets.fieldtrip_cmc import data_path-from mne.utils import _time_mask from mne.channels import read_layout from mne.decoding import TransformerMixin, BaseEstimator +from mne.io.base import BaseRaw+from mne.epochs import BaseEpochs+from mne.utils import _time_mask+from mne.cov import (_regularized_covariance, compute_raw_covariance)+from mne.filter import filter_data+from mne.time_frequency import psd_array_welch+import locale+locale.setlocale(locale.LC_ALL, "en_US.UTF-8")+  def freq_mask(freqs, fmin, fmax):     """convenience function to select frequencies"""     return _time_mask(freqs, fmin, fmax) + # Define parameters fname = data_path() + '/SubjectCMC.ds' raw = mne.io.read_raw_ctf(fname) raw.crop(50., 250.).load_data()  # crop for memory purposes+picks = mne.pick_types(raw.info, meg=True, eeg=False, ref_meg=False)+sf = raw.info['sfreq']  freqs_sig = 9, 12 freqs_noise = 8, 13   class SSD(BaseEstimator, TransformerMixin):-    """Implement Spatio-Spectral Decomposision+    """+    This is a Python Implementation of Spatio Spectral Decomposition (SSD)+    method [1],[2] for both raw and epoched data. This source code is  based on+    the matlab implementation available at+    https://github.com/svendaehne/matlab_SPoC/tree/master/SSD and the+    PR MNE-based implementation of Denis A. Engemann <denis.engemann@gmail.com>++    SSD seeks at maximizing the power at a frequency band of interest while+    simultaneously minimizing it at the flanking (surrounding) frequency bins+    (considered noise). It extremizes the covariance matrices associated to+    signal and noise.++    Cosidering f as the freq. of interest, noise signals can be calculated+    either by filtering the signals in the frequency range [f−Δfb:f+Δfb]+    and then performing band-stop filtering around frequency f [f−Δfs:f+Δfs],+    where Δfb and Δfs generally are set equal to 2 and 1 Hz, or by filtering+    in the frequency range [f−Δf:f+Δf] with the following subtraction of+    the filtered signal around f [1].++    SSD can either be used as a dimentionality reduction method or a denoised+    ‘denoised’ low rank factorization method [2].      Parameters     ----------     filt_params_signal : dict         Filtering for the frequencies of interst.     filt_params_noise  : dict         Filtering for the frequencies of non-interest.-    estimator : str-        Which covariance estimator to use. Defaults to "oas".-    n_components  : int, None-        How many components to keep. Default to 5.-    subtract_signal : bool-        Whether to subtract the noise from the signal to enhcane-        sptial filter.-    sort_by_spectral_ratio : bool-        Whether to sort by the spectral ratio. Defaults to True.-+    sampling_freq : float+        sampling frequency (in Hz) of the recordings.+    estimator : float | str | None (default 'oas')+        Which covariance estimator to use+        If not None (same as 'empirical'), allow regularization for+        covariance estimation. If float, shrinkage is used+        (0 <= shrinkage <= 1). For str options, estimator will be passed to+        method to mne.compute_covariance().+    n_components : int| None (default None)+        The number of components to decompose the signals.+        If n_components is None no dimentionality reduction is made, and the+        transformed data is projected in the whole source space.+   picks: array| int | None  (default None)+       Indeces of good-channels. Can be the output of mne.pick_types+

These blank lines in the doc string look untypical. We can remove them.

vpeterson

comment created time in 2 days

PullRequestReviewEvent

Pull request review commentdengemann/mne-python

added option to handle epoched data

 import mne from mne import Epochs from mne.datasets.fieldtrip_cmc import data_path-from mne.utils import _time_mask from mne.channels import read_layout from mne.decoding import TransformerMixin, BaseEstimator +from mne.io.base import BaseRaw+from mne.epochs import BaseEpochs+from mne.utils import _time_mask+from mne.cov import (_regularized_covariance, compute_raw_covariance)+from mne.filter import filter_data+from mne.time_frequency import psd_array_welch+import locale+locale.setlocale(locale.LC_ALL, "en_US.UTF-8")+  def freq_mask(freqs, fmin, fmax):     """convenience function to select frequencies"""     return _time_mask(freqs, fmin, fmax) + # Define parameters fname = data_path() + '/SubjectCMC.ds' raw = mne.io.read_raw_ctf(fname) raw.crop(50., 250.).load_data()  # crop for memory purposes+picks = mne.pick_types(raw.info, meg=True, eeg=False, ref_meg=False)+sf = raw.info['sfreq']  freqs_sig = 9, 12 freqs_noise = 8, 13   class SSD(BaseEstimator, TransformerMixin):-    """Implement Spatio-Spectral Decomposision+    """+    This is a Python Implementation of Spatio Spectral Decomposition (SSD)+    method [1],[2] for both raw and epoched data. This source code is  based on+    the matlab implementation available at+    https://github.com/svendaehne/matlab_SPoC/tree/master/SSD and the+    PR MNE-based implementation of Denis A. Engemann <denis.engemann@gmail.com>

These authorship details are not necessary. You do not find this in other functions of the MNE source code. For what I proposed at least, it is also not true that the source code was based on any other code. I implemented the initial code based on the 2011 paper. Let me know if the reference to the Matlab code is justified for any line that you have proposed.

vpeterson

comment created time in 2 days

PullRequestReviewEvent

Pull request review commentdengemann/mne-python

added option to handle epoched data

 import mne from mne import Epochs from mne.datasets.fieldtrip_cmc import data_path-from mne.utils import _time_mask from mne.channels import read_layout from mne.decoding import TransformerMixin, BaseEstimator +from mne.io.base import BaseRaw+from mne.epochs import BaseEpochs+from mne.utils import _time_mask+from mne.cov import (_regularized_covariance, compute_raw_covariance)+from mne.filter import filter_data+from mne.time_frequency import psd_array_welch+import locale+locale.setlocale(locale.LC_ALL, "en_US.UTF-8")

What is this? It looks computer specific and should not be there.

vpeterson

comment created time in 2 days

PullRequestReviewEvent

Pull request review commentdengemann/mne-python

added option to handle epoched data

 =========================================================== Compute Sepctro-Spatial Decomposition (SDD) spatial filters ===========================================================- In this example, we will compute spatial filters for retaining oscillatory brain activity and down-weighting 1/f background signals as proposed by [1]_. The idea is to learn spatial filters that separate oscillatory dynamics from surrounding non-oscillatory noise based on the covariance in the frequency band of interest and the noise covariance absed on surrounding frequencies.- References ----------- .. [1] Nikulin, V. V., Nolte, G., & Curio, G. (2011). A novel method for        reliable and fast extraction of neuronal EEG/MEG oscillations on the        basis of spatio-spectral decomposition. NeuroImage, 55(4), 1528-1535. """-# Author: Denis A. Engemann <denis.engemann@gmail.com>-#+# Author: Denis A. Engemann <denis.engemann@gmail.com>, &+# Victoria Peterson <victoriapeterson09@gmail.com>

I think btw. the typical pattern is not to use & and indent the second line to the first letter of the author in the first line. ... details.

vpeterson

comment created time in 2 days

PullRequestReviewEvent

pull request commentdengemann/mne-python

added option to handle epoched data

@vpeterson are you happy -- in principle with your PR ? We could merge it to move on and then discuss what's next.

vpeterson

comment created time in 2 days

Pull request review commentdengemann/mne-python

added option to handle epoched data

 =========================================================== Compute Sepctro-Spatial Decomposition (SDD) spatial filters ===========================================================- In this example, we will compute spatial filters for retaining oscillatory brain activity and down-weighting 1/f background signals as proposed by [1]_. The idea is to learn spatial filters that separate oscillatory dynamics from surrounding non-oscillatory noise based on the covariance in the frequency band of interest and the noise covariance absed on surrounding frequencies.- References ----------- .. [1] Nikulin, V. V., Nolte, G., & Curio, G. (2011). A novel method for        reliable and fast extraction of neuronal EEG/MEG oscillations on the        basis of spatio-spectral decomposition. NeuroImage, 55(4), 1528-1535. """-# Author: Denis A. Engemann <denis.engemann@gmail.com>-#+# Author: Denis A. Engemann <denis.engemann@gmail.com>, &+# Victoria Peterson <victoriapeterson09@gmail.com>

Very good. I was gonna suggest this.

vpeterson

comment created time in 2 days

PullRequestReviewEvent

pull request commentmne-tools/mne-python

DOC: add literature reference for apply_inverse_cov

@larsoner @larsoner I have addressed your concerns and fixed a few more footcite cases on the fly.

I also dropped an e-mail to John Mosher to see if there is any important paper to be cited for the general idea of projecting the data cov, beyond this implementation that comes from our work with @DavidSabbagh

dengemann

comment created time in 4 days

push eventdengemann/mne-python

dengemann

commit sha 8c0cd0fa6889567fac0815559eaf2b4c4ca264f6

some more footcite

view details

dengemann

commit sha cc1122da52119b7cc3a438738fe51e93666ea644

fix

view details

push time in 4 days

push eventdengemann/mne-python

Denis A. Engemann

commit sha b3b36c5808426366aefe42c9a0321e54ef02fc9f

Update examples/inverse/plot_mne_cov_power.py Co-authored-by: Daniel McCloy <dan@mccloy.info>

view details

push time in 4 days

push eventdengemann/mne-python

Denis A. Engemann

commit sha 00358d0bddf8e195024e285fd04ff28f3d92b72a

Update doc/references.bib Co-authored-by: Daniel McCloy <dan@mccloy.info>

view details

push time in 4 days

pull request commentmne-tools/mne-python

DOC: add literature reference for apply_inverse_cov

@larsoner I saw that some in some other places footcite has not been used either. While I'm at it shall I fix it in other places?

There are a lot of places it hasn't been updated, in general I update them in whatever function/file I happen to be working on at a given time.

Ok I'll fix a few I saw jn the cov documentation

dengemann

comment created time in 4 days

push eventdengemann/mne-python

dengemann

commit sha 19c070e558b4968c872850126574eae1d99a0f16

fix bib

view details

push time in 4 days

pull request commentmne-tools/mne-python

DOC: add literature reference for apply_inverse_cov

@larsoner I saw that some in some other places footcite has not been used either. While I'm at it shall I fix it in other places?

Also @larsoner @agramfort while this ref gives credit to the Sabbagh paper whose original research code went into the initial contribution, probably the idea of apply MNE operators to covariances may be older. If you are aware of other references that would deserve credit here I'd be very happy to add them here.

dengemann

comment created time in 4 days

push eventdengemann/mne-python

dengemann

commit sha 019a0ed6be0067c3409d1957d68708c923168544

footcite & improve wording

view details

push time in 4 days

Pull request review commentdengemann/mne-python

added option to handle epoched data, sort component with respect to s…

 def freq_mask(freqs, fmin, fmax): fname = data_path() + '/SubjectCMC.ds' raw = mne.io.read_raw_ctf(fname) raw.crop(50., 250.).load_data()  # crop for memory purposes+picks=mne.pick_types(raw.info, meg=True, eeg=False, ref_meg=False)+sf=raw.info['sfreq']  freqs_sig = 9, 12 freqs_noise = 8, 13   class SSD(BaseEstimator, TransformerMixin):-    """Implement Spatio-Spectral Decomposision+    """+    +    This is a Python Implementation of Spatio Spectral Decomposition (SSD) +    method [1],[2] for both raw and epoched data. This source code is  based on+    the matlab implementation available at +    https://github.com/svendaehne/matlab_SPoC/tree/master/SSD and the PR MNE-based+    implementation of Denis A. Engemann <denis.engemann@gmail.com>+    +    SSD seeks at maximizing the power at a frequency band of interest while+    simultaneously minimizing it at the flanking (surrounding) frequency bins+    (considered noise). It extremizes the covariance matrices associated to +    signal and noise.+    +    Cosidering f as the freq. of interest, noise signals can be calculated+    either by filtering the signals in the frequency range [f−Δfb:f+Δfb] and then +    performing band-stop filtering around frequency f [f−Δfs:f+Δfs], where Δfb+    and Δfs generally are set equal to 2 and 1 Hz, or by filtering +    in the frequency range [f−Δf:f+Δf] with the following subtraction of +    the filtered signal around f [1]. +    +    SSD can either be used as a dimentionality reduction method or a denoised +    ‘denoised’ low rank factorization method [2].+              Parameters     ----------     filt_params_signal : dict         Filtering for the frequencies of interst.     filt_params_noise  : dict         Filtering for the frequencies of non-interest.-    estimator : str-        Which covariance estimator to use. Defaults to "oas".-    n_components  : int, None-        How many components to keep. Default to 5.-    subtract_signal : bool-        Whether to subtract the noise from the signal to enhcane-        sptial filter.-    sort_by_spectral_ratio : bool-        Whether to sort by the spectral ratio. Defaults to True.-+    sampling_freq : float+        sampling frequency (in Hz) of the recordings.+    estimator : float | str | None (default 'oas')+        Which covariance estimator to use+        If not None (same as 'empirical'), allow regularization for+        covariance estimation. If float, shrinkage is used +        (0 <= shrinkage <= 1). For str options, estimator will be passed to method +        to mne.compute_covariance().    +    n_components : int| None (default None)+        The number of components to decompose the signals. +        If n_components is None no dimentionality reduction is made, and the +        transformed data is projected in the whole source space.+   picks: array| int | None  (default None)+       Indeces of good-channels. Can be the output of mne.pick_types+ +   sort_by_spectral_ratio: bool (default True)+       if set to True, the components are sorted according to the spectral ratio+       See [1] Nikulin 2011, Eq. (24)+       +   return_filtered : bool (default False)+        If return_filtered is True, data is bandpassed and projected onto +        the SSD components.+        +   n_fft: int (default None)+       if sort_by_spectral_ratio is set to True, then the sources will be sorted+       accordinly to their spectral ratio which is calculated based on +       "psd_array_welch" function. the n_fft set the length of FFT used.+       See mne.time_frequency.psd_array_welch for more information+    +   cov_method_params : TYPE, optional+        As in mne.decoding.SPoC +        The default is None.+   rank : None | dict | ‘info’ | ‘full’+        As in mne.decoding.SPoC +        This controls the rank computation that can be read from the+        measurement info or estimated from the data. +        See Notes of mne.compute_rank() for details.The default is None.+        The default is None.++    +    REFERENCES:+    [1] Nikulin, V. V., Nolte, G., & Curio, G. (2011). A novel method for +    reliable and fast extraction of neuronal EEG/MEG oscillations on the basis +    of spatio-spectral decomposition. NeuroImage, 55(4), 1528-1535.+    [2] Haufe, S., Dähne, S., & Nikulin, V. V. (2014). Dimensionality reduction+    for the analysis of brain oscillations. NeuroImage, 101, 583-597.+    +    +                 """ -    def __init__(self, filt_params_signal, filt_params_noise,-                 estimator='oas', n_components=None,-                 subtract_signal=True,-                 reject=None,-                 flat=None,-                 picks=None,-                 sort_by_spectral_ratio=True):+    def __init__(self, filt_params_signal, filt_params_noise, sampling_freq,+                 estimator='oas', n_components=None, picks=None,+                 sort_by_spectral_ratio=True, return_filtered=False, n_fft=None, cov_method_params=None, rank=None):+                 """Initialize instance"""          dicts = {"signal": filt_params_signal, "noise": filt_params_noise}         for param, dd in [('l', 0), ('h', 0), ('l', 1), ('h', 1)]:             key = ('signal', 'noise')[dd]             if  param + '_freq' not in dicts[key]:                 raise ValueError(-                    "'%' must be defined in filter parameters for %s" % key)+                    "'%%' must be defined in filter parameters for %s" % key)             val = dicts[key][param + '_freq']             if not isinstance(val, (int, float)):                 raise ValueError(                     "Frequencies must be numbers, got %s" % type(val))+       +          #check freq bands+        if (filt_params_noise['l_freq'] > filt_params_signal['l_freq'] or  +                filt_params_signal['h_freq']>filt_params_noise['h_freq']):+            raise ValueError('Wrongly specified frequency bands!\nThe signal band-pass must be within the t noise band-pass!')          self.freqs_signal = (filt_params_signal['l_freq'],                              filt_params_signal['h_freq'])         self.freqs_noise = (filt_params_noise['l_freq'],                             filt_params_noise['h_freq'])+        +        +                       self.filt_params_signal = filt_params_signal         self.filt_params_noise = filt_params_noise-        self.subtract_signal = subtract_signal-        self.picks = picks+        self.sort_by_spectral_ratio = sort_by_spectral_ratio+        if n_fft is None:+            self.n_fft= int(sampling_freq)+        else:+            self.n_fft=int(n_fft)+        self.picks_ = picks+        +        self.return_filtered=return_filtered+        +                self.estimator = estimator         self.n_components = n_components-+        self.rank = rank+        self.sampling_freq=sampling_freq      +        self.cov_method_params = cov_method_params+        +         def fit(self, inst):         """Fit"""-        if self.picks == None:-            self.picks_ = mne.pick_types(inst.info, meg=True, eeg=False, ref_meg=False)-        else:-            self.picks_ = self.picks-        if isinstance(inst, mne.io.base.BaseRaw):+        +        +        if isinstance(inst, BaseRaw):+            if self.picks_ is None:+                raise ValueError('picks should be provided')+            self.max_components=len(self.picks_)             inst_signal = inst.copy()             inst_signal.filter(picks=self.picks_, **self.filt_params_signal)-+            self.Xs=inst_signal+            #noise             inst_noise = inst.copy()             inst_noise.filter(picks=self.picks_, **self.filt_params_noise)-            if self.subtract_signal:-                inst_noise._data[self.picks_] -= inst_signal._data[self.picks_]-            cov_signal = mne.compute_raw_covariance(-                inst_signal, picks=self.picks_, method=self.estimator)-            cov_noise = mne.compute_raw_covariance(inst_noise, picks=self.picks_,-                method=self.estimator)+            # subtract signal:+            inst_noise._data[self.picks_] -= inst_signal._data[self.picks_]+           +            cov_signal = compute_raw_covariance(+                inst_signal, picks=self.picks_, method=self.estimator, rank=self.rank)+            cov_noise = compute_raw_covariance(inst_noise, picks=self.picks_,+                method=self.estimator, rank=self.rank)             del inst_noise             del inst_signal         else:-            raise NotImplementedError()+            if isinstance(inst, BaseEpochs)  or isinstance(inst, np.ndarray):+            # data X is epoched +            # part of the following code is copied from mne csp+                n_epochs, n_channels, n_samples = inst.shape+                self.max_components=n_channels+              +                #reshape for filtering+                X_aux=np.reshape(inst, [n_epochs, n_channels*n_samples])+                X_s=filter_data(X_aux, self.sampling_freq, **self.filt_params_signal)  +                +                #rephase for filtering+                X_aux=np.reshape(inst, [n_epochs, n_channels*n_samples])+                X_n=filter_data(X_aux, self.sampling_freq, **self.filt_params_noise)+                # subtract signal:+                X_n -= X_s+                +                # Estimate single trial covariance+                #reshape to original shape+                X_s=np.reshape(X_s, [n_epochs,n_channels,n_samples])

Sometimes they are missing something .. I used pyflakes and pep8. Here we had particularly many white space errors so I suspect something has not been working at that level.

vpeterson

comment created time in 4 days

PullRequestReviewEvent

Pull request review commentdengemann/mne-python

added option to handle epoched data, sort component with respect to s…

 def spectral_ratio_ssd(psd, freqs, freqs_sig, freqs_noise):                                   fir_design='firwin'),           filt_params_noise=dict(l_freq=freqs_noise[0], h_freq=freqs_noise[1],                                   l_trans_bandwidth=1, h_trans_bandwidth=1,-                                  fir_design='firwin'))-+                                  fir_design='firwin'), +          sampling_freq=raw.info['sfreq'], picks=picks)+#%%

You are probably right because it is the way the thing is defined also in SPoC, now that I think of it. I suspect however, that results would look very similar while some time could be saved. We can try/benchmark at a later point in time. Let's first move on with the other points. Once that is done and we are happy we can add the SSD class to a proper module and write unit tests.

vpeterson

comment created time in 4 days

PullRequestReviewEvent

PR opened mne-tools/mne-python

DOC: add literature reference for apply_inverse_cov

This PR adds a reference for the recently introduced apply_inverse_covfunction.

cc @agramfort

+21 -1

0 comment

2 changed files

pr created time in 4 days

create barnchdengemann/mne-python

branch : references

created branch time in 4 days

Pull request review commentdengemann/mne-python

added option to handle epoched data, sort component with respect to s…

 def freq_mask(freqs, fmin, fmax): fname = data_path() + '/SubjectCMC.ds' raw = mne.io.read_raw_ctf(fname) raw.crop(50., 250.).load_data()  # crop for memory purposes+picks=mne.pick_types(raw.info, meg=True, eeg=False, ref_meg=False)+sf=raw.info['sfreq']  freqs_sig = 9, 12 freqs_noise = 8, 13   class SSD(BaseEstimator, TransformerMixin):-    """Implement Spatio-Spectral Decomposision+    """+    +    This is a Python Implementation of Spatio Spectral Decomposition (SSD) +    method [1],[2] for both raw and epoched data. This source code is  based on+    the matlab implementation available at +    https://github.com/svendaehne/matlab_SPoC/tree/master/SSD and the PR MNE-based+    implementation of Denis A. Engemann <denis.engemann@gmail.com>+    +    SSD seeks at maximizing the power at a frequency band of interest while+    simultaneously minimizing it at the flanking (surrounding) frequency bins+    (considered noise). It extremizes the covariance matrices associated to +    signal and noise.+    +    Cosidering f as the freq. of interest, noise signals can be calculated+    either by filtering the signals in the frequency range [f−Δfb:f+Δfb] and then +    performing band-stop filtering around frequency f [f−Δfs:f+Δfs], where Δfb+    and Δfs generally are set equal to 2 and 1 Hz, or by filtering +    in the frequency range [f−Δf:f+Δf] with the following subtraction of +    the filtered signal around f [1]. +    +    SSD can either be used as a dimentionality reduction method or a denoised +    ‘denoised’ low rank factorization method [2].+              Parameters     ----------     filt_params_signal : dict         Filtering for the frequencies of interst.     filt_params_noise  : dict         Filtering for the frequencies of non-interest.-    estimator : str-        Which covariance estimator to use. Defaults to "oas".-    n_components  : int, None-        How many components to keep. Default to 5.-    subtract_signal : bool-        Whether to subtract the noise from the signal to enhcane-        sptial filter.-    sort_by_spectral_ratio : bool-        Whether to sort by the spectral ratio. Defaults to True.-+    sampling_freq : float+        sampling frequency (in Hz) of the recordings.+    estimator : float | str | None (default 'oas')+        Which covariance estimator to use+        If not None (same as 'empirical'), allow regularization for+        covariance estimation. If float, shrinkage is used +        (0 <= shrinkage <= 1). For str options, estimator will be passed to method +        to mne.compute_covariance().    +    n_components : int| None (default None)+        The number of components to decompose the signals. +        If n_components is None no dimentionality reduction is made, and the +        transformed data is projected in the whole source space.+   picks: array| int | None  (default None)+       Indeces of good-channels. Can be the output of mne.pick_types+ +   sort_by_spectral_ratio: bool (default True)+       if set to True, the components are sorted according to the spectral ratio+       See [1] Nikulin 2011, Eq. (24)+       +   return_filtered : bool (default False)+        If return_filtered is True, data is bandpassed and projected onto +        the SSD components.+        +   n_fft: int (default None)+       if sort_by_spectral_ratio is set to True, then the sources will be sorted+       accordinly to their spectral ratio which is calculated based on +       "psd_array_welch" function. the n_fft set the length of FFT used.+       See mne.time_frequency.psd_array_welch for more information+    +   cov_method_params : TYPE, optional+        As in mne.decoding.SPoC +        The default is None.+   rank : None | dict | ‘info’ | ‘full’+        As in mne.decoding.SPoC +        This controls the rank computation that can be read from the+        measurement info or estimated from the data. +        See Notes of mne.compute_rank() for details.The default is None.+        The default is None.++    +    REFERENCES:+    [1] Nikulin, V. V., Nolte, G., & Curio, G. (2011). A novel method for +    reliable and fast extraction of neuronal EEG/MEG oscillations on the basis +    of spatio-spectral decomposition. NeuroImage, 55(4), 1528-1535.+    [2] Haufe, S., Dähne, S., & Nikulin, V. V. (2014). Dimensionality reduction+    for the analysis of brain oscillations. NeuroImage, 101, 583-597.+    +    +                 """ -    def __init__(self, filt_params_signal, filt_params_noise,-                 estimator='oas', n_components=None,-                 subtract_signal=True,-                 reject=None,-                 flat=None,-                 picks=None,-                 sort_by_spectral_ratio=True):+    def __init__(self, filt_params_signal, filt_params_noise, sampling_freq,+                 estimator='oas', n_components=None, picks=None,+                 sort_by_spectral_ratio=True, return_filtered=False, n_fft=None, cov_method_params=None, rank=None):+                 """Initialize instance"""          dicts = {"signal": filt_params_signal, "noise": filt_params_noise}         for param, dd in [('l', 0), ('h', 0), ('l', 1), ('h', 1)]:             key = ('signal', 'noise')[dd]             if  param + '_freq' not in dicts[key]:                 raise ValueError(-                    "'%' must be defined in filter parameters for %s" % key)+                    "'%%' must be defined in filter parameters for %s" % key)             val = dicts[key][param + '_freq']             if not isinstance(val, (int, float)):                 raise ValueError(                     "Frequencies must be numbers, got %s" % type(val))+       +          #check freq bands+        if (filt_params_noise['l_freq'] > filt_params_signal['l_freq'] or  +                filt_params_signal['h_freq']>filt_params_noise['h_freq']):+            raise ValueError('Wrongly specified frequency bands!\nThe signal band-pass must be within the t noise band-pass!')          self.freqs_signal = (filt_params_signal['l_freq'],                              filt_params_signal['h_freq'])         self.freqs_noise = (filt_params_noise['l_freq'],                             filt_params_noise['h_freq'])+        +        +                       self.filt_params_signal = filt_params_signal         self.filt_params_noise = filt_params_noise-        self.subtract_signal = subtract_signal-        self.picks = picks+        self.sort_by_spectral_ratio = sort_by_spectral_ratio+        if n_fft is None:+            self.n_fft= int(sampling_freq)+        else:+            self.n_fft=int(n_fft)+        self.picks_ = picks+        +        self.return_filtered=return_filtered+        +                self.estimator = estimator         self.n_components = n_components-+        self.rank = rank+        self.sampling_freq=sampling_freq      +        self.cov_method_params = cov_method_params+        +         def fit(self, inst):         """Fit"""-        if self.picks == None:-            self.picks_ = mne.pick_types(inst.info, meg=True, eeg=False, ref_meg=False)-        else:-            self.picks_ = self.picks-        if isinstance(inst, mne.io.base.BaseRaw):+        +        +        if isinstance(inst, BaseRaw):+            if self.picks_ is None:+                raise ValueError('picks should be provided')+            self.max_components=len(self.picks_)             inst_signal = inst.copy()             inst_signal.filter(picks=self.picks_, **self.filt_params_signal)-+            self.Xs=inst_signal+            #noise             inst_noise = inst.copy()             inst_noise.filter(picks=self.picks_, **self.filt_params_noise)-            if self.subtract_signal:-                inst_noise._data[self.picks_] -= inst_signal._data[self.picks_]-            cov_signal = mne.compute_raw_covariance(-                inst_signal, picks=self.picks_, method=self.estimator)-            cov_noise = mne.compute_raw_covariance(inst_noise, picks=self.picks_,-                method=self.estimator)+            # subtract signal:+            inst_noise._data[self.picks_] -= inst_signal._data[self.picks_]+           +            cov_signal = compute_raw_covariance(+                inst_signal, picks=self.picks_, method=self.estimator, rank=self.rank)+            cov_noise = compute_raw_covariance(inst_noise, picks=self.picks_,+                method=self.estimator, rank=self.rank)             del inst_noise             del inst_signal         else:-            raise NotImplementedError()+            if isinstance(inst, BaseEpochs)  or isinstance(inst, np.ndarray):+            # data X is epoched +            # part of the following code is copied from mne csp+                n_epochs, n_channels, n_samples = inst.shape+                self.max_components=n_channels+              +                #reshape for filtering+                X_aux=np.reshape(inst, [n_epochs, n_channels*n_samples])+                X_s=filter_data(X_aux, self.sampling_freq, **self.filt_params_signal)  +                +                #rephase for filtering+                X_aux=np.reshape(inst, [n_epochs, n_channels*n_samples])+                X_n=filter_data(X_aux, self.sampling_freq, **self.filt_params_noise)+                # subtract signal:+                X_n -= X_s+                +                # Estimate single trial covariance+                #reshape to original shape+                X_s=np.reshape(X_s, [n_epochs,n_channels,n_samples])+                self.Xs=X_s+                covs = np.empty((n_epochs, n_channels, n_channels))+                for ii, epoch in enumerate(X_s):+                    covs[ii] = _regularized_covariance(+                        epoch, reg=self.estimator, method_params=self.cov_method_params,+                        rank=self.rank)+                    +                cov_signal = covs.mean(0)+            +                #% Covariance matrix for the flanking frequencies (noise)+                        +                +                +                #reshape to original shape+                X_n=np.reshape(X_n, [n_epochs,n_channels,n_samples])+                # Estimate single trial covariance+                covs_n = np.empty((n_epochs, n_channels, n_channels))+                for ii, epoch in enumerate(X_n):+                    covs_n[ii] = _regularized_covariance(+                        epoch, reg=self.estimator, method_params=self.cov_method_params,+                        rank=self.rank)+        +                cov_noise = covs_n.mean(0)+                       +            +            else:+                raise NotImplementedError()+        +        eigvals_,eigvects_ = eigh(cov_signal.data, cov_noise.data)+        # #sort in descencing order+        ix = np.argsort(eigvals_)[::-1]+        self.eigvals_=eigvals_[ix]+        self.filters_ = eigvects_[:,ix]+        # self.filters_ = eigvects_++        self.patterns_ = np.linalg.pinv(self.filters_)      +             +                +        return self+ +    def spectral_ratio_ssd(self,ssd_sources):+        """Spectral ratio measure for best n_components selection+        See Nikulin 2011, Eq. (24)+        +        Parameters+        ----------+        ssd_sources : data projected on the SSD space. +        output of transform+       +        """+                  +            +        psd, freqs = psd_array_welch(+        ssd_sources, sfreq=self.sampling_freq, n_fft=self.n_fft)+        sig_idx = _time_mask(freqs, *self.freqs_signal)+        noise_idx = _time_mask(freqs, *self.freqs_noise)+        if psd.ndim ==3:+            spec_ratio = psd[:, :,sig_idx].mean(axis=2).mean(axis=0) / psd[:,:, noise_idx].mean(axis=2).mean(axis=0)  -        self.eigvals_, self.filters_ = eigh(cov_signal.data, cov_noise.data)-        self.patterns_ = np.linalg.pinv(self.filters_)--    def transform(self, data):-        if self.n_components is None:-            n_components = len(self.picks_)         else:-            n_components = self.n_components-        return np.dot(self.filters_.T[:n_components], data[self.picks_])+                    +            spec_ratio = psd[:, sig_idx].mean(axis=1) / psd[:, noise_idx].mean(axis=1)+        sorter_spec = spec_ratio.argsort()[::-1]+        return spec_ratio, sorter_spec++    def transform(self, inst):+        """Estimate epochs sources given the SSD filters.++        Parameters+        ----------+        inst : instance of Raw or Epochs (n_epochs, n_channels, n_times)+            The data to be processed. The instance is modified inplace.+       +        Returns+        -------+        out : instance of Raw or Epochs+            The processed data.+        +        """+        if self.filters_ is None:+            raise RuntimeError('No filters available. Please first call fit')+        if self.return_filtered:+            inst=self.Xs+        if isinstance(inst, BaseRaw):+            data=inst.get_data()+            X_ssd=np.dot(self.filters_.T, data[self.picks_])

whitespace

vpeterson

comment created time in 5 days

Pull request review commentdengemann/mne-python

added option to handle epoched data, sort component with respect to s…

 def freq_mask(freqs, fmin, fmax): fname = data_path() + '/SubjectCMC.ds' raw = mne.io.read_raw_ctf(fname) raw.crop(50., 250.).load_data()  # crop for memory purposes+picks=mne.pick_types(raw.info, meg=True, eeg=False, ref_meg=False)+sf=raw.info['sfreq']  freqs_sig = 9, 12 freqs_noise = 8, 13   class SSD(BaseEstimator, TransformerMixin):-    """Implement Spatio-Spectral Decomposision+    """+    +    This is a Python Implementation of Spatio Spectral Decomposition (SSD) +    method [1],[2] for both raw and epoched data. This source code is  based on+    the matlab implementation available at +    https://github.com/svendaehne/matlab_SPoC/tree/master/SSD and the PR MNE-based+    implementation of Denis A. Engemann <denis.engemann@gmail.com>+    +    SSD seeks at maximizing the power at a frequency band of interest while+    simultaneously minimizing it at the flanking (surrounding) frequency bins+    (considered noise). It extremizes the covariance matrices associated to +    signal and noise.+    +    Cosidering f as the freq. of interest, noise signals can be calculated+    either by filtering the signals in the frequency range [f−Δfb:f+Δfb] and then +    performing band-stop filtering around frequency f [f−Δfs:f+Δfs], where Δfb+    and Δfs generally are set equal to 2 and 1 Hz, or by filtering +    in the frequency range [f−Δf:f+Δf] with the following subtraction of +    the filtered signal around f [1]. +    +    SSD can either be used as a dimentionality reduction method or a denoised +    ‘denoised’ low rank factorization method [2].+              Parameters     ----------     filt_params_signal : dict         Filtering for the frequencies of interst.     filt_params_noise  : dict         Filtering for the frequencies of non-interest.-    estimator : str-        Which covariance estimator to use. Defaults to "oas".-    n_components  : int, None-        How many components to keep. Default to 5.-    subtract_signal : bool-        Whether to subtract the noise from the signal to enhcane-        sptial filter.-    sort_by_spectral_ratio : bool-        Whether to sort by the spectral ratio. Defaults to True.-+    sampling_freq : float+        sampling frequency (in Hz) of the recordings.+    estimator : float | str | None (default 'oas')+        Which covariance estimator to use+        If not None (same as 'empirical'), allow regularization for+        covariance estimation. If float, shrinkage is used +        (0 <= shrinkage <= 1). For str options, estimator will be passed to method +        to mne.compute_covariance().    +    n_components : int| None (default None)+        The number of components to decompose the signals. +        If n_components is None no dimentionality reduction is made, and the +        transformed data is projected in the whole source space.+   picks: array| int | None  (default None)+       Indeces of good-channels. Can be the output of mne.pick_types+ +   sort_by_spectral_ratio: bool (default True)+       if set to True, the components are sorted according to the spectral ratio+       See [1] Nikulin 2011, Eq. (24)+       +   return_filtered : bool (default False)+        If return_filtered is True, data is bandpassed and projected onto +        the SSD components.+        +   n_fft: int (default None)+       if sort_by_spectral_ratio is set to True, then the sources will be sorted+       accordinly to their spectral ratio which is calculated based on +       "psd_array_welch" function. the n_fft set the length of FFT used.+       See mne.time_frequency.psd_array_welch for more information+    +   cov_method_params : TYPE, optional+        As in mne.decoding.SPoC +        The default is None.+   rank : None | dict | ‘info’ | ‘full’+        As in mne.decoding.SPoC +        This controls the rank computation that can be read from the+        measurement info or estimated from the data. +        See Notes of mne.compute_rank() for details.The default is None.+        The default is None.++    +    REFERENCES:+    [1] Nikulin, V. V., Nolte, G., & Curio, G. (2011). A novel method for +    reliable and fast extraction of neuronal EEG/MEG oscillations on the basis +    of spatio-spectral decomposition. NeuroImage, 55(4), 1528-1535.+    [2] Haufe, S., Dähne, S., & Nikulin, V. V. (2014). Dimensionality reduction+    for the analysis of brain oscillations. NeuroImage, 101, 583-597.+    +    +                 """ -    def __init__(self, filt_params_signal, filt_params_noise,-                 estimator='oas', n_components=None,-                 subtract_signal=True,-                 reject=None,-                 flat=None,-                 picks=None,-                 sort_by_spectral_ratio=True):+    def __init__(self, filt_params_signal, filt_params_noise, sampling_freq,+                 estimator='oas', n_components=None, picks=None,+                 sort_by_spectral_ratio=True, return_filtered=False, n_fft=None, cov_method_params=None, rank=None):+                 """Initialize instance"""          dicts = {"signal": filt_params_signal, "noise": filt_params_noise}         for param, dd in [('l', 0), ('h', 0), ('l', 1), ('h', 1)]:             key = ('signal', 'noise')[dd]             if  param + '_freq' not in dicts[key]:                 raise ValueError(-                    "'%' must be defined in filter parameters for %s" % key)+                    "'%%' must be defined in filter parameters for %s" % key)             val = dicts[key][param + '_freq']             if not isinstance(val, (int, float)):                 raise ValueError(                     "Frequencies must be numbers, got %s" % type(val))+       +          #check freq bands+        if (filt_params_noise['l_freq'] > filt_params_signal['l_freq'] or  +                filt_params_signal['h_freq']>filt_params_noise['h_freq']):+            raise ValueError('Wrongly specified frequency bands!\nThe signal band-pass must be within the t noise band-pass!')          self.freqs_signal = (filt_params_signal['l_freq'],                              filt_params_signal['h_freq'])         self.freqs_noise = (filt_params_noise['l_freq'],                             filt_params_noise['h_freq'])+        +        +                       self.filt_params_signal = filt_params_signal         self.filt_params_noise = filt_params_noise-        self.subtract_signal = subtract_signal-        self.picks = picks+        self.sort_by_spectral_ratio = sort_by_spectral_ratio+        if n_fft is None:+            self.n_fft= int(sampling_freq)+        else:+            self.n_fft=int(n_fft)+        self.picks_ = picks+        +        self.return_filtered=return_filtered+        +                self.estimator = estimator         self.n_components = n_components-+        self.rank = rank+        self.sampling_freq=sampling_freq      +        self.cov_method_params = cov_method_params+        +         def fit(self, inst):         """Fit"""-        if self.picks == None:-            self.picks_ = mne.pick_types(inst.info, meg=True, eeg=False, ref_meg=False)-        else:-            self.picks_ = self.picks-        if isinstance(inst, mne.io.base.BaseRaw):+        +        +        if isinstance(inst, BaseRaw):+            if self.picks_ is None:+                raise ValueError('picks should be provided')+            self.max_components=len(self.picks_)             inst_signal = inst.copy()             inst_signal.filter(picks=self.picks_, **self.filt_params_signal)-+            self.Xs=inst_signal+            #noise             inst_noise = inst.copy()             inst_noise.filter(picks=self.picks_, **self.filt_params_noise)-            if self.subtract_signal:-                inst_noise._data[self.picks_] -= inst_signal._data[self.picks_]-            cov_signal = mne.compute_raw_covariance(-                inst_signal, picks=self.picks_, method=self.estimator)-            cov_noise = mne.compute_raw_covariance(inst_noise, picks=self.picks_,-                method=self.estimator)+            # subtract signal:+            inst_noise._data[self.picks_] -= inst_signal._data[self.picks_]+           +            cov_signal = compute_raw_covariance(+                inst_signal, picks=self.picks_, method=self.estimator, rank=self.rank)+            cov_noise = compute_raw_covariance(inst_noise, picks=self.picks_,+                method=self.estimator, rank=self.rank)             del inst_noise             del inst_signal         else:-            raise NotImplementedError()+            if isinstance(inst, BaseEpochs)  or isinstance(inst, np.ndarray):+            # data X is epoched +            # part of the following code is copied from mne csp+                n_epochs, n_channels, n_samples = inst.shape+                self.max_components=n_channels+              +                #reshape for filtering+                X_aux=np.reshape(inst, [n_epochs, n_channels*n_samples])+                X_s=filter_data(X_aux, self.sampling_freq, **self.filt_params_signal)  +                +                #rephase for filtering+                X_aux=np.reshape(inst, [n_epochs, n_channels*n_samples])+                X_n=filter_data(X_aux, self.sampling_freq, **self.filt_params_noise)+                # subtract signal:+                X_n -= X_s+                +                # Estimate single trial covariance+                #reshape to original shape+                X_s=np.reshape(X_s, [n_epochs,n_channels,n_samples])+                self.Xs=X_s+                covs = np.empty((n_epochs, n_channels, n_channels))+                for ii, epoch in enumerate(X_s):+                    covs[ii] = _regularized_covariance(+                        epoch, reg=self.estimator, method_params=self.cov_method_params,+                        rank=self.rank)+                    +                cov_signal = covs.mean(0)+            +                #% Covariance matrix for the flanking frequencies (noise)+                        +                +                +                #reshape to original shape+                X_n=np.reshape(X_n, [n_epochs,n_channels,n_samples])+                # Estimate single trial covariance+                covs_n = np.empty((n_epochs, n_channels, n_channels))+                for ii, epoch in enumerate(X_n):+                    covs_n[ii] = _regularized_covariance(+                        epoch, reg=self.estimator, method_params=self.cov_method_params,+                        rank=self.rank)+        +                cov_noise = covs_n.mean(0)+                       +            +            else:+                raise NotImplementedError()+        +        eigvals_,eigvects_ = eigh(cov_signal.data, cov_noise.data)+        # #sort in descencing order+        ix = np.argsort(eigvals_)[::-1]+        self.eigvals_=eigvals_[ix]+        self.filters_ = eigvects_[:,ix]+        # self.filters_ = eigvects_++        self.patterns_ = np.linalg.pinv(self.filters_)      +             +                +        return self+ +    def spectral_ratio_ssd(self,ssd_sources):+        """Spectral ratio measure for best n_components selection+        See Nikulin 2011, Eq. (24)+        +        Parameters+        ----------+        ssd_sources : data projected on the SSD space. +        output of transform+       +        """+                  +            +        psd, freqs = psd_array_welch(+        ssd_sources, sfreq=self.sampling_freq, n_fft=self.n_fft)+        sig_idx = _time_mask(freqs, *self.freqs_signal)+        noise_idx = _time_mask(freqs, *self.freqs_noise)+        if psd.ndim ==3:+            spec_ratio = psd[:, :,sig_idx].mean(axis=2).mean(axis=0) / psd[:,:, noise_idx].mean(axis=2).mean(axis=0)  -        self.eigvals_, self.filters_ = eigh(cov_signal.data, cov_noise.data)-        self.patterns_ = np.linalg.pinv(self.filters_)--    def transform(self, data):-        if self.n_components is None:-            n_components = len(self.picks_)         else:-            n_components = self.n_components-        return np.dot(self.filters_.T[:n_components], data[self.picks_])+                    +            spec_ratio = psd[:, sig_idx].mean(axis=1) / psd[:, noise_idx].mean(axis=1)+        sorter_spec = spec_ratio.argsort()[::-1]+        return spec_ratio, sorter_spec++    def transform(self, inst):+        """Estimate epochs sources given the SSD filters.++        Parameters+        ----------+        inst : instance of Raw or Epochs (n_epochs, n_channels, n_times)+            The data to be processed. The instance is modified inplace.+       +        Returns+        -------+        out : instance of Raw or Epochs+            The processed data.+        +        """+        if self.filters_ is None:+            raise RuntimeError('No filters available. Please first call fit')+        if self.return_filtered:+            inst=self.Xs+        if isinstance(inst, BaseRaw):+            data=inst.get_data()+            X_ssd=np.dot(self.filters_.T, data[self.picks_])+           +        else:+            if isinstance(inst, BaseEpochs)  or isinstance(inst, np.ndarray):+                +                data=inst    +                #project data on source space+                X_ssd = np.asarray([np.dot(self.filters_.T, epoch) for epoch in data])+        +        if self.sort_by_spectral_ratio:+            self.spec_ratio, self.sorter_spec=self.spectral_ratio_ssd(ssd_sources=X_ssd)+            self.filters_=self.filters_[:,self.sorter_spec]+            self.patterns_=self.patterns_[self.sorter_spec]++            if isinstance(inst, BaseRaw):+                X_ssd=X_ssd[self.sorter_spec]+            else:+                X_ssd=X_ssd[:,self.sorter_spec,:]+            if self.n_components is None:+                n_components = self.max_components+                return X_ssd+            else:+                n_components = self.n_components+                if isinstance(inst, BaseRaw):+                    X_ssd=X_ssd[:n_components]+                else:+                    X_ssd=X_ssd[:,:n_components,:]+       +    +    def apply(self, inst):+        """+        Remove selected components from the signal.+        This procedure will reconstruct M/EEG signals from which the dynamics +        described by the excluded components is subtracted (denoised by low-rank factorization). +        See [2]  Haufe et al. for more information.+        +        The data is processed in place.++        Parameters+        ----------+        inst : instance of Raw or Epochs +            The data to be processed. The instance is modified inplace.+       +       +        Returns+        -------+        out : instance of Raw or Epochs+            The processed data.+        +        """+        X_ssd=self.transform(inst)+       +        +        pick_patterns = self.patterns_[:self.n_components].T+        if isinstance(inst, BaseRaw):+            X=np.dot(pick_patterns, X_ssd) -    def apply(self, instance):-        pass+        else:+            if isinstance(inst, BaseEpochs):+                if not isinstance(inst, np.ndarray):+                    raise ValueError("X should be of type ndarray (got %s)." % type(inst))+                X=np.asarray([np.dot(pick_patterns, epoch) for epoch in X_ssd])

Probably it would be better to pre-allocate the output array and add the results step by step.

vpeterson

comment created time in 5 days

Pull request review commentdengemann/mne-python

added option to handle epoched data, sort component with respect to s…

 def spectral_ratio_ssd(psd, freqs, freqs_sig, freqs_noise):                                   fir_design='firwin'),           filt_params_noise=dict(l_freq=freqs_noise[0], h_freq=freqs_noise[1],                                   l_trans_bandwidth=1, h_trans_bandwidth=1,-                                  fir_design='firwin'))-+                                  fir_design='firwin'), +          sampling_freq=raw.info['sfreq'], picks=picks)+#%%

these comments/directives should not be there. also see the ones below.

vpeterson

comment created time in 5 days

Pull request review commentdengemann/mne-python

added option to handle epoched data, sort component with respect to s…

 def freq_mask(freqs, fmin, fmax): fname = data_path() + '/SubjectCMC.ds' raw = mne.io.read_raw_ctf(fname) raw.crop(50., 250.).load_data()  # crop for memory purposes+picks=mne.pick_types(raw.info, meg=True, eeg=False, ref_meg=False)+sf=raw.info['sfreq']  freqs_sig = 9, 12 freqs_noise = 8, 13   class SSD(BaseEstimator, TransformerMixin):-    """Implement Spatio-Spectral Decomposision+    """+    +    This is a Python Implementation of Spatio Spectral Decomposition (SSD) +    method [1],[2] for both raw and epoched data. This source code is  based on+    the matlab implementation available at +    https://github.com/svendaehne/matlab_SPoC/tree/master/SSD and the PR MNE-based+    implementation of Denis A. Engemann <denis.engemann@gmail.com>+    +    SSD seeks at maximizing the power at a frequency band of interest while+    simultaneously minimizing it at the flanking (surrounding) frequency bins+    (considered noise). It extremizes the covariance matrices associated to +    signal and noise.+    +    Cosidering f as the freq. of interest, noise signals can be calculated+    either by filtering the signals in the frequency range [f−Δfb:f+Δfb] and then +    performing band-stop filtering around frequency f [f−Δfs:f+Δfs], where Δfb+    and Δfs generally are set equal to 2 and 1 Hz, or by filtering +    in the frequency range [f−Δf:f+Δf] with the following subtraction of +    the filtered signal around f [1]. +    +    SSD can either be used as a dimentionality reduction method or a denoised +    ‘denoised’ low rank factorization method [2].+              Parameters     ----------     filt_params_signal : dict         Filtering for the frequencies of interst.     filt_params_noise  : dict         Filtering for the frequencies of non-interest.-    estimator : str-        Which covariance estimator to use. Defaults to "oas".-    n_components  : int, None-        How many components to keep. Default to 5.-    subtract_signal : bool-        Whether to subtract the noise from the signal to enhcane-        sptial filter.-    sort_by_spectral_ratio : bool-        Whether to sort by the spectral ratio. Defaults to True.-+    sampling_freq : float+        sampling frequency (in Hz) of the recordings.+    estimator : float | str | None (default 'oas')+        Which covariance estimator to use+        If not None (same as 'empirical'), allow regularization for+        covariance estimation. If float, shrinkage is used +        (0 <= shrinkage <= 1). For str options, estimator will be passed to method +        to mne.compute_covariance().    +    n_components : int| None (default None)+        The number of components to decompose the signals. +        If n_components is None no dimentionality reduction is made, and the +        transformed data is projected in the whole source space.+   picks: array| int | None  (default None)+       Indeces of good-channels. Can be the output of mne.pick_types+ +   sort_by_spectral_ratio: bool (default True)+       if set to True, the components are sorted according to the spectral ratio+       See [1] Nikulin 2011, Eq. (24)+       +   return_filtered : bool (default False)+        If return_filtered is True, data is bandpassed and projected onto +        the SSD components.+        +   n_fft: int (default None)+       if sort_by_spectral_ratio is set to True, then the sources will be sorted+       accordinly to their spectral ratio which is calculated based on +       "psd_array_welch" function. the n_fft set the length of FFT used.+       See mne.time_frequency.psd_array_welch for more information+    +   cov_method_params : TYPE, optional+        As in mne.decoding.SPoC +        The default is None.+   rank : None | dict | ‘info’ | ‘full’+        As in mne.decoding.SPoC +        This controls the rank computation that can be read from the+        measurement info or estimated from the data. +        See Notes of mne.compute_rank() for details.The default is None.+        The default is None.++    +    REFERENCES:+    [1] Nikulin, V. V., Nolte, G., & Curio, G. (2011). A novel method for +    reliable and fast extraction of neuronal EEG/MEG oscillations on the basis +    of spatio-spectral decomposition. NeuroImage, 55(4), 1528-1535.+    [2] Haufe, S., Dähne, S., & Nikulin, V. V. (2014). Dimensionality reduction+    for the analysis of brain oscillations. NeuroImage, 101, 583-597.+    +    +                 """ -    def __init__(self, filt_params_signal, filt_params_noise,-                 estimator='oas', n_components=None,-                 subtract_signal=True,-                 reject=None,-                 flat=None,-                 picks=None,-                 sort_by_spectral_ratio=True):+    def __init__(self, filt_params_signal, filt_params_noise, sampling_freq,+                 estimator='oas', n_components=None, picks=None,+                 sort_by_spectral_ratio=True, return_filtered=False, n_fft=None, cov_method_params=None, rank=None):+                 """Initialize instance"""          dicts = {"signal": filt_params_signal, "noise": filt_params_noise}         for param, dd in [('l', 0), ('h', 0), ('l', 1), ('h', 1)]:             key = ('signal', 'noise')[dd]             if  param + '_freq' not in dicts[key]:                 raise ValueError(-                    "'%' must be defined in filter parameters for %s" % key)+                    "'%%' must be defined in filter parameters for %s" % key)             val = dicts[key][param + '_freq']             if not isinstance(val, (int, float)):                 raise ValueError(                     "Frequencies must be numbers, got %s" % type(val))+       +          #check freq bands+        if (filt_params_noise['l_freq'] > filt_params_signal['l_freq'] or  +                filt_params_signal['h_freq']>filt_params_noise['h_freq']):+            raise ValueError('Wrongly specified frequency bands!\nThe signal band-pass must be within the t noise band-pass!')          self.freqs_signal = (filt_params_signal['l_freq'],                              filt_params_signal['h_freq'])         self.freqs_noise = (filt_params_noise['l_freq'],                             filt_params_noise['h_freq'])+        +        +                       self.filt_params_signal = filt_params_signal         self.filt_params_noise = filt_params_noise-        self.subtract_signal = subtract_signal-        self.picks = picks+        self.sort_by_spectral_ratio = sort_by_spectral_ratio+        if n_fft is None:+            self.n_fft= int(sampling_freq)+        else:+            self.n_fft=int(n_fft)+        self.picks_ = picks+        +        self.return_filtered=return_filtered+        +                self.estimator = estimator         self.n_components = n_components-+        self.rank = rank+        self.sampling_freq=sampling_freq      +        self.cov_method_params = cov_method_params+        +         def fit(self, inst):         """Fit"""-        if self.picks == None:-            self.picks_ = mne.pick_types(inst.info, meg=True, eeg=False, ref_meg=False)-        else:-            self.picks_ = self.picks-        if isinstance(inst, mne.io.base.BaseRaw):+        +        +        if isinstance(inst, BaseRaw):+            if self.picks_ is None:+                raise ValueError('picks should be provided')+            self.max_components=len(self.picks_)             inst_signal = inst.copy()             inst_signal.filter(picks=self.picks_, **self.filt_params_signal)-+            self.Xs=inst_signal+            #noise             inst_noise = inst.copy()             inst_noise.filter(picks=self.picks_, **self.filt_params_noise)-            if self.subtract_signal:-                inst_noise._data[self.picks_] -= inst_signal._data[self.picks_]-            cov_signal = mne.compute_raw_covariance(-                inst_signal, picks=self.picks_, method=self.estimator)-            cov_noise = mne.compute_raw_covariance(inst_noise, picks=self.picks_,-                method=self.estimator)+            # subtract signal:+            inst_noise._data[self.picks_] -= inst_signal._data[self.picks_]+           +            cov_signal = compute_raw_covariance(+                inst_signal, picks=self.picks_, method=self.estimator, rank=self.rank)+            cov_noise = compute_raw_covariance(inst_noise, picks=self.picks_,+                method=self.estimator, rank=self.rank)             del inst_noise             del inst_signal         else:-            raise NotImplementedError()+            if isinstance(inst, BaseEpochs)  or isinstance(inst, np.ndarray):+            # data X is epoched +            # part of the following code is copied from mne csp+                n_epochs, n_channels, n_samples = inst.shape+                self.max_components=n_channels+              +                #reshape for filtering+                X_aux=np.reshape(inst, [n_epochs, n_channels*n_samples])+                X_s=filter_data(X_aux, self.sampling_freq, **self.filt_params_signal)  +                +                #rephase for filtering+                X_aux=np.reshape(inst, [n_epochs, n_channels*n_samples])+                X_n=filter_data(X_aux, self.sampling_freq, **self.filt_params_noise)+                # subtract signal:+                X_n -= X_s+                +                # Estimate single trial covariance+                #reshape to original shape+                X_s=np.reshape(X_s, [n_epochs,n_channels,n_samples])+                self.Xs=X_s+                covs = np.empty((n_epochs, n_channels, n_channels))+                for ii, epoch in enumerate(X_s):+                    covs[ii] = _regularized_covariance(+                        epoch, reg=self.estimator, method_params=self.cov_method_params,+                        rank=self.rank)+                    +                cov_signal = covs.mean(0)+            +                #% Covariance matrix for the flanking frequencies (noise)+                        +                +                +                #reshape to original shape+                X_n=np.reshape(X_n, [n_epochs,n_channels,n_samples])+                # Estimate single trial covariance+                covs_n = np.empty((n_epochs, n_channels, n_channels))+                for ii, epoch in enumerate(X_n):+                    covs_n[ii] = _regularized_covariance(+                        epoch, reg=self.estimator, method_params=self.cov_method_params,+                        rank=self.rank)+        +                cov_noise = covs_n.mean(0)+                       +            +            else:+                raise NotImplementedError()+        +        eigvals_,eigvects_ = eigh(cov_signal.data, cov_noise.data)+        # #sort in descencing order+        ix = np.argsort(eigvals_)[::-1]+        self.eigvals_=eigvals_[ix]+        self.filters_ = eigvects_[:,ix]+        # self.filters_ = eigvects_++        self.patterns_ = np.linalg.pinv(self.filters_)      +             +                +        return self+ +    def spectral_ratio_ssd(self,ssd_sources):+        """Spectral ratio measure for best n_components selection+        See Nikulin 2011, Eq. (24)+        +        Parameters+        ----------+        ssd_sources : data projected on the SSD space. +        output of transform+       +        """+                  +            +        psd, freqs = psd_array_welch(+        ssd_sources, sfreq=self.sampling_freq, n_fft=self.n_fft)+        sig_idx = _time_mask(freqs, *self.freqs_signal)+        noise_idx = _time_mask(freqs, *self.freqs_noise)+        if psd.ndim ==3:+            spec_ratio = psd[:, :,sig_idx].mean(axis=2).mean(axis=0) / psd[:,:, noise_idx].mean(axis=2).mean(axis=0)  -        self.eigvals_, self.filters_ = eigh(cov_signal.data, cov_noise.data)-        self.patterns_ = np.linalg.pinv(self.filters_)--    def transform(self, data):-        if self.n_components is None:-            n_components = len(self.picks_)         else:-            n_components = self.n_components-        return np.dot(self.filters_.T[:n_components], data[self.picks_])+                    +            spec_ratio = psd[:, sig_idx].mean(axis=1) / psd[:, noise_idx].mean(axis=1)+        sorter_spec = spec_ratio.argsort()[::-1]+        return spec_ratio, sorter_spec++    def transform(self, inst):+        """Estimate epochs sources given the SSD filters.++        Parameters+        ----------+        inst : instance of Raw or Epochs (n_epochs, n_channels, n_times)+            The data to be processed. The instance is modified inplace.+       +        Returns+        -------+        out : instance of Raw or Epochs+            The processed data.+        +        """+        if self.filters_ is None:+            raise RuntimeError('No filters available. Please first call fit')+        if self.return_filtered:+            inst=self.Xs+        if isinstance(inst, BaseRaw):+            data=inst.get_data()+            X_ssd=np.dot(self.filters_.T, data[self.picks_])+           +        else:+            if isinstance(inst, BaseEpochs)  or isinstance(inst, np.ndarray):+                +                data=inst    +                #project data on source space+                X_ssd = np.asarray([np.dot(self.filters_.T, epoch) for epoch in data])+        +        if self.sort_by_spectral_ratio:+            self.spec_ratio, self.sorter_spec=self.spectral_ratio_ssd(ssd_sources=X_ssd)+            self.filters_=self.filters_[:,self.sorter_spec]+            self.patterns_=self.patterns_[self.sorter_spec]++            if isinstance(inst, BaseRaw):+                X_ssd=X_ssd[self.sorter_spec]+            else:+                X_ssd=X_ssd[:,self.sorter_spec,:]+            if self.n_components is None:+                n_components = self.max_components+                return X_ssd+            else:+                n_components = self.n_components+                if isinstance(inst, BaseRaw):+                    X_ssd=X_ssd[:n_components]+                else:+                    X_ssd=X_ssd[:,:n_components,:]+       +    +    def apply(self, inst):+        """+        Remove selected components from the signal.+        This procedure will reconstruct M/EEG signals from which the dynamics +        described by the excluded components is subtracted (denoised by low-rank factorization). +        See [2]  Haufe et al. for more information.+        +        The data is processed in place.++        Parameters+        ----------+        inst : instance of Raw or Epochs +            The data to be processed. The instance is modified inplace.+       +       +        Returns+        -------+        out : instance of Raw or Epochs+            The processed data.+        

unnecessary line

vpeterson

comment created time in 5 days

Pull request review commentdengemann/mne-python

added option to handle epoched data, sort component with respect to s…

 def freq_mask(freqs, fmin, fmax): fname = data_path() + '/SubjectCMC.ds' raw = mne.io.read_raw_ctf(fname) raw.crop(50., 250.).load_data()  # crop for memory purposes+picks=mne.pick_types(raw.info, meg=True, eeg=False, ref_meg=False)+sf=raw.info['sfreq']  freqs_sig = 9, 12 freqs_noise = 8, 13   class SSD(BaseEstimator, TransformerMixin):-    """Implement Spatio-Spectral Decomposision+    """+    +    This is a Python Implementation of Spatio Spectral Decomposition (SSD) +    method [1],[2] for both raw and epoched data. This source code is  based on+    the matlab implementation available at +    https://github.com/svendaehne/matlab_SPoC/tree/master/SSD and the PR MNE-based+    implementation of Denis A. Engemann <denis.engemann@gmail.com>+    +    SSD seeks at maximizing the power at a frequency band of interest while+    simultaneously minimizing it at the flanking (surrounding) frequency bins+    (considered noise). It extremizes the covariance matrices associated to +    signal and noise.+    +    Cosidering f as the freq. of interest, noise signals can be calculated+    either by filtering the signals in the frequency range [f−Δfb:f+Δfb] and then +    performing band-stop filtering around frequency f [f−Δfs:f+Δfs], where Δfb+    and Δfs generally are set equal to 2 and 1 Hz, or by filtering +    in the frequency range [f−Δf:f+Δf] with the following subtraction of +    the filtered signal around f [1]. +    +    SSD can either be used as a dimentionality reduction method or a denoised +    ‘denoised’ low rank factorization method [2].+              Parameters     ----------     filt_params_signal : dict         Filtering for the frequencies of interst.     filt_params_noise  : dict         Filtering for the frequencies of non-interest.-    estimator : str-        Which covariance estimator to use. Defaults to "oas".-    n_components  : int, None-        How many components to keep. Default to 5.-    subtract_signal : bool-        Whether to subtract the noise from the signal to enhcane-        sptial filter.-    sort_by_spectral_ratio : bool-        Whether to sort by the spectral ratio. Defaults to True.-+    sampling_freq : float+        sampling frequency (in Hz) of the recordings.+    estimator : float | str | None (default 'oas')+        Which covariance estimator to use+        If not None (same as 'empirical'), allow regularization for+        covariance estimation. If float, shrinkage is used +        (0 <= shrinkage <= 1). For str options, estimator will be passed to method +        to mne.compute_covariance().    +    n_components : int| None (default None)+        The number of components to decompose the signals. +        If n_components is None no dimentionality reduction is made, and the +        transformed data is projected in the whole source space.+   picks: array| int | None  (default None)+       Indeces of good-channels. Can be the output of mne.pick_types+ +   sort_by_spectral_ratio: bool (default True)+       if set to True, the components are sorted according to the spectral ratio+       See [1] Nikulin 2011, Eq. (24)+       +   return_filtered : bool (default False)+        If return_filtered is True, data is bandpassed and projected onto +        the SSD components.+        +   n_fft: int (default None)+       if sort_by_spectral_ratio is set to True, then the sources will be sorted+       accordinly to their spectral ratio which is calculated based on +       "psd_array_welch" function. the n_fft set the length of FFT used.+       See mne.time_frequency.psd_array_welch for more information+    +   cov_method_params : TYPE, optional+        As in mne.decoding.SPoC +        The default is None.+   rank : None | dict | ‘info’ | ‘full’+        As in mne.decoding.SPoC +        This controls the rank computation that can be read from the+        measurement info or estimated from the data. +        See Notes of mne.compute_rank() for details.The default is None.+        The default is None.++    +    REFERENCES:+    [1] Nikulin, V. V., Nolte, G., & Curio, G. (2011). A novel method for +    reliable and fast extraction of neuronal EEG/MEG oscillations on the basis +    of spatio-spectral decomposition. NeuroImage, 55(4), 1528-1535.+    [2] Haufe, S., Dähne, S., & Nikulin, V. V. (2014). Dimensionality reduction+    for the analysis of brain oscillations. NeuroImage, 101, 583-597.+    +    +                 """ -    def __init__(self, filt_params_signal, filt_params_noise,-                 estimator='oas', n_components=None,-                 subtract_signal=True,-                 reject=None,-                 flat=None,-                 picks=None,-                 sort_by_spectral_ratio=True):+    def __init__(self, filt_params_signal, filt_params_noise, sampling_freq,+                 estimator='oas', n_components=None, picks=None,+                 sort_by_spectral_ratio=True, return_filtered=False, n_fft=None, cov_method_params=None, rank=None):+                 """Initialize instance"""          dicts = {"signal": filt_params_signal, "noise": filt_params_noise}         for param, dd in [('l', 0), ('h', 0), ('l', 1), ('h', 1)]:             key = ('signal', 'noise')[dd]             if  param + '_freq' not in dicts[key]:                 raise ValueError(-                    "'%' must be defined in filter parameters for %s" % key)+                    "'%%' must be defined in filter parameters for %s" % key)             val = dicts[key][param + '_freq']             if not isinstance(val, (int, float)):                 raise ValueError(                     "Frequencies must be numbers, got %s" % type(val))+       +          #check freq bands+        if (filt_params_noise['l_freq'] > filt_params_signal['l_freq'] or  +                filt_params_signal['h_freq']>filt_params_noise['h_freq']):+            raise ValueError('Wrongly specified frequency bands!\nThe signal band-pass must be within the t noise band-pass!')          self.freqs_signal = (filt_params_signal['l_freq'],                              filt_params_signal['h_freq'])         self.freqs_noise = (filt_params_noise['l_freq'],                             filt_params_noise['h_freq'])+        +        +                       self.filt_params_signal = filt_params_signal         self.filt_params_noise = filt_params_noise-        self.subtract_signal = subtract_signal-        self.picks = picks+        self.sort_by_spectral_ratio = sort_by_spectral_ratio+        if n_fft is None:+            self.n_fft= int(sampling_freq)+        else:+            self.n_fft=int(n_fft)+        self.picks_ = picks+        +        self.return_filtered=return_filtered+        +                self.estimator = estimator         self.n_components = n_components-+        self.rank = rank+        self.sampling_freq=sampling_freq      +        self.cov_method_params = cov_method_params+        +         def fit(self, inst):         """Fit"""-        if self.picks == None:-            self.picks_ = mne.pick_types(inst.info, meg=True, eeg=False, ref_meg=False)-        else:-            self.picks_ = self.picks-        if isinstance(inst, mne.io.base.BaseRaw):+        +        +        if isinstance(inst, BaseRaw):+            if self.picks_ is None:+                raise ValueError('picks should be provided')+            self.max_components=len(self.picks_)             inst_signal = inst.copy()             inst_signal.filter(picks=self.picks_, **self.filt_params_signal)-+            self.Xs=inst_signal+            #noise             inst_noise = inst.copy()             inst_noise.filter(picks=self.picks_, **self.filt_params_noise)-            if self.subtract_signal:-                inst_noise._data[self.picks_] -= inst_signal._data[self.picks_]-            cov_signal = mne.compute_raw_covariance(-                inst_signal, picks=self.picks_, method=self.estimator)-            cov_noise = mne.compute_raw_covariance(inst_noise, picks=self.picks_,-                method=self.estimator)+            # subtract signal:+            inst_noise._data[self.picks_] -= inst_signal._data[self.picks_]+           +            cov_signal = compute_raw_covariance(+                inst_signal, picks=self.picks_, method=self.estimator, rank=self.rank)+            cov_noise = compute_raw_covariance(inst_noise, picks=self.picks_,+                method=self.estimator, rank=self.rank)             del inst_noise             del inst_signal         else:-            raise NotImplementedError()+            if isinstance(inst, BaseEpochs)  or isinstance(inst, np.ndarray):+            # data X is epoched +            # part of the following code is copied from mne csp+                n_epochs, n_channels, n_samples = inst.shape+                self.max_components=n_channels+              +                #reshape for filtering+                X_aux=np.reshape(inst, [n_epochs, n_channels*n_samples])+                X_s=filter_data(X_aux, self.sampling_freq, **self.filt_params_signal)  +                +                #rephase for filtering+                X_aux=np.reshape(inst, [n_epochs, n_channels*n_samples])+                X_n=filter_data(X_aux, self.sampling_freq, **self.filt_params_noise)+                # subtract signal:+                X_n -= X_s+                +                # Estimate single trial covariance+                #reshape to original shape+                X_s=np.reshape(X_s, [n_epochs,n_channels,n_samples])+                self.Xs=X_s+                covs = np.empty((n_epochs, n_channels, n_channels))+                for ii, epoch in enumerate(X_s):+                    covs[ii] = _regularized_covariance(+                        epoch, reg=self.estimator, method_params=self.cov_method_params,+                        rank=self.rank)+                    +                cov_signal = covs.mean(0)+            +                #% Covariance matrix for the flanking frequencies (noise)+                        +                +                +                #reshape to original shape+                X_n=np.reshape(X_n, [n_epochs,n_channels,n_samples])+                # Estimate single trial covariance+                covs_n = np.empty((n_epochs, n_channels, n_channels))+                for ii, epoch in enumerate(X_n):+                    covs_n[ii] = _regularized_covariance(+                        epoch, reg=self.estimator, method_params=self.cov_method_params,+                        rank=self.rank)+        +                cov_noise = covs_n.mean(0)+                       +            +            else:+                raise NotImplementedError()+        +        eigvals_,eigvects_ = eigh(cov_signal.data, cov_noise.data)+        # #sort in descencing order+        ix = np.argsort(eigvals_)[::-1]+        self.eigvals_=eigvals_[ix]+        self.filters_ = eigvects_[:,ix]+        # self.filters_ = eigvects_++        self.patterns_ = np.linalg.pinv(self.filters_)      +             +                +        return self+ +    def spectral_ratio_ssd(self,ssd_sources):+        """Spectral ratio measure for best n_components selection+        See Nikulin 2011, Eq. (24)+        +        Parameters+        ----------+        ssd_sources : data projected on the SSD space. +        output of transform+       +        """+                  +            +        psd, freqs = psd_array_welch(+        ssd_sources, sfreq=self.sampling_freq, n_fft=self.n_fft)+        sig_idx = _time_mask(freqs, *self.freqs_signal)+        noise_idx = _time_mask(freqs, *self.freqs_noise)+        if psd.ndim ==3:

whitespace

vpeterson

comment created time in 5 days

Pull request review commentdengemann/mne-python

added option to handle epoched data, sort component with respect to s…

 def freq_mask(freqs, fmin, fmax): fname = data_path() + '/SubjectCMC.ds' raw = mne.io.read_raw_ctf(fname) raw.crop(50., 250.).load_data()  # crop for memory purposes+picks=mne.pick_types(raw.info, meg=True, eeg=False, ref_meg=False)+sf=raw.info['sfreq']  freqs_sig = 9, 12 freqs_noise = 8, 13   class SSD(BaseEstimator, TransformerMixin):-    """Implement Spatio-Spectral Decomposision+    """+    +    This is a Python Implementation of Spatio Spectral Decomposition (SSD) +    method [1],[2] for both raw and epoched data. This source code is  based on+    the matlab implementation available at +    https://github.com/svendaehne/matlab_SPoC/tree/master/SSD and the PR MNE-based+    implementation of Denis A. Engemann <denis.engemann@gmail.com>+    +    SSD seeks at maximizing the power at a frequency band of interest while+    simultaneously minimizing it at the flanking (surrounding) frequency bins+    (considered noise). It extremizes the covariance matrices associated to +    signal and noise.+    +    Cosidering f as the freq. of interest, noise signals can be calculated+    either by filtering the signals in the frequency range [f−Δfb:f+Δfb] and then +    performing band-stop filtering around frequency f [f−Δfs:f+Δfs], where Δfb+    and Δfs generally are set equal to 2 and 1 Hz, or by filtering +    in the frequency range [f−Δf:f+Δf] with the following subtraction of +    the filtered signal around f [1]. +    +    SSD can either be used as a dimentionality reduction method or a denoised +    ‘denoised’ low rank factorization method [2].+              Parameters     ----------     filt_params_signal : dict         Filtering for the frequencies of interst.     filt_params_noise  : dict         Filtering for the frequencies of non-interest.-    estimator : str-        Which covariance estimator to use. Defaults to "oas".-    n_components  : int, None-        How many components to keep. Default to 5.-    subtract_signal : bool-        Whether to subtract the noise from the signal to enhcane-        sptial filter.-    sort_by_spectral_ratio : bool-        Whether to sort by the spectral ratio. Defaults to True.-+    sampling_freq : float+        sampling frequency (in Hz) of the recordings.+    estimator : float | str | None (default 'oas')+        Which covariance estimator to use+        If not None (same as 'empirical'), allow regularization for+        covariance estimation. If float, shrinkage is used +        (0 <= shrinkage <= 1). For str options, estimator will be passed to method +        to mne.compute_covariance().    +    n_components : int| None (default None)+        The number of components to decompose the signals. +        If n_components is None no dimentionality reduction is made, and the +        transformed data is projected in the whole source space.+   picks: array| int | None  (default None)+       Indeces of good-channels. Can be the output of mne.pick_types+ +   sort_by_spectral_ratio: bool (default True)+       if set to True, the components are sorted according to the spectral ratio+       See [1] Nikulin 2011, Eq. (24)+       +   return_filtered : bool (default False)+        If return_filtered is True, data is bandpassed and projected onto +        the SSD components.+        +   n_fft: int (default None)+       if sort_by_spectral_ratio is set to True, then the sources will be sorted+       accordinly to their spectral ratio which is calculated based on +       "psd_array_welch" function. the n_fft set the length of FFT used.+       See mne.time_frequency.psd_array_welch for more information+    +   cov_method_params : TYPE, optional+        As in mne.decoding.SPoC +        The default is None.+   rank : None | dict | ‘info’ | ‘full’+        As in mne.decoding.SPoC +        This controls the rank computation that can be read from the+        measurement info or estimated from the data. +        See Notes of mne.compute_rank() for details.The default is None.+        The default is None.++    +    REFERENCES:+    [1] Nikulin, V. V., Nolte, G., & Curio, G. (2011). A novel method for +    reliable and fast extraction of neuronal EEG/MEG oscillations on the basis +    of spatio-spectral decomposition. NeuroImage, 55(4), 1528-1535.+    [2] Haufe, S., Dähne, S., & Nikulin, V. V. (2014). Dimensionality reduction+    for the analysis of brain oscillations. NeuroImage, 101, 583-597.+    +    +                 """ -    def __init__(self, filt_params_signal, filt_params_noise,-                 estimator='oas', n_components=None,-                 subtract_signal=True,-                 reject=None,-                 flat=None,-                 picks=None,-                 sort_by_spectral_ratio=True):+    def __init__(self, filt_params_signal, filt_params_noise, sampling_freq,+                 estimator='oas', n_components=None, picks=None,+                 sort_by_spectral_ratio=True, return_filtered=False, n_fft=None, cov_method_params=None, rank=None):+                 """Initialize instance"""          dicts = {"signal": filt_params_signal, "noise": filt_params_noise}         for param, dd in [('l', 0), ('h', 0), ('l', 1), ('h', 1)]:             key = ('signal', 'noise')[dd]             if  param + '_freq' not in dicts[key]:                 raise ValueError(-                    "'%' must be defined in filter parameters for %s" % key)+                    "'%%' must be defined in filter parameters for %s" % key)             val = dicts[key][param + '_freq']             if not isinstance(val, (int, float)):                 raise ValueError(                     "Frequencies must be numbers, got %s" % type(val))+       +          #check freq bands+        if (filt_params_noise['l_freq'] > filt_params_signal['l_freq'] or  +                filt_params_signal['h_freq']>filt_params_noise['h_freq']):+            raise ValueError('Wrongly specified frequency bands!\nThe signal band-pass must be within the t noise band-pass!')          self.freqs_signal = (filt_params_signal['l_freq'],                              filt_params_signal['h_freq'])         self.freqs_noise = (filt_params_noise['l_freq'],                             filt_params_noise['h_freq'])+        +        +                       self.filt_params_signal = filt_params_signal         self.filt_params_noise = filt_params_noise-        self.subtract_signal = subtract_signal-        self.picks = picks+        self.sort_by_spectral_ratio = sort_by_spectral_ratio+        if n_fft is None:+            self.n_fft= int(sampling_freq)+        else:+            self.n_fft=int(n_fft)+        self.picks_ = picks+        +        self.return_filtered=return_filtered+        +                self.estimator = estimator         self.n_components = n_components-+        self.rank = rank+        self.sampling_freq=sampling_freq      +        self.cov_method_params = cov_method_params+        +         def fit(self, inst):         """Fit"""-        if self.picks == None:-            self.picks_ = mne.pick_types(inst.info, meg=True, eeg=False, ref_meg=False)-        else:-            self.picks_ = self.picks-        if isinstance(inst, mne.io.base.BaseRaw):+        +        +        if isinstance(inst, BaseRaw):+            if self.picks_ is None:+                raise ValueError('picks should be provided')+            self.max_components=len(self.picks_)             inst_signal = inst.copy()             inst_signal.filter(picks=self.picks_, **self.filt_params_signal)-+            self.Xs=inst_signal+            #noise             inst_noise = inst.copy()             inst_noise.filter(picks=self.picks_, **self.filt_params_noise)-            if self.subtract_signal:-                inst_noise._data[self.picks_] -= inst_signal._data[self.picks_]-            cov_signal = mne.compute_raw_covariance(-                inst_signal, picks=self.picks_, method=self.estimator)-            cov_noise = mne.compute_raw_covariance(inst_noise, picks=self.picks_,-                method=self.estimator)+            # subtract signal:+            inst_noise._data[self.picks_] -= inst_signal._data[self.picks_]+           +            cov_signal = compute_raw_covariance(+                inst_signal, picks=self.picks_, method=self.estimator, rank=self.rank)+            cov_noise = compute_raw_covariance(inst_noise, picks=self.picks_,+                method=self.estimator, rank=self.rank)             del inst_noise             del inst_signal         else:-            raise NotImplementedError()+            if isinstance(inst, BaseEpochs)  or isinstance(inst, np.ndarray):+            # data X is epoched +            # part of the following code is copied from mne csp+                n_epochs, n_channels, n_samples = inst.shape+                self.max_components=n_channels+              +                #reshape for filtering+                X_aux=np.reshape(inst, [n_epochs, n_channels*n_samples])+                X_s=filter_data(X_aux, self.sampling_freq, **self.filt_params_signal)  +                +                #rephase for filtering+                X_aux=np.reshape(inst, [n_epochs, n_channels*n_samples])+                X_n=filter_data(X_aux, self.sampling_freq, **self.filt_params_noise)+                # subtract signal:+                X_n -= X_s+                +                # Estimate single trial covariance+                #reshape to original shape+                X_s=np.reshape(X_s, [n_epochs,n_channels,n_samples])+                self.Xs=X_s+                covs = np.empty((n_epochs, n_channels, n_channels))+                for ii, epoch in enumerate(X_s):+                    covs[ii] = _regularized_covariance(+                        epoch, reg=self.estimator, method_params=self.cov_method_params,+                        rank=self.rank)+                    +                cov_signal = covs.mean(0)+            +                #% Covariance matrix for the flanking frequencies (noise)+                        +                +                +                #reshape to original shape+                X_n=np.reshape(X_n, [n_epochs,n_channels,n_samples])+                # Estimate single trial covariance+                covs_n = np.empty((n_epochs, n_channels, n_channels))+                for ii, epoch in enumerate(X_n):+                    covs_n[ii] = _regularized_covariance(+                        epoch, reg=self.estimator, method_params=self.cov_method_params,+                        rank=self.rank)+        +                cov_noise = covs_n.mean(0)+                       +            +            else:+                raise NotImplementedError()+        +        eigvals_,eigvects_ = eigh(cov_signal.data, cov_noise.data)+        # #sort in descencing order+        ix = np.argsort(eigvals_)[::-1]+        self.eigvals_=eigvals_[ix]+        self.filters_ = eigvects_[:,ix]+        # self.filters_ = eigvects_++        self.patterns_ = np.linalg.pinv(self.filters_)      +             +                +        return self+ +    def spectral_ratio_ssd(self,ssd_sources):+        """Spectral ratio measure for best n_components selection+        See Nikulin 2011, Eq. (24)+        +        Parameters+        ----------+        ssd_sources : data projected on the SSD space. +        output of transform+       +        """+                  +            +        psd, freqs = psd_array_welch(+        ssd_sources, sfreq=self.sampling_freq, n_fft=self.n_fft)+        sig_idx = _time_mask(freqs, *self.freqs_signal)+        noise_idx = _time_mask(freqs, *self.freqs_noise)+        if psd.ndim ==3:+            spec_ratio = psd[:, :,sig_idx].mean(axis=2).mean(axis=0) / psd[:,:, noise_idx].mean(axis=2).mean(axis=0)  -        self.eigvals_, self.filters_ = eigh(cov_signal.data, cov_noise.data)-        self.patterns_ = np.linalg.pinv(self.filters_)--    def transform(self, data):-        if self.n_components is None:-            n_components = len(self.picks_)         else:-            n_components = self.n_components-        return np.dot(self.filters_.T[:n_components], data[self.picks_])+                    +            spec_ratio = psd[:, sig_idx].mean(axis=1) / psd[:, noise_idx].mean(axis=1)+        sorter_spec = spec_ratio.argsort()[::-1]+        return spec_ratio, sorter_spec++    def transform(self, inst):+        """Estimate epochs sources given the SSD filters.++        Parameters+        ----------+        inst : instance of Raw or Epochs (n_epochs, n_channels, n_times)+            The data to be processed. The instance is modified inplace.+       +        Returns+        -------+        out : instance of Raw or Epochs+            The processed data.+        +        """+        if self.filters_ is None:+            raise RuntimeError('No filters available. Please first call fit')+        if self.return_filtered:+            inst=self.Xs+        if isinstance(inst, BaseRaw):+            data=inst.get_data()+            X_ssd=np.dot(self.filters_.T, data[self.picks_])+           +        else:+            if isinstance(inst, BaseEpochs)  or isinstance(inst, np.ndarray):+                +                data=inst    +                #project data on source space+                X_ssd = np.asarray([np.dot(self.filters_.T, epoch) for epoch in data])+        +        if self.sort_by_spectral_ratio:+            self.spec_ratio, self.sorter_spec=self.spectral_ratio_ssd(ssd_sources=X_ssd)+            self.filters_=self.filters_[:,self.sorter_spec]+            self.patterns_=self.patterns_[self.sorter_spec]++            if isinstance(inst, BaseRaw):+                X_ssd=X_ssd[self.sorter_spec]

white spaces .. all the way done. Please ensure the style is respecting whitespace rules elswhere.

vpeterson

comment created time in 5 days

Pull request review commentdengemann/mne-python

added option to handle epoched data, sort component with respect to s…

 def freq_mask(freqs, fmin, fmax): fname = data_path() + '/SubjectCMC.ds' raw = mne.io.read_raw_ctf(fname) raw.crop(50., 250.).load_data()  # crop for memory purposes+picks=mne.pick_types(raw.info, meg=True, eeg=False, ref_meg=False)+sf=raw.info['sfreq']  freqs_sig = 9, 12 freqs_noise = 8, 13   class SSD(BaseEstimator, TransformerMixin):-    """Implement Spatio-Spectral Decomposision+    """+    +    This is a Python Implementation of Spatio Spectral Decomposition (SSD) +    method [1],[2] for both raw and epoched data. This source code is  based on+    the matlab implementation available at +    https://github.com/svendaehne/matlab_SPoC/tree/master/SSD and the PR MNE-based+    implementation of Denis A. Engemann <denis.engemann@gmail.com>+    +    SSD seeks at maximizing the power at a frequency band of interest while+    simultaneously minimizing it at the flanking (surrounding) frequency bins+    (considered noise). It extremizes the covariance matrices associated to +    signal and noise.+    +    Cosidering f as the freq. of interest, noise signals can be calculated+    either by filtering the signals in the frequency range [f−Δfb:f+Δfb] and then +    performing band-stop filtering around frequency f [f−Δfs:f+Δfs], where Δfb+    and Δfs generally are set equal to 2 and 1 Hz, or by filtering +    in the frequency range [f−Δf:f+Δf] with the following subtraction of +    the filtered signal around f [1]. +    +    SSD can either be used as a dimentionality reduction method or a denoised +    ‘denoised’ low rank factorization method [2].+              Parameters     ----------     filt_params_signal : dict         Filtering for the frequencies of interst.     filt_params_noise  : dict         Filtering for the frequencies of non-interest.-    estimator : str-        Which covariance estimator to use. Defaults to "oas".-    n_components  : int, None-        How many components to keep. Default to 5.-    subtract_signal : bool-        Whether to subtract the noise from the signal to enhcane-        sptial filter.-    sort_by_spectral_ratio : bool-        Whether to sort by the spectral ratio. Defaults to True.-+    sampling_freq : float+        sampling frequency (in Hz) of the recordings.+    estimator : float | str | None (default 'oas')+        Which covariance estimator to use+        If not None (same as 'empirical'), allow regularization for+        covariance estimation. If float, shrinkage is used +        (0 <= shrinkage <= 1). For str options, estimator will be passed to method +        to mne.compute_covariance().    +    n_components : int| None (default None)+        The number of components to decompose the signals. +        If n_components is None no dimentionality reduction is made, and the +        transformed data is projected in the whole source space.+   picks: array| int | None  (default None)+       Indeces of good-channels. Can be the output of mne.pick_types+ +   sort_by_spectral_ratio: bool (default True)+       if set to True, the components are sorted according to the spectral ratio+       See [1] Nikulin 2011, Eq. (24)+       +   return_filtered : bool (default False)+        If return_filtered is True, data is bandpassed and projected onto +        the SSD components.+        +   n_fft: int (default None)+       if sort_by_spectral_ratio is set to True, then the sources will be sorted+       accordinly to their spectral ratio which is calculated based on +       "psd_array_welch" function. the n_fft set the length of FFT used.+       See mne.time_frequency.psd_array_welch for more information+    +   cov_method_params : TYPE, optional+        As in mne.decoding.SPoC +        The default is None.+   rank : None | dict | ‘info’ | ‘full’+        As in mne.decoding.SPoC +        This controls the rank computation that can be read from the+        measurement info or estimated from the data. +        See Notes of mne.compute_rank() for details.The default is None.+        The default is None.++    +    REFERENCES:+    [1] Nikulin, V. V., Nolte, G., & Curio, G. (2011). A novel method for +    reliable and fast extraction of neuronal EEG/MEG oscillations on the basis +    of spatio-spectral decomposition. NeuroImage, 55(4), 1528-1535.+    [2] Haufe, S., Dähne, S., & Nikulin, V. V. (2014). Dimensionality reduction+    for the analysis of brain oscillations. NeuroImage, 101, 583-597.+    +    +                 """ -    def __init__(self, filt_params_signal, filt_params_noise,-                 estimator='oas', n_components=None,-                 subtract_signal=True,-                 reject=None,-                 flat=None,-                 picks=None,-                 sort_by_spectral_ratio=True):+    def __init__(self, filt_params_signal, filt_params_noise, sampling_freq,+                 estimator='oas', n_components=None, picks=None,+                 sort_by_spectral_ratio=True, return_filtered=False, n_fft=None, cov_method_params=None, rank=None):+                 """Initialize instance"""          dicts = {"signal": filt_params_signal, "noise": filt_params_noise}         for param, dd in [('l', 0), ('h', 0), ('l', 1), ('h', 1)]:             key = ('signal', 'noise')[dd]             if  param + '_freq' not in dicts[key]:                 raise ValueError(-                    "'%' must be defined in filter parameters for %s" % key)+                    "'%%' must be defined in filter parameters for %s" % key)             val = dicts[key][param + '_freq']             if not isinstance(val, (int, float)):                 raise ValueError(                     "Frequencies must be numbers, got %s" % type(val))+       +          #check freq bands+        if (filt_params_noise['l_freq'] > filt_params_signal['l_freq'] or  +                filt_params_signal['h_freq']>filt_params_noise['h_freq']):+            raise ValueError('Wrongly specified frequency bands!\nThe signal band-pass must be within the t noise band-pass!')          self.freqs_signal = (filt_params_signal['l_freq'],                              filt_params_signal['h_freq'])         self.freqs_noise = (filt_params_noise['l_freq'],                             filt_params_noise['h_freq'])+        +        +                       self.filt_params_signal = filt_params_signal         self.filt_params_noise = filt_params_noise-        self.subtract_signal = subtract_signal-        self.picks = picks+        self.sort_by_spectral_ratio = sort_by_spectral_ratio+        if n_fft is None:+            self.n_fft= int(sampling_freq)+        else:+            self.n_fft=int(n_fft)+        self.picks_ = picks+        +        self.return_filtered=return_filtered+        +                self.estimator = estimator         self.n_components = n_components-+        self.rank = rank+        self.sampling_freq=sampling_freq      +        self.cov_method_params = cov_method_params+        +         def fit(self, inst):         """Fit"""-        if self.picks == None:-            self.picks_ = mne.pick_types(inst.info, meg=True, eeg=False, ref_meg=False)-        else:-            self.picks_ = self.picks-        if isinstance(inst, mne.io.base.BaseRaw):+        +        +        if isinstance(inst, BaseRaw):+            if self.picks_ is None:+                raise ValueError('picks should be provided')+            self.max_components=len(self.picks_)             inst_signal = inst.copy()             inst_signal.filter(picks=self.picks_, **self.filt_params_signal)-+            self.Xs=inst_signal+            #noise             inst_noise = inst.copy()             inst_noise.filter(picks=self.picks_, **self.filt_params_noise)-            if self.subtract_signal:-                inst_noise._data[self.picks_] -= inst_signal._data[self.picks_]-            cov_signal = mne.compute_raw_covariance(-                inst_signal, picks=self.picks_, method=self.estimator)-            cov_noise = mne.compute_raw_covariance(inst_noise, picks=self.picks_,-                method=self.estimator)+            # subtract signal:+            inst_noise._data[self.picks_] -= inst_signal._data[self.picks_]+           +            cov_signal = compute_raw_covariance(+                inst_signal, picks=self.picks_, method=self.estimator, rank=self.rank)+            cov_noise = compute_raw_covariance(inst_noise, picks=self.picks_,+                method=self.estimator, rank=self.rank)             del inst_noise             del inst_signal         else:-            raise NotImplementedError()+            if isinstance(inst, BaseEpochs)  or isinstance(inst, np.ndarray):+            # data X is epoched +            # part of the following code is copied from mne csp+                n_epochs, n_channels, n_samples = inst.shape+                self.max_components=n_channels+              +                #reshape for filtering+                X_aux=np.reshape(inst, [n_epochs, n_channels*n_samples])+                X_s=filter_data(X_aux, self.sampling_freq, **self.filt_params_signal)  +                +                #rephase for filtering+                X_aux=np.reshape(inst, [n_epochs, n_channels*n_samples])+                X_n=filter_data(X_aux, self.sampling_freq, **self.filt_params_noise)+                # subtract signal:+                X_n -= X_s+                +                # Estimate single trial covariance+                #reshape to original shape+                X_s=np.reshape(X_s, [n_epochs,n_channels,n_samples])+                self.Xs=X_s+                covs = np.empty((n_epochs, n_channels, n_channels))+                for ii, epoch in enumerate(X_s):+                    covs[ii] = _regularized_covariance(+                        epoch, reg=self.estimator, method_params=self.cov_method_params,+                        rank=self.rank)+                    +                cov_signal = covs.mean(0)+            +                #% Covariance matrix for the flanking frequencies (noise)+                        +                +                +                #reshape to original shape+                X_n=np.reshape(X_n, [n_epochs,n_channels,n_samples])+                # Estimate single trial covariance+                covs_n = np.empty((n_epochs, n_channels, n_channels))+                for ii, epoch in enumerate(X_n):+                    covs_n[ii] = _regularized_covariance(+                        epoch, reg=self.estimator, method_params=self.cov_method_params,+                        rank=self.rank)+        +                cov_noise = covs_n.mean(0)+                       +            +            else:+                raise NotImplementedError()+        +        eigvals_,eigvects_ = eigh(cov_signal.data, cov_noise.data)+        # #sort in descencing order+        ix = np.argsort(eigvals_)[::-1]+        self.eigvals_=eigvals_[ix]+        self.filters_ = eigvects_[:,ix]+        # self.filters_ = eigvects_++        self.patterns_ = np.linalg.pinv(self.filters_)      +             +                +        return self+ +    def spectral_ratio_ssd(self,ssd_sources):+        """Spectral ratio measure for best n_components selection+        See Nikulin 2011, Eq. (24)+        +        Parameters+        ----------+        ssd_sources : data projected on the SSD space. +        output of transform+       +        """+                  +            +        psd, freqs = psd_array_welch(+        ssd_sources, sfreq=self.sampling_freq, n_fft=self.n_fft)+        sig_idx = _time_mask(freqs, *self.freqs_signal)+        noise_idx = _time_mask(freqs, *self.freqs_noise)+        if psd.ndim ==3:+            spec_ratio = psd[:, :,sig_idx].mean(axis=2).mean(axis=0) / psd[:,:, noise_idx].mean(axis=2).mean(axis=0)  -        self.eigvals_, self.filters_ = eigh(cov_signal.data, cov_noise.data)-        self.patterns_ = np.linalg.pinv(self.filters_)--    def transform(self, data):-        if self.n_components is None:-            n_components = len(self.picks_)         else:-            n_components = self.n_components-        return np.dot(self.filters_.T[:n_components], data[self.picks_])+                    +            spec_ratio = psd[:, sig_idx].mean(axis=1) / psd[:, noise_idx].mean(axis=1)+        sorter_spec = spec_ratio.argsort()[::-1]+        return spec_ratio, sorter_spec++    def transform(self, inst):+        """Estimate epochs sources given the SSD filters.++        Parameters+        ----------+        inst : instance of Raw or Epochs (n_epochs, n_channels, n_times)+            The data to be processed. The instance is modified inplace.+       +        Returns+        -------+        out : instance of Raw or Epochs+            The processed data.+        +        """+        if self.filters_ is None:+            raise RuntimeError('No filters available. Please first call fit')+        if self.return_filtered:+            inst=self.Xs+        if isinstance(inst, BaseRaw):+            data=inst.get_data()+            X_ssd=np.dot(self.filters_.T, data[self.picks_])+           +        else:+            if isinstance(inst, BaseEpochs)  or isinstance(inst, np.ndarray):+                

unneccesary line

vpeterson

comment created time in 5 days

Pull request review commentdengemann/mne-python

added option to handle epoched data, sort component with respect to s…

 def freq_mask(freqs, fmin, fmax): fname = data_path() + '/SubjectCMC.ds' raw = mne.io.read_raw_ctf(fname) raw.crop(50., 250.).load_data()  # crop for memory purposes+picks=mne.pick_types(raw.info, meg=True, eeg=False, ref_meg=False)+sf=raw.info['sfreq']  freqs_sig = 9, 12 freqs_noise = 8, 13   class SSD(BaseEstimator, TransformerMixin):-    """Implement Spatio-Spectral Decomposision+    """+    +    This is a Python Implementation of Spatio Spectral Decomposition (SSD) +    method [1],[2] for both raw and epoched data. This source code is  based on+    the matlab implementation available at +    https://github.com/svendaehne/matlab_SPoC/tree/master/SSD and the PR MNE-based+    implementation of Denis A. Engemann <denis.engemann@gmail.com>+    +    SSD seeks at maximizing the power at a frequency band of interest while+    simultaneously minimizing it at the flanking (surrounding) frequency bins+    (considered noise). It extremizes the covariance matrices associated to +    signal and noise.+    +    Cosidering f as the freq. of interest, noise signals can be calculated+    either by filtering the signals in the frequency range [f−Δfb:f+Δfb] and then +    performing band-stop filtering around frequency f [f−Δfs:f+Δfs], where Δfb+    and Δfs generally are set equal to 2 and 1 Hz, or by filtering +    in the frequency range [f−Δf:f+Δf] with the following subtraction of +    the filtered signal around f [1]. +    +    SSD can either be used as a dimentionality reduction method or a denoised +    ‘denoised’ low rank factorization method [2].+              Parameters     ----------     filt_params_signal : dict         Filtering for the frequencies of interst.     filt_params_noise  : dict         Filtering for the frequencies of non-interest.-    estimator : str-        Which covariance estimator to use. Defaults to "oas".-    n_components  : int, None-        How many components to keep. Default to 5.-    subtract_signal : bool-        Whether to subtract the noise from the signal to enhcane-        sptial filter.-    sort_by_spectral_ratio : bool-        Whether to sort by the spectral ratio. Defaults to True.-+    sampling_freq : float+        sampling frequency (in Hz) of the recordings.+    estimator : float | str | None (default 'oas')+        Which covariance estimator to use+        If not None (same as 'empirical'), allow regularization for+        covariance estimation. If float, shrinkage is used +        (0 <= shrinkage <= 1). For str options, estimator will be passed to method +        to mne.compute_covariance().    +    n_components : int| None (default None)+        The number of components to decompose the signals. +        If n_components is None no dimentionality reduction is made, and the +        transformed data is projected in the whole source space.+   picks: array| int | None  (default None)+       Indeces of good-channels. Can be the output of mne.pick_types+ +   sort_by_spectral_ratio: bool (default True)+       if set to True, the components are sorted according to the spectral ratio+       See [1] Nikulin 2011, Eq. (24)+       +   return_filtered : bool (default False)+        If return_filtered is True, data is bandpassed and projected onto +        the SSD components.+        +   n_fft: int (default None)+       if sort_by_spectral_ratio is set to True, then the sources will be sorted+       accordinly to their spectral ratio which is calculated based on +       "psd_array_welch" function. the n_fft set the length of FFT used.+       See mne.time_frequency.psd_array_welch for more information+    +   cov_method_params : TYPE, optional+        As in mne.decoding.SPoC +        The default is None.+   rank : None | dict | ‘info’ | ‘full’+        As in mne.decoding.SPoC +        This controls the rank computation that can be read from the+        measurement info or estimated from the data. +        See Notes of mne.compute_rank() for details.The default is None.+        The default is None.++    +    REFERENCES:+    [1] Nikulin, V. V., Nolte, G., & Curio, G. (2011). A novel method for +    reliable and fast extraction of neuronal EEG/MEG oscillations on the basis +    of spatio-spectral decomposition. NeuroImage, 55(4), 1528-1535.+    [2] Haufe, S., Dähne, S., & Nikulin, V. V. (2014). Dimensionality reduction+    for the analysis of brain oscillations. NeuroImage, 101, 583-597.+    +    +                 """ -    def __init__(self, filt_params_signal, filt_params_noise,-                 estimator='oas', n_components=None,-                 subtract_signal=True,-                 reject=None,-                 flat=None,-                 picks=None,-                 sort_by_spectral_ratio=True):+    def __init__(self, filt_params_signal, filt_params_noise, sampling_freq,+                 estimator='oas', n_components=None, picks=None,+                 sort_by_spectral_ratio=True, return_filtered=False, n_fft=None, cov_method_params=None, rank=None):+                 """Initialize instance"""          dicts = {"signal": filt_params_signal, "noise": filt_params_noise}         for param, dd in [('l', 0), ('h', 0), ('l', 1), ('h', 1)]:             key = ('signal', 'noise')[dd]             if  param + '_freq' not in dicts[key]:                 raise ValueError(-                    "'%' must be defined in filter parameters for %s" % key)+                    "'%%' must be defined in filter parameters for %s" % key)             val = dicts[key][param + '_freq']             if not isinstance(val, (int, float)):                 raise ValueError(                     "Frequencies must be numbers, got %s" % type(val))+       +          #check freq bands+        if (filt_params_noise['l_freq'] > filt_params_signal['l_freq'] or  +                filt_params_signal['h_freq']>filt_params_noise['h_freq']):+            raise ValueError('Wrongly specified frequency bands!\nThe signal band-pass must be within the t noise band-pass!')          self.freqs_signal = (filt_params_signal['l_freq'],                              filt_params_signal['h_freq'])         self.freqs_noise = (filt_params_noise['l_freq'],                             filt_params_noise['h_freq'])+        +        +                       self.filt_params_signal = filt_params_signal         self.filt_params_noise = filt_params_noise-        self.subtract_signal = subtract_signal-        self.picks = picks+        self.sort_by_spectral_ratio = sort_by_spectral_ratio+        if n_fft is None:+            self.n_fft= int(sampling_freq)+        else:+            self.n_fft=int(n_fft)+        self.picks_ = picks+        +        self.return_filtered=return_filtered+        +                self.estimator = estimator         self.n_components = n_components-+        self.rank = rank+        self.sampling_freq=sampling_freq      +        self.cov_method_params = cov_method_params+        +         def fit(self, inst):         """Fit"""-        if self.picks == None:-            self.picks_ = mne.pick_types(inst.info, meg=True, eeg=False, ref_meg=False)-        else:-            self.picks_ = self.picks-        if isinstance(inst, mne.io.base.BaseRaw):+        +        +        if isinstance(inst, BaseRaw):+            if self.picks_ is None:+                raise ValueError('picks should be provided')+            self.max_components=len(self.picks_)             inst_signal = inst.copy()             inst_signal.filter(picks=self.picks_, **self.filt_params_signal)-+            self.Xs=inst_signal+            #noise             inst_noise = inst.copy()             inst_noise.filter(picks=self.picks_, **self.filt_params_noise)-            if self.subtract_signal:-                inst_noise._data[self.picks_] -= inst_signal._data[self.picks_]-            cov_signal = mne.compute_raw_covariance(-                inst_signal, picks=self.picks_, method=self.estimator)-            cov_noise = mne.compute_raw_covariance(inst_noise, picks=self.picks_,-                method=self.estimator)+            # subtract signal:+            inst_noise._data[self.picks_] -= inst_signal._data[self.picks_]+           +            cov_signal = compute_raw_covariance(+                inst_signal, picks=self.picks_, method=self.estimator, rank=self.rank)+            cov_noise = compute_raw_covariance(inst_noise, picks=self.picks_,+                method=self.estimator, rank=self.rank)             del inst_noise             del inst_signal         else:-            raise NotImplementedError()+            if isinstance(inst, BaseEpochs)  or isinstance(inst, np.ndarray):+            # data X is epoched +            # part of the following code is copied from mne csp+                n_epochs, n_channels, n_samples = inst.shape+                self.max_components=n_channels+              +                #reshape for filtering+                X_aux=np.reshape(inst, [n_epochs, n_channels*n_samples])+                X_s=filter_data(X_aux, self.sampling_freq, **self.filt_params_signal)  +                +                #rephase for filtering+                X_aux=np.reshape(inst, [n_epochs, n_channels*n_samples])+                X_n=filter_data(X_aux, self.sampling_freq, **self.filt_params_noise)+                # subtract signal:+                X_n -= X_s+                +                # Estimate single trial covariance+                #reshape to original shape+                X_s=np.reshape(X_s, [n_epochs,n_channels,n_samples])+                self.Xs=X_s+                covs = np.empty((n_epochs, n_channels, n_channels))+                for ii, epoch in enumerate(X_s):+                    covs[ii] = _regularized_covariance(+                        epoch, reg=self.estimator, method_params=self.cov_method_params,+                        rank=self.rank)+                    +                cov_signal = covs.mean(0)+            +                #% Covariance matrix for the flanking frequencies (noise)+                        +                +                +                #reshape to original shape+                X_n=np.reshape(X_n, [n_epochs,n_channels,n_samples])+                # Estimate single trial covariance+                covs_n = np.empty((n_epochs, n_channels, n_channels))+                for ii, epoch in enumerate(X_n):+                    covs_n[ii] = _regularized_covariance(+                        epoch, reg=self.estimator, method_params=self.cov_method_params,+                        rank=self.rank)+        +                cov_noise = covs_n.mean(0)+                       +            +            else:+                raise NotImplementedError()+        +        eigvals_,eigvects_ = eigh(cov_signal.data, cov_noise.data)+        # #sort in descencing order+        ix = np.argsort(eigvals_)[::-1]+        self.eigvals_=eigvals_[ix]+        self.filters_ = eigvects_[:,ix]+        # self.filters_ = eigvects_++        self.patterns_ = np.linalg.pinv(self.filters_)      +             +                +        return self+ +    def spectral_ratio_ssd(self,ssd_sources):+        """Spectral ratio measure for best n_components selection+        See Nikulin 2011, Eq. (24)+        +        Parameters+        ----------+        ssd_sources : data projected on the SSD space. +        output of transform+       +        """+                  +            +        psd, freqs = psd_array_welch(+        ssd_sources, sfreq=self.sampling_freq, n_fft=self.n_fft)+        sig_idx = _time_mask(freqs, *self.freqs_signal)+        noise_idx = _time_mask(freqs, *self.freqs_noise)+        if psd.ndim ==3:+            spec_ratio = psd[:, :,sig_idx].mean(axis=2).mean(axis=0) / psd[:,:, noise_idx].mean(axis=2).mean(axis=0)  -        self.eigvals_, self.filters_ = eigh(cov_signal.data, cov_noise.data)-        self.patterns_ = np.linalg.pinv(self.filters_)--    def transform(self, data):-        if self.n_components is None:-            n_components = len(self.picks_)         else:-            n_components = self.n_components-        return np.dot(self.filters_.T[:n_components], data[self.picks_])+                    +            spec_ratio = psd[:, sig_idx].mean(axis=1) / psd[:, noise_idx].mean(axis=1)+        sorter_spec = spec_ratio.argsort()[::-1]+        return spec_ratio, sorter_spec++    def transform(self, inst):+        """Estimate epochs sources given the SSD filters.++        Parameters+        ----------+        inst : instance of Raw or Epochs (n_epochs, n_channels, n_times)+            The data to be processed. The instance is modified inplace.+       +        Returns+        -------+        out : instance of Raw or Epochs+            The processed data.+        +        """+        if self.filters_ is None:+            raise RuntimeError('No filters available. Please first call fit')+        if self.return_filtered:+            inst=self.Xs

whitespace

vpeterson

comment created time in 5 days

Pull request review commentdengemann/mne-python

added option to handle epoched data, sort component with respect to s…

 def freq_mask(freqs, fmin, fmax): fname = data_path() + '/SubjectCMC.ds' raw = mne.io.read_raw_ctf(fname) raw.crop(50., 250.).load_data()  # crop for memory purposes+picks=mne.pick_types(raw.info, meg=True, eeg=False, ref_meg=False)+sf=raw.info['sfreq']  freqs_sig = 9, 12 freqs_noise = 8, 13   class SSD(BaseEstimator, TransformerMixin):-    """Implement Spatio-Spectral Decomposision+    """+    +    This is a Python Implementation of Spatio Spectral Decomposition (SSD) +    method [1],[2] for both raw and epoched data. This source code is  based on+    the matlab implementation available at +    https://github.com/svendaehne/matlab_SPoC/tree/master/SSD and the PR MNE-based+    implementation of Denis A. Engemann <denis.engemann@gmail.com>+    +    SSD seeks at maximizing the power at a frequency band of interest while+    simultaneously minimizing it at the flanking (surrounding) frequency bins+    (considered noise). It extremizes the covariance matrices associated to +    signal and noise.+    +    Cosidering f as the freq. of interest, noise signals can be calculated+    either by filtering the signals in the frequency range [f−Δfb:f+Δfb] and then +    performing band-stop filtering around frequency f [f−Δfs:f+Δfs], where Δfb+    and Δfs generally are set equal to 2 and 1 Hz, or by filtering +    in the frequency range [f−Δf:f+Δf] with the following subtraction of +    the filtered signal around f [1]. +    +    SSD can either be used as a dimentionality reduction method or a denoised +    ‘denoised’ low rank factorization method [2].+              Parameters     ----------     filt_params_signal : dict         Filtering for the frequencies of interst.     filt_params_noise  : dict         Filtering for the frequencies of non-interest.-    estimator : str-        Which covariance estimator to use. Defaults to "oas".-    n_components  : int, None-        How many components to keep. Default to 5.-    subtract_signal : bool-        Whether to subtract the noise from the signal to enhcane-        sptial filter.-    sort_by_spectral_ratio : bool-        Whether to sort by the spectral ratio. Defaults to True.-+    sampling_freq : float+        sampling frequency (in Hz) of the recordings.+    estimator : float | str | None (default 'oas')+        Which covariance estimator to use+        If not None (same as 'empirical'), allow regularization for+        covariance estimation. If float, shrinkage is used +        (0 <= shrinkage <= 1). For str options, estimator will be passed to method +        to mne.compute_covariance().    +    n_components : int| None (default None)+        The number of components to decompose the signals. +        If n_components is None no dimentionality reduction is made, and the +        transformed data is projected in the whole source space.+   picks: array| int | None  (default None)+       Indeces of good-channels. Can be the output of mne.pick_types+ +   sort_by_spectral_ratio: bool (default True)+       if set to True, the components are sorted according to the spectral ratio+       See [1] Nikulin 2011, Eq. (24)+       +   return_filtered : bool (default False)+        If return_filtered is True, data is bandpassed and projected onto +        the SSD components.+        +   n_fft: int (default None)+       if sort_by_spectral_ratio is set to True, then the sources will be sorted+       accordinly to their spectral ratio which is calculated based on +       "psd_array_welch" function. the n_fft set the length of FFT used.+       See mne.time_frequency.psd_array_welch for more information+    +   cov_method_params : TYPE, optional+        As in mne.decoding.SPoC +        The default is None.+   rank : None | dict | ‘info’ | ‘full’+        As in mne.decoding.SPoC +        This controls the rank computation that can be read from the+        measurement info or estimated from the data. +        See Notes of mne.compute_rank() for details.The default is None.+        The default is None.++    +    REFERENCES:+    [1] Nikulin, V. V., Nolte, G., & Curio, G. (2011). A novel method for +    reliable and fast extraction of neuronal EEG/MEG oscillations on the basis +    of spatio-spectral decomposition. NeuroImage, 55(4), 1528-1535.+    [2] Haufe, S., Dähne, S., & Nikulin, V. V. (2014). Dimensionality reduction+    for the analysis of brain oscillations. NeuroImage, 101, 583-597.+    +    +                 """ -    def __init__(self, filt_params_signal, filt_params_noise,-                 estimator='oas', n_components=None,-                 subtract_signal=True,-                 reject=None,-                 flat=None,-                 picks=None,-                 sort_by_spectral_ratio=True):+    def __init__(self, filt_params_signal, filt_params_noise, sampling_freq,+                 estimator='oas', n_components=None, picks=None,+                 sort_by_spectral_ratio=True, return_filtered=False, n_fft=None, cov_method_params=None, rank=None):+                 """Initialize instance"""          dicts = {"signal": filt_params_signal, "noise": filt_params_noise}         for param, dd in [('l', 0), ('h', 0), ('l', 1), ('h', 1)]:             key = ('signal', 'noise')[dd]             if  param + '_freq' not in dicts[key]:                 raise ValueError(-                    "'%' must be defined in filter parameters for %s" % key)+                    "'%%' must be defined in filter parameters for %s" % key)             val = dicts[key][param + '_freq']             if not isinstance(val, (int, float)):                 raise ValueError(                     "Frequencies must be numbers, got %s" % type(val))+       +          #check freq bands+        if (filt_params_noise['l_freq'] > filt_params_signal['l_freq'] or  +                filt_params_signal['h_freq']>filt_params_noise['h_freq']):+            raise ValueError('Wrongly specified frequency bands!\nThe signal band-pass must be within the t noise band-pass!')          self.freqs_signal = (filt_params_signal['l_freq'],                              filt_params_signal['h_freq'])         self.freqs_noise = (filt_params_noise['l_freq'],                             filt_params_noise['h_freq'])+        +        +                       self.filt_params_signal = filt_params_signal         self.filt_params_noise = filt_params_noise-        self.subtract_signal = subtract_signal-        self.picks = picks+        self.sort_by_spectral_ratio = sort_by_spectral_ratio+        if n_fft is None:+            self.n_fft= int(sampling_freq)+        else:+            self.n_fft=int(n_fft)+        self.picks_ = picks+        +        self.return_filtered=return_filtered+        +                self.estimator = estimator         self.n_components = n_components-+        self.rank = rank+        self.sampling_freq=sampling_freq      +        self.cov_method_params = cov_method_params+        +         def fit(self, inst):         """Fit"""-        if self.picks == None:-            self.picks_ = mne.pick_types(inst.info, meg=True, eeg=False, ref_meg=False)-        else:-            self.picks_ = self.picks-        if isinstance(inst, mne.io.base.BaseRaw):+        +        +        if isinstance(inst, BaseRaw):+            if self.picks_ is None:+                raise ValueError('picks should be provided')+            self.max_components=len(self.picks_)             inst_signal = inst.copy()             inst_signal.filter(picks=self.picks_, **self.filt_params_signal)-+            self.Xs=inst_signal+            #noise             inst_noise = inst.copy()             inst_noise.filter(picks=self.picks_, **self.filt_params_noise)-            if self.subtract_signal:-                inst_noise._data[self.picks_] -= inst_signal._data[self.picks_]-            cov_signal = mne.compute_raw_covariance(-                inst_signal, picks=self.picks_, method=self.estimator)-            cov_noise = mne.compute_raw_covariance(inst_noise, picks=self.picks_,-                method=self.estimator)+            # subtract signal:+            inst_noise._data[self.picks_] -= inst_signal._data[self.picks_]+           +            cov_signal = compute_raw_covariance(+                inst_signal, picks=self.picks_, method=self.estimator, rank=self.rank)+            cov_noise = compute_raw_covariance(inst_noise, picks=self.picks_,+                method=self.estimator, rank=self.rank)             del inst_noise             del inst_signal         else:-            raise NotImplementedError()+            if isinstance(inst, BaseEpochs)  or isinstance(inst, np.ndarray):+            # data X is epoched +            # part of the following code is copied from mne csp+                n_epochs, n_channels, n_samples = inst.shape+                self.max_components=n_channels+              +                #reshape for filtering+                X_aux=np.reshape(inst, [n_epochs, n_channels*n_samples])+                X_s=filter_data(X_aux, self.sampling_freq, **self.filt_params_signal)  +                +                #rephase for filtering+                X_aux=np.reshape(inst, [n_epochs, n_channels*n_samples])+                X_n=filter_data(X_aux, self.sampling_freq, **self.filt_params_noise)+                # subtract signal:+                X_n -= X_s+                +                # Estimate single trial covariance+                #reshape to original shape+                X_s=np.reshape(X_s, [n_epochs,n_channels,n_samples])+                self.Xs=X_s+                covs = np.empty((n_epochs, n_channels, n_channels))+                for ii, epoch in enumerate(X_s):+                    covs[ii] = _regularized_covariance(+                        epoch, reg=self.estimator, method_params=self.cov_method_params,+                        rank=self.rank)+                    +                cov_signal = covs.mean(0)+            +                #% Covariance matrix for the flanking frequencies (noise)+                        +                +                +                #reshape to original shape+                X_n=np.reshape(X_n, [n_epochs,n_channels,n_samples])+                # Estimate single trial covariance+                covs_n = np.empty((n_epochs, n_channels, n_channels))+                for ii, epoch in enumerate(X_n):+                    covs_n[ii] = _regularized_covariance(+                        epoch, reg=self.estimator, method_params=self.cov_method_params,+                        rank=self.rank)+        +                cov_noise = covs_n.mean(0)+                       +            +            else:+                raise NotImplementedError()+        +        eigvals_,eigvects_ = eigh(cov_signal.data, cov_noise.data)+        # #sort in descencing order+        ix = np.argsort(eigvals_)[::-1]+        self.eigvals_=eigvals_[ix]+        self.filters_ = eigvects_[:,ix]+        # self.filters_ = eigvects_++        self.patterns_ = np.linalg.pinv(self.filters_)      +             +                +        return self+ +    def spectral_ratio_ssd(self,ssd_sources):+        """Spectral ratio measure for best n_components selection+        See Nikulin 2011, Eq. (24)+        +        Parameters+        ----------+        ssd_sources : data projected on the SSD space. +        output of transform+       +        """+                  +            +        psd, freqs = psd_array_welch(+        ssd_sources, sfreq=self.sampling_freq, n_fft=self.n_fft)+        sig_idx = _time_mask(freqs, *self.freqs_signal)+        noise_idx = _time_mask(freqs, *self.freqs_noise)+        if psd.ndim ==3:+            spec_ratio = psd[:, :,sig_idx].mean(axis=2).mean(axis=0) / psd[:,:, noise_idx].mean(axis=2).mean(axis=0)  -        self.eigvals_, self.filters_ = eigh(cov_signal.data, cov_noise.data)-        self.patterns_ = np.linalg.pinv(self.filters_)--    def transform(self, data):-        if self.n_components is None:-            n_components = len(self.picks_)         else:-            n_components = self.n_components-        return np.dot(self.filters_.T[:n_components], data[self.picks_])+                    +            spec_ratio = psd[:, sig_idx].mean(axis=1) / psd[:, noise_idx].mean(axis=1)+        sorter_spec = spec_ratio.argsort()[::-1]+        return spec_ratio, sorter_spec++    def transform(self, inst):+        """Estimate epochs sources given the SSD filters.++        Parameters+        ----------+        inst : instance of Raw or Epochs (n_epochs, n_channels, n_times)+            The data to be processed. The instance is modified inplace.+       +        Returns+        -------+        out : instance of Raw or Epochs+            The processed data.+        

unnecessary line

vpeterson

comment created time in 5 days

Pull request review commentdengemann/mne-python

added option to handle epoched data, sort component with respect to s…

 def freq_mask(freqs, fmin, fmax): fname = data_path() + '/SubjectCMC.ds' raw = mne.io.read_raw_ctf(fname) raw.crop(50., 250.).load_data()  # crop for memory purposes+picks=mne.pick_types(raw.info, meg=True, eeg=False, ref_meg=False)+sf=raw.info['sfreq']  freqs_sig = 9, 12 freqs_noise = 8, 13   class SSD(BaseEstimator, TransformerMixin):-    """Implement Spatio-Spectral Decomposision+    """+    +    This is a Python Implementation of Spatio Spectral Decomposition (SSD) +    method [1],[2] for both raw and epoched data. This source code is  based on+    the matlab implementation available at +    https://github.com/svendaehne/matlab_SPoC/tree/master/SSD and the PR MNE-based+    implementation of Denis A. Engemann <denis.engemann@gmail.com>+    +    SSD seeks at maximizing the power at a frequency band of interest while+    simultaneously minimizing it at the flanking (surrounding) frequency bins+    (considered noise). It extremizes the covariance matrices associated to +    signal and noise.+    +    Cosidering f as the freq. of interest, noise signals can be calculated+    either by filtering the signals in the frequency range [f−Δfb:f+Δfb] and then +    performing band-stop filtering around frequency f [f−Δfs:f+Δfs], where Δfb+    and Δfs generally are set equal to 2 and 1 Hz, or by filtering +    in the frequency range [f−Δf:f+Δf] with the following subtraction of +    the filtered signal around f [1]. +    +    SSD can either be used as a dimentionality reduction method or a denoised +    ‘denoised’ low rank factorization method [2].+              Parameters     ----------     filt_params_signal : dict         Filtering for the frequencies of interst.     filt_params_noise  : dict         Filtering for the frequencies of non-interest.-    estimator : str-        Which covariance estimator to use. Defaults to "oas".-    n_components  : int, None-        How many components to keep. Default to 5.-    subtract_signal : bool-        Whether to subtract the noise from the signal to enhcane-        sptial filter.-    sort_by_spectral_ratio : bool-        Whether to sort by the spectral ratio. Defaults to True.-+    sampling_freq : float+        sampling frequency (in Hz) of the recordings.+    estimator : float | str | None (default 'oas')+        Which covariance estimator to use+        If not None (same as 'empirical'), allow regularization for+        covariance estimation. If float, shrinkage is used +        (0 <= shrinkage <= 1). For str options, estimator will be passed to method +        to mne.compute_covariance().    +    n_components : int| None (default None)+        The number of components to decompose the signals. +        If n_components is None no dimentionality reduction is made, and the +        transformed data is projected in the whole source space.+   picks: array| int | None  (default None)+       Indeces of good-channels. Can be the output of mne.pick_types+ +   sort_by_spectral_ratio: bool (default True)+       if set to True, the components are sorted according to the spectral ratio+       See [1] Nikulin 2011, Eq. (24)+       +   return_filtered : bool (default False)+        If return_filtered is True, data is bandpassed and projected onto +        the SSD components.+        +   n_fft: int (default None)+       if sort_by_spectral_ratio is set to True, then the sources will be sorted+       accordinly to their spectral ratio which is calculated based on +       "psd_array_welch" function. the n_fft set the length of FFT used.+       See mne.time_frequency.psd_array_welch for more information+    +   cov_method_params : TYPE, optional+        As in mne.decoding.SPoC +        The default is None.+   rank : None | dict | ‘info’ | ‘full’+        As in mne.decoding.SPoC +        This controls the rank computation that can be read from the+        measurement info or estimated from the data. +        See Notes of mne.compute_rank() for details.The default is None.+        The default is None.++    +    REFERENCES:+    [1] Nikulin, V. V., Nolte, G., & Curio, G. (2011). A novel method for +    reliable and fast extraction of neuronal EEG/MEG oscillations on the basis +    of spatio-spectral decomposition. NeuroImage, 55(4), 1528-1535.+    [2] Haufe, S., Dähne, S., & Nikulin, V. V. (2014). Dimensionality reduction+    for the analysis of brain oscillations. NeuroImage, 101, 583-597.+    +    +                 """ -    def __init__(self, filt_params_signal, filt_params_noise,-                 estimator='oas', n_components=None,-                 subtract_signal=True,-                 reject=None,-                 flat=None,-                 picks=None,-                 sort_by_spectral_ratio=True):+    def __init__(self, filt_params_signal, filt_params_noise, sampling_freq,+                 estimator='oas', n_components=None, picks=None,+                 sort_by_spectral_ratio=True, return_filtered=False, n_fft=None, cov_method_params=None, rank=None):+                 """Initialize instance"""          dicts = {"signal": filt_params_signal, "noise": filt_params_noise}         for param, dd in [('l', 0), ('h', 0), ('l', 1), ('h', 1)]:             key = ('signal', 'noise')[dd]             if  param + '_freq' not in dicts[key]:                 raise ValueError(-                    "'%' must be defined in filter parameters for %s" % key)+                    "'%%' must be defined in filter parameters for %s" % key)             val = dicts[key][param + '_freq']             if not isinstance(val, (int, float)):                 raise ValueError(                     "Frequencies must be numbers, got %s" % type(val))+       +          #check freq bands+        if (filt_params_noise['l_freq'] > filt_params_signal['l_freq'] or  +                filt_params_signal['h_freq']>filt_params_noise['h_freq']):+            raise ValueError('Wrongly specified frequency bands!\nThe signal band-pass must be within the t noise band-pass!')          self.freqs_signal = (filt_params_signal['l_freq'],                              filt_params_signal['h_freq'])         self.freqs_noise = (filt_params_noise['l_freq'],                             filt_params_noise['h_freq'])+        +        +                       self.filt_params_signal = filt_params_signal         self.filt_params_noise = filt_params_noise-        self.subtract_signal = subtract_signal-        self.picks = picks+        self.sort_by_spectral_ratio = sort_by_spectral_ratio+        if n_fft is None:+            self.n_fft= int(sampling_freq)+        else:+            self.n_fft=int(n_fft)+        self.picks_ = picks+        +        self.return_filtered=return_filtered+        +                self.estimator = estimator         self.n_components = n_components-+        self.rank = rank+        self.sampling_freq=sampling_freq      +        self.cov_method_params = cov_method_params+        +         def fit(self, inst):         """Fit"""-        if self.picks == None:-            self.picks_ = mne.pick_types(inst.info, meg=True, eeg=False, ref_meg=False)-        else:-            self.picks_ = self.picks-        if isinstance(inst, mne.io.base.BaseRaw):+        +        +        if isinstance(inst, BaseRaw):+            if self.picks_ is None:+                raise ValueError('picks should be provided')+            self.max_components=len(self.picks_)             inst_signal = inst.copy()             inst_signal.filter(picks=self.picks_, **self.filt_params_signal)-+            self.Xs=inst_signal+            #noise             inst_noise = inst.copy()             inst_noise.filter(picks=self.picks_, **self.filt_params_noise)-            if self.subtract_signal:-                inst_noise._data[self.picks_] -= inst_signal._data[self.picks_]-            cov_signal = mne.compute_raw_covariance(-                inst_signal, picks=self.picks_, method=self.estimator)-            cov_noise = mne.compute_raw_covariance(inst_noise, picks=self.picks_,-                method=self.estimator)+            # subtract signal:+            inst_noise._data[self.picks_] -= inst_signal._data[self.picks_]+           +            cov_signal = compute_raw_covariance(+                inst_signal, picks=self.picks_, method=self.estimator, rank=self.rank)+            cov_noise = compute_raw_covariance(inst_noise, picks=self.picks_,+                method=self.estimator, rank=self.rank)             del inst_noise             del inst_signal         else:-            raise NotImplementedError()+            if isinstance(inst, BaseEpochs)  or isinstance(inst, np.ndarray):+            # data X is epoched +            # part of the following code is copied from mne csp+                n_epochs, n_channels, n_samples = inst.shape+                self.max_components=n_channels+              +                #reshape for filtering+                X_aux=np.reshape(inst, [n_epochs, n_channels*n_samples])+                X_s=filter_data(X_aux, self.sampling_freq, **self.filt_params_signal)  +                +                #rephase for filtering+                X_aux=np.reshape(inst, [n_epochs, n_channels*n_samples])+                X_n=filter_data(X_aux, self.sampling_freq, **self.filt_params_noise)+                # subtract signal:+                X_n -= X_s+                +                # Estimate single trial covariance+                #reshape to original shape+                X_s=np.reshape(X_s, [n_epochs,n_channels,n_samples])+                self.Xs=X_s+                covs = np.empty((n_epochs, n_channels, n_channels))+                for ii, epoch in enumerate(X_s):+                    covs[ii] = _regularized_covariance(+                        epoch, reg=self.estimator, method_params=self.cov_method_params,+                        rank=self.rank)+                    +                cov_signal = covs.mean(0)+            +                #% Covariance matrix for the flanking frequencies (noise)+                        +                +                +                #reshape to original shape+                X_n=np.reshape(X_n, [n_epochs,n_channels,n_samples])+                # Estimate single trial covariance+                covs_n = np.empty((n_epochs, n_channels, n_channels))+                for ii, epoch in enumerate(X_n):+                    covs_n[ii] = _regularized_covariance(+                        epoch, reg=self.estimator, method_params=self.cov_method_params,+                        rank=self.rank)+        +                cov_noise = covs_n.mean(0)+                       +            +            else:+                raise NotImplementedError()+        +        eigvals_,eigvects_ = eigh(cov_signal.data, cov_noise.data)+        # #sort in descencing order+        ix = np.argsort(eigvals_)[::-1]+        self.eigvals_=eigvals_[ix]+        self.filters_ = eigvects_[:,ix]+        # self.filters_ = eigvects_++        self.patterns_ = np.linalg.pinv(self.filters_)      +             +                +        return self+ +    def spectral_ratio_ssd(self,ssd_sources):+        """Spectral ratio measure for best n_components selection+        See Nikulin 2011, Eq. (24)+        +        Parameters+        ----------+        ssd_sources : data projected on the SSD space. +        output of transform+       +        """+                  +            +        psd, freqs = psd_array_welch(+        ssd_sources, sfreq=self.sampling_freq, n_fft=self.n_fft)+        sig_idx = _time_mask(freqs, *self.freqs_signal)+        noise_idx = _time_mask(freqs, *self.freqs_noise)+        if psd.ndim ==3:+            spec_ratio = psd[:, :,sig_idx].mean(axis=2).mean(axis=0) / psd[:,:, noise_idx].mean(axis=2).mean(axis=0) 

check if line exceeds 80 characters, otherwise break line using parentheses or backslashes.

vpeterson

comment created time in 5 days

Pull request review commentdengemann/mne-python

added option to handle epoched data, sort component with respect to s…

 def freq_mask(freqs, fmin, fmax): fname = data_path() + '/SubjectCMC.ds' raw = mne.io.read_raw_ctf(fname) raw.crop(50., 250.).load_data()  # crop for memory purposes+picks=mne.pick_types(raw.info, meg=True, eeg=False, ref_meg=False)+sf=raw.info['sfreq']  freqs_sig = 9, 12 freqs_noise = 8, 13   class SSD(BaseEstimator, TransformerMixin):-    """Implement Spatio-Spectral Decomposision+    """+    +    This is a Python Implementation of Spatio Spectral Decomposition (SSD) +    method [1],[2] for both raw and epoched data. This source code is  based on+    the matlab implementation available at +    https://github.com/svendaehne/matlab_SPoC/tree/master/SSD and the PR MNE-based+    implementation of Denis A. Engemann <denis.engemann@gmail.com>+    +    SSD seeks at maximizing the power at a frequency band of interest while+    simultaneously minimizing it at the flanking (surrounding) frequency bins+    (considered noise). It extremizes the covariance matrices associated to +    signal and noise.+    +    Cosidering f as the freq. of interest, noise signals can be calculated+    either by filtering the signals in the frequency range [f−Δfb:f+Δfb] and then +    performing band-stop filtering around frequency f [f−Δfs:f+Δfs], where Δfb+    and Δfs generally are set equal to 2 and 1 Hz, or by filtering +    in the frequency range [f−Δf:f+Δf] with the following subtraction of +    the filtered signal around f [1]. +    +    SSD can either be used as a dimentionality reduction method or a denoised +    ‘denoised’ low rank factorization method [2].+              Parameters     ----------     filt_params_signal : dict         Filtering for the frequencies of interst.     filt_params_noise  : dict         Filtering for the frequencies of non-interest.-    estimator : str-        Which covariance estimator to use. Defaults to "oas".-    n_components  : int, None-        How many components to keep. Default to 5.-    subtract_signal : bool-        Whether to subtract the noise from the signal to enhcane-        sptial filter.-    sort_by_spectral_ratio : bool-        Whether to sort by the spectral ratio. Defaults to True.-+    sampling_freq : float+        sampling frequency (in Hz) of the recordings.+    estimator : float | str | None (default 'oas')+        Which covariance estimator to use+        If not None (same as 'empirical'), allow regularization for+        covariance estimation. If float, shrinkage is used +        (0 <= shrinkage <= 1). For str options, estimator will be passed to method +        to mne.compute_covariance().    +    n_components : int| None (default None)+        The number of components to decompose the signals. +        If n_components is None no dimentionality reduction is made, and the +        transformed data is projected in the whole source space.+   picks: array| int | None  (default None)+       Indeces of good-channels. Can be the output of mne.pick_types+ +   sort_by_spectral_ratio: bool (default True)+       if set to True, the components are sorted according to the spectral ratio+       See [1] Nikulin 2011, Eq. (24)+       +   return_filtered : bool (default False)+        If return_filtered is True, data is bandpassed and projected onto +        the SSD components.+        +   n_fft: int (default None)+       if sort_by_spectral_ratio is set to True, then the sources will be sorted+       accordinly to their spectral ratio which is calculated based on +       "psd_array_welch" function. the n_fft set the length of FFT used.+       See mne.time_frequency.psd_array_welch for more information+    +   cov_method_params : TYPE, optional+        As in mne.decoding.SPoC +        The default is None.+   rank : None | dict | ‘info’ | ‘full’+        As in mne.decoding.SPoC +        This controls the rank computation that can be read from the+        measurement info or estimated from the data. +        See Notes of mne.compute_rank() for details.The default is None.+        The default is None.++    +    REFERENCES:+    [1] Nikulin, V. V., Nolte, G., & Curio, G. (2011). A novel method for +    reliable and fast extraction of neuronal EEG/MEG oscillations on the basis +    of spatio-spectral decomposition. NeuroImage, 55(4), 1528-1535.+    [2] Haufe, S., Dähne, S., & Nikulin, V. V. (2014). Dimensionality reduction+    for the analysis of brain oscillations. NeuroImage, 101, 583-597.+    +    +                 """ -    def __init__(self, filt_params_signal, filt_params_noise,-                 estimator='oas', n_components=None,-                 subtract_signal=True,-                 reject=None,-                 flat=None,-                 picks=None,-                 sort_by_spectral_ratio=True):+    def __init__(self, filt_params_signal, filt_params_noise, sampling_freq,+                 estimator='oas', n_components=None, picks=None,+                 sort_by_spectral_ratio=True, return_filtered=False, n_fft=None, cov_method_params=None, rank=None):+                 """Initialize instance"""          dicts = {"signal": filt_params_signal, "noise": filt_params_noise}         for param, dd in [('l', 0), ('h', 0), ('l', 1), ('h', 1)]:             key = ('signal', 'noise')[dd]             if  param + '_freq' not in dicts[key]:                 raise ValueError(-                    "'%' must be defined in filter parameters for %s" % key)+                    "'%%' must be defined in filter parameters for %s" % key)             val = dicts[key][param + '_freq']             if not isinstance(val, (int, float)):                 raise ValueError(                     "Frequencies must be numbers, got %s" % type(val))+       +          #check freq bands+        if (filt_params_noise['l_freq'] > filt_params_signal['l_freq'] or  +                filt_params_signal['h_freq']>filt_params_noise['h_freq']):+            raise ValueError('Wrongly specified frequency bands!\nThe signal band-pass must be within the t noise band-pass!')          self.freqs_signal = (filt_params_signal['l_freq'],                              filt_params_signal['h_freq'])         self.freqs_noise = (filt_params_noise['l_freq'],                             filt_params_noise['h_freq'])+        +        +                       self.filt_params_signal = filt_params_signal         self.filt_params_noise = filt_params_noise-        self.subtract_signal = subtract_signal-        self.picks = picks+        self.sort_by_spectral_ratio = sort_by_spectral_ratio+        if n_fft is None:+            self.n_fft= int(sampling_freq)+        else:+            self.n_fft=int(n_fft)+        self.picks_ = picks+        +        self.return_filtered=return_filtered+        +                self.estimator = estimator         self.n_components = n_components-+        self.rank = rank+        self.sampling_freq=sampling_freq      +        self.cov_method_params = cov_method_params+        +         def fit(self, inst):         """Fit"""-        if self.picks == None:-            self.picks_ = mne.pick_types(inst.info, meg=True, eeg=False, ref_meg=False)-        else:-            self.picks_ = self.picks-        if isinstance(inst, mne.io.base.BaseRaw):+        +        +        if isinstance(inst, BaseRaw):+            if self.picks_ is None:+                raise ValueError('picks should be provided')+            self.max_components=len(self.picks_)             inst_signal = inst.copy()             inst_signal.filter(picks=self.picks_, **self.filt_params_signal)-+            self.Xs=inst_signal+            #noise             inst_noise = inst.copy()             inst_noise.filter(picks=self.picks_, **self.filt_params_noise)-            if self.subtract_signal:-                inst_noise._data[self.picks_] -= inst_signal._data[self.picks_]-            cov_signal = mne.compute_raw_covariance(-                inst_signal, picks=self.picks_, method=self.estimator)-            cov_noise = mne.compute_raw_covariance(inst_noise, picks=self.picks_,-                method=self.estimator)+            # subtract signal:+            inst_noise._data[self.picks_] -= inst_signal._data[self.picks_]+           +            cov_signal = compute_raw_covariance(+                inst_signal, picks=self.picks_, method=self.estimator, rank=self.rank)+            cov_noise = compute_raw_covariance(inst_noise, picks=self.picks_,+                method=self.estimator, rank=self.rank)             del inst_noise             del inst_signal         else:-            raise NotImplementedError()+            if isinstance(inst, BaseEpochs)  or isinstance(inst, np.ndarray):+            # data X is epoched +            # part of the following code is copied from mne csp+                n_epochs, n_channels, n_samples = inst.shape+                self.max_components=n_channels+              +                #reshape for filtering+                X_aux=np.reshape(inst, [n_epochs, n_channels*n_samples])+                X_s=filter_data(X_aux, self.sampling_freq, **self.filt_params_signal)  +                +                #rephase for filtering+                X_aux=np.reshape(inst, [n_epochs, n_channels*n_samples])+                X_n=filter_data(X_aux, self.sampling_freq, **self.filt_params_noise)+                # subtract signal:+                X_n -= X_s+                +                # Estimate single trial covariance+                #reshape to original shape+                X_s=np.reshape(X_s, [n_epochs,n_channels,n_samples])+                self.Xs=X_s+                covs = np.empty((n_epochs, n_channels, n_channels))+                for ii, epoch in enumerate(X_s):+                    covs[ii] = _regularized_covariance(+                        epoch, reg=self.estimator, method_params=self.cov_method_params,+                        rank=self.rank)+                    +                cov_signal = covs.mean(0)+            +                #% Covariance matrix for the flanking frequencies (noise)+                        +                +                +                #reshape to original shape+                X_n=np.reshape(X_n, [n_epochs,n_channels,n_samples])+                # Estimate single trial covariance+                covs_n = np.empty((n_epochs, n_channels, n_channels))+                for ii, epoch in enumerate(X_n):+                    covs_n[ii] = _regularized_covariance(+                        epoch, reg=self.estimator, method_params=self.cov_method_params,+                        rank=self.rank)+        +                cov_noise = covs_n.mean(0)+                       +            +            else:+                raise NotImplementedError()+        +        eigvals_,eigvects_ = eigh(cov_signal.data, cov_noise.data)+        # #sort in descencing order+        ix = np.argsort(eigvals_)[::-1]+        self.eigvals_=eigvals_[ix]+        self.filters_ = eigvects_[:,ix]+        # self.filters_ = eigvects_++        self.patterns_ = np.linalg.pinv(self.filters_)      +             +                +        return self+ +    def spectral_ratio_ssd(self,ssd_sources):

whitespace

vpeterson

comment created time in 5 days

Pull request review commentdengemann/mne-python

added option to handle epoched data, sort component with respect to s…

 def freq_mask(freqs, fmin, fmax): fname = data_path() + '/SubjectCMC.ds' raw = mne.io.read_raw_ctf(fname) raw.crop(50., 250.).load_data()  # crop for memory purposes+picks=mne.pick_types(raw.info, meg=True, eeg=False, ref_meg=False)+sf=raw.info['sfreq']  freqs_sig = 9, 12 freqs_noise = 8, 13   class SSD(BaseEstimator, TransformerMixin):-    """Implement Spatio-Spectral Decomposision+    """+    +    This is a Python Implementation of Spatio Spectral Decomposition (SSD) +    method [1],[2] for both raw and epoched data. This source code is  based on+    the matlab implementation available at +    https://github.com/svendaehne/matlab_SPoC/tree/master/SSD and the PR MNE-based+    implementation of Denis A. Engemann <denis.engemann@gmail.com>+    +    SSD seeks at maximizing the power at a frequency band of interest while+    simultaneously minimizing it at the flanking (surrounding) frequency bins+    (considered noise). It extremizes the covariance matrices associated to +    signal and noise.+    +    Cosidering f as the freq. of interest, noise signals can be calculated+    either by filtering the signals in the frequency range [f−Δfb:f+Δfb] and then +    performing band-stop filtering around frequency f [f−Δfs:f+Δfs], where Δfb+    and Δfs generally are set equal to 2 and 1 Hz, or by filtering +    in the frequency range [f−Δf:f+Δf] with the following subtraction of +    the filtered signal around f [1]. +    +    SSD can either be used as a dimentionality reduction method or a denoised +    ‘denoised’ low rank factorization method [2].+              Parameters     ----------     filt_params_signal : dict         Filtering for the frequencies of interst.     filt_params_noise  : dict         Filtering for the frequencies of non-interest.-    estimator : str-        Which covariance estimator to use. Defaults to "oas".-    n_components  : int, None-        How many components to keep. Default to 5.-    subtract_signal : bool-        Whether to subtract the noise from the signal to enhcane-        sptial filter.-    sort_by_spectral_ratio : bool-        Whether to sort by the spectral ratio. Defaults to True.-+    sampling_freq : float+        sampling frequency (in Hz) of the recordings.+    estimator : float | str | None (default 'oas')+        Which covariance estimator to use+        If not None (same as 'empirical'), allow regularization for+        covariance estimation. If float, shrinkage is used +        (0 <= shrinkage <= 1). For str options, estimator will be passed to method +        to mne.compute_covariance().    +    n_components : int| None (default None)+        The number of components to decompose the signals. +        If n_components is None no dimentionality reduction is made, and the +        transformed data is projected in the whole source space.+   picks: array| int | None  (default None)+       Indeces of good-channels. Can be the output of mne.pick_types+ +   sort_by_spectral_ratio: bool (default True)+       if set to True, the components are sorted according to the spectral ratio+       See [1] Nikulin 2011, Eq. (24)+       +   return_filtered : bool (default False)+        If return_filtered is True, data is bandpassed and projected onto +        the SSD components.+        +   n_fft: int (default None)+       if sort_by_spectral_ratio is set to True, then the sources will be sorted+       accordinly to their spectral ratio which is calculated based on +       "psd_array_welch" function. the n_fft set the length of FFT used.+       See mne.time_frequency.psd_array_welch for more information+    +   cov_method_params : TYPE, optional+        As in mne.decoding.SPoC +        The default is None.+   rank : None | dict | ‘info’ | ‘full’+        As in mne.decoding.SPoC +        This controls the rank computation that can be read from the+        measurement info or estimated from the data. +        See Notes of mne.compute_rank() for details.The default is None.+        The default is None.++    +    REFERENCES:+    [1] Nikulin, V. V., Nolte, G., & Curio, G. (2011). A novel method for +    reliable and fast extraction of neuronal EEG/MEG oscillations on the basis +    of spatio-spectral decomposition. NeuroImage, 55(4), 1528-1535.+    [2] Haufe, S., Dähne, S., & Nikulin, V. V. (2014). Dimensionality reduction+    for the analysis of brain oscillations. NeuroImage, 101, 583-597.+    +    +                 """ -    def __init__(self, filt_params_signal, filt_params_noise,-                 estimator='oas', n_components=None,-                 subtract_signal=True,-                 reject=None,-                 flat=None,-                 picks=None,-                 sort_by_spectral_ratio=True):+    def __init__(self, filt_params_signal, filt_params_noise, sampling_freq,+                 estimator='oas', n_components=None, picks=None,+                 sort_by_spectral_ratio=True, return_filtered=False, n_fft=None, cov_method_params=None, rank=None):+                 """Initialize instance"""          dicts = {"signal": filt_params_signal, "noise": filt_params_noise}         for param, dd in [('l', 0), ('h', 0), ('l', 1), ('h', 1)]:             key = ('signal', 'noise')[dd]             if  param + '_freq' not in dicts[key]:                 raise ValueError(-                    "'%' must be defined in filter parameters for %s" % key)+                    "'%%' must be defined in filter parameters for %s" % key)             val = dicts[key][param + '_freq']             if not isinstance(val, (int, float)):                 raise ValueError(                     "Frequencies must be numbers, got %s" % type(val))+       +          #check freq bands+        if (filt_params_noise['l_freq'] > filt_params_signal['l_freq'] or  +                filt_params_signal['h_freq']>filt_params_noise['h_freq']):+            raise ValueError('Wrongly specified frequency bands!\nThe signal band-pass must be within the t noise band-pass!')          self.freqs_signal = (filt_params_signal['l_freq'],                              filt_params_signal['h_freq'])         self.freqs_noise = (filt_params_noise['l_freq'],                             filt_params_noise['h_freq'])+        +        +                       self.filt_params_signal = filt_params_signal         self.filt_params_noise = filt_params_noise-        self.subtract_signal = subtract_signal-        self.picks = picks+        self.sort_by_spectral_ratio = sort_by_spectral_ratio+        if n_fft is None:+            self.n_fft= int(sampling_freq)+        else:+            self.n_fft=int(n_fft)+        self.picks_ = picks+        +        self.return_filtered=return_filtered+        +                self.estimator = estimator         self.n_components = n_components-+        self.rank = rank+        self.sampling_freq=sampling_freq      +        self.cov_method_params = cov_method_params+        +         def fit(self, inst):         """Fit"""-        if self.picks == None:-            self.picks_ = mne.pick_types(inst.info, meg=True, eeg=False, ref_meg=False)-        else:-            self.picks_ = self.picks-        if isinstance(inst, mne.io.base.BaseRaw):+        +        +        if isinstance(inst, BaseRaw):+            if self.picks_ is None:+                raise ValueError('picks should be provided')+            self.max_components=len(self.picks_)             inst_signal = inst.copy()             inst_signal.filter(picks=self.picks_, **self.filt_params_signal)-+            self.Xs=inst_signal+            #noise             inst_noise = inst.copy()             inst_noise.filter(picks=self.picks_, **self.filt_params_noise)-            if self.subtract_signal:-                inst_noise._data[self.picks_] -= inst_signal._data[self.picks_]-            cov_signal = mne.compute_raw_covariance(-                inst_signal, picks=self.picks_, method=self.estimator)-            cov_noise = mne.compute_raw_covariance(inst_noise, picks=self.picks_,-                method=self.estimator)+            # subtract signal:+            inst_noise._data[self.picks_] -= inst_signal._data[self.picks_]+           +            cov_signal = compute_raw_covariance(+                inst_signal, picks=self.picks_, method=self.estimator, rank=self.rank)+            cov_noise = compute_raw_covariance(inst_noise, picks=self.picks_,+                method=self.estimator, rank=self.rank)             del inst_noise             del inst_signal         else:-            raise NotImplementedError()+            if isinstance(inst, BaseEpochs)  or isinstance(inst, np.ndarray):+            # data X is epoched +            # part of the following code is copied from mne csp+                n_epochs, n_channels, n_samples = inst.shape+                self.max_components=n_channels+              +                #reshape for filtering+                X_aux=np.reshape(inst, [n_epochs, n_channels*n_samples])+                X_s=filter_data(X_aux, self.sampling_freq, **self.filt_params_signal)  +                +                #rephase for filtering+                X_aux=np.reshape(inst, [n_epochs, n_channels*n_samples])+                X_n=filter_data(X_aux, self.sampling_freq, **self.filt_params_noise)+                # subtract signal:+                X_n -= X_s+                +                # Estimate single trial covariance+                #reshape to original shape+                X_s=np.reshape(X_s, [n_epochs,n_channels,n_samples])+                self.Xs=X_s+                covs = np.empty((n_epochs, n_channels, n_channels))+                for ii, epoch in enumerate(X_s):+                    covs[ii] = _regularized_covariance(+                        epoch, reg=self.estimator, method_params=self.cov_method_params,+                        rank=self.rank)+                    +                cov_signal = covs.mean(0)+            +                #% Covariance matrix for the flanking frequencies (noise)+                        +                +                +                #reshape to original shape+                X_n=np.reshape(X_n, [n_epochs,n_channels,n_samples])+                # Estimate single trial covariance+                covs_n = np.empty((n_epochs, n_channels, n_channels))+                for ii, epoch in enumerate(X_n):+                    covs_n[ii] = _regularized_covariance(+                        epoch, reg=self.estimator, method_params=self.cov_method_params,+                        rank=self.rank)+        +                cov_noise = covs_n.mean(0)+                       +            +            else:+                raise NotImplementedError()+        +        eigvals_,eigvects_ = eigh(cov_signal.data, cov_noise.data)+        # #sort in descencing order+        ix = np.argsort(eigvals_)[::-1]+        self.eigvals_=eigvals_[ix]+        self.filters_ = eigvects_[:,ix]+        # self.filters_ = eigvects_++        self.patterns_ = np.linalg.pinv(self.filters_)      

correct whitespaces.

vpeterson

comment created time in 5 days

Pull request review commentdengemann/mne-python

added option to handle epoched data, sort component with respect to s…

 def freq_mask(freqs, fmin, fmax): fname = data_path() + '/SubjectCMC.ds' raw = mne.io.read_raw_ctf(fname) raw.crop(50., 250.).load_data()  # crop for memory purposes+picks=mne.pick_types(raw.info, meg=True, eeg=False, ref_meg=False)+sf=raw.info['sfreq']  freqs_sig = 9, 12 freqs_noise = 8, 13   class SSD(BaseEstimator, TransformerMixin):-    """Implement Spatio-Spectral Decomposision+    """+    +    This is a Python Implementation of Spatio Spectral Decomposition (SSD) +    method [1],[2] for both raw and epoched data. This source code is  based on+    the matlab implementation available at +    https://github.com/svendaehne/matlab_SPoC/tree/master/SSD and the PR MNE-based+    implementation of Denis A. Engemann <denis.engemann@gmail.com>+    +    SSD seeks at maximizing the power at a frequency band of interest while+    simultaneously minimizing it at the flanking (surrounding) frequency bins+    (considered noise). It extremizes the covariance matrices associated to +    signal and noise.+    +    Cosidering f as the freq. of interest, noise signals can be calculated+    either by filtering the signals in the frequency range [f−Δfb:f+Δfb] and then +    performing band-stop filtering around frequency f [f−Δfs:f+Δfs], where Δfb+    and Δfs generally are set equal to 2 and 1 Hz, or by filtering +    in the frequency range [f−Δf:f+Δf] with the following subtraction of +    the filtered signal around f [1]. +    +    SSD can either be used as a dimentionality reduction method or a denoised +    ‘denoised’ low rank factorization method [2].+              Parameters     ----------     filt_params_signal : dict         Filtering for the frequencies of interst.     filt_params_noise  : dict         Filtering for the frequencies of non-interest.-    estimator : str-        Which covariance estimator to use. Defaults to "oas".-    n_components  : int, None-        How many components to keep. Default to 5.-    subtract_signal : bool-        Whether to subtract the noise from the signal to enhcane-        sptial filter.-    sort_by_spectral_ratio : bool-        Whether to sort by the spectral ratio. Defaults to True.-+    sampling_freq : float+        sampling frequency (in Hz) of the recordings.+    estimator : float | str | None (default 'oas')+        Which covariance estimator to use+        If not None (same as 'empirical'), allow regularization for+        covariance estimation. If float, shrinkage is used +        (0 <= shrinkage <= 1). For str options, estimator will be passed to method +        to mne.compute_covariance().    +    n_components : int| None (default None)+        The number of components to decompose the signals. +        If n_components is None no dimentionality reduction is made, and the +        transformed data is projected in the whole source space.+   picks: array| int | None  (default None)+       Indeces of good-channels. Can be the output of mne.pick_types+ +   sort_by_spectral_ratio: bool (default True)+       if set to True, the components are sorted according to the spectral ratio+       See [1] Nikulin 2011, Eq. (24)+       +   return_filtered : bool (default False)+        If return_filtered is True, data is bandpassed and projected onto +        the SSD components.+        +   n_fft: int (default None)+       if sort_by_spectral_ratio is set to True, then the sources will be sorted+       accordinly to their spectral ratio which is calculated based on +       "psd_array_welch" function. the n_fft set the length of FFT used.+       See mne.time_frequency.psd_array_welch for more information+    +   cov_method_params : TYPE, optional+        As in mne.decoding.SPoC +        The default is None.+   rank : None | dict | ‘info’ | ‘full’+        As in mne.decoding.SPoC +        This controls the rank computation that can be read from the+        measurement info or estimated from the data. +        See Notes of mne.compute_rank() for details.The default is None.+        The default is None.++    +    REFERENCES:+    [1] Nikulin, V. V., Nolte, G., & Curio, G. (2011). A novel method for +    reliable and fast extraction of neuronal EEG/MEG oscillations on the basis +    of spatio-spectral decomposition. NeuroImage, 55(4), 1528-1535.+    [2] Haufe, S., Dähne, S., & Nikulin, V. V. (2014). Dimensionality reduction+    for the analysis of brain oscillations. NeuroImage, 101, 583-597.+    +    +                 """ -    def __init__(self, filt_params_signal, filt_params_noise,-                 estimator='oas', n_components=None,-                 subtract_signal=True,-                 reject=None,-                 flat=None,-                 picks=None,-                 sort_by_spectral_ratio=True):+    def __init__(self, filt_params_signal, filt_params_noise, sampling_freq,+                 estimator='oas', n_components=None, picks=None,+                 sort_by_spectral_ratio=True, return_filtered=False, n_fft=None, cov_method_params=None, rank=None):+                 """Initialize instance"""          dicts = {"signal": filt_params_signal, "noise": filt_params_noise}         for param, dd in [('l', 0), ('h', 0), ('l', 1), ('h', 1)]:             key = ('signal', 'noise')[dd]             if  param + '_freq' not in dicts[key]:                 raise ValueError(-                    "'%' must be defined in filter parameters for %s" % key)+                    "'%%' must be defined in filter parameters for %s" % key)             val = dicts[key][param + '_freq']             if not isinstance(val, (int, float)):                 raise ValueError(                     "Frequencies must be numbers, got %s" % type(val))+       +          #check freq bands+        if (filt_params_noise['l_freq'] > filt_params_signal['l_freq'] or  +                filt_params_signal['h_freq']>filt_params_noise['h_freq']):+            raise ValueError('Wrongly specified frequency bands!\nThe signal band-pass must be within the t noise band-pass!')          self.freqs_signal = (filt_params_signal['l_freq'],                              filt_params_signal['h_freq'])         self.freqs_noise = (filt_params_noise['l_freq'],                             filt_params_noise['h_freq'])+        +        +                       self.filt_params_signal = filt_params_signal         self.filt_params_noise = filt_params_noise-        self.subtract_signal = subtract_signal-        self.picks = picks+        self.sort_by_spectral_ratio = sort_by_spectral_ratio+        if n_fft is None:+            self.n_fft= int(sampling_freq)+        else:+            self.n_fft=int(n_fft)+        self.picks_ = picks+        +        self.return_filtered=return_filtered+        +                self.estimator = estimator         self.n_components = n_components-+        self.rank = rank+        self.sampling_freq=sampling_freq      +        self.cov_method_params = cov_method_params+        +         def fit(self, inst):         """Fit"""-        if self.picks == None:-            self.picks_ = mne.pick_types(inst.info, meg=True, eeg=False, ref_meg=False)-        else:-            self.picks_ = self.picks-        if isinstance(inst, mne.io.base.BaseRaw):+        +        +        if isinstance(inst, BaseRaw):+            if self.picks_ is None:+                raise ValueError('picks should be provided')+            self.max_components=len(self.picks_)             inst_signal = inst.copy()             inst_signal.filter(picks=self.picks_, **self.filt_params_signal)-+            self.Xs=inst_signal+            #noise             inst_noise = inst.copy()             inst_noise.filter(picks=self.picks_, **self.filt_params_noise)-            if self.subtract_signal:-                inst_noise._data[self.picks_] -= inst_signal._data[self.picks_]-            cov_signal = mne.compute_raw_covariance(-                inst_signal, picks=self.picks_, method=self.estimator)-            cov_noise = mne.compute_raw_covariance(inst_noise, picks=self.picks_,-                method=self.estimator)+            # subtract signal:+            inst_noise._data[self.picks_] -= inst_signal._data[self.picks_]+           +            cov_signal = compute_raw_covariance(+                inst_signal, picks=self.picks_, method=self.estimator, rank=self.rank)+            cov_noise = compute_raw_covariance(inst_noise, picks=self.picks_,+                method=self.estimator, rank=self.rank)             del inst_noise             del inst_signal         else:-            raise NotImplementedError()+            if isinstance(inst, BaseEpochs)  or isinstance(inst, np.ndarray):+            # data X is epoched +            # part of the following code is copied from mne csp+                n_epochs, n_channels, n_samples = inst.shape+                self.max_components=n_channels+              +                #reshape for filtering+                X_aux=np.reshape(inst, [n_epochs, n_channels*n_samples])+                X_s=filter_data(X_aux, self.sampling_freq, **self.filt_params_signal)  +                +                #rephase for filtering+                X_aux=np.reshape(inst, [n_epochs, n_channels*n_samples])+                X_n=filter_data(X_aux, self.sampling_freq, **self.filt_params_noise)+                # subtract signal:+                X_n -= X_s+                +                # Estimate single trial covariance+                #reshape to original shape+                X_s=np.reshape(X_s, [n_epochs,n_channels,n_samples])+                self.Xs=X_s+                covs = np.empty((n_epochs, n_channels, n_channels))+                for ii, epoch in enumerate(X_s):+                    covs[ii] = _regularized_covariance(+                        epoch, reg=self.estimator, method_params=self.cov_method_params,+                        rank=self.rank)+                    +                cov_signal = covs.mean(0)+            +                #% Covariance matrix for the flanking frequencies (noise)+                        +                +                +                #reshape to original shape+                X_n=np.reshape(X_n, [n_epochs,n_channels,n_samples])+                # Estimate single trial covariance+                covs_n = np.empty((n_epochs, n_channels, n_channels))+                for ii, epoch in enumerate(X_n):+                    covs_n[ii] = _regularized_covariance(+                        epoch, reg=self.estimator, method_params=self.cov_method_params,+                        rank=self.rank)+        +                cov_noise = covs_n.mean(0)+                       +            +            else:+                raise NotImplementedError()+        +        eigvals_,eigvects_ = eigh(cov_signal.data, cov_noise.data)+        # #sort in descencing order+        ix = np.argsort(eigvals_)[::-1]+        self.eigvals_=eigvals_[ix]

wrong whitespaces.

vpeterson

comment created time in 5 days

Pull request review commentdengemann/mne-python

added option to handle epoched data, sort component with respect to s…

 def freq_mask(freqs, fmin, fmax): fname = data_path() + '/SubjectCMC.ds' raw = mne.io.read_raw_ctf(fname) raw.crop(50., 250.).load_data()  # crop for memory purposes+picks=mne.pick_types(raw.info, meg=True, eeg=False, ref_meg=False)+sf=raw.info['sfreq']  freqs_sig = 9, 12 freqs_noise = 8, 13   class SSD(BaseEstimator, TransformerMixin):-    """Implement Spatio-Spectral Decomposision+    """+    +    This is a Python Implementation of Spatio Spectral Decomposition (SSD) +    method [1],[2] for both raw and epoched data. This source code is  based on+    the matlab implementation available at +    https://github.com/svendaehne/matlab_SPoC/tree/master/SSD and the PR MNE-based+    implementation of Denis A. Engemann <denis.engemann@gmail.com>+    +    SSD seeks at maximizing the power at a frequency band of interest while+    simultaneously minimizing it at the flanking (surrounding) frequency bins+    (considered noise). It extremizes the covariance matrices associated to +    signal and noise.+    +    Cosidering f as the freq. of interest, noise signals can be calculated+    either by filtering the signals in the frequency range [f−Δfb:f+Δfb] and then +    performing band-stop filtering around frequency f [f−Δfs:f+Δfs], where Δfb+    and Δfs generally are set equal to 2 and 1 Hz, or by filtering +    in the frequency range [f−Δf:f+Δf] with the following subtraction of +    the filtered signal around f [1]. +    +    SSD can either be used as a dimentionality reduction method or a denoised +    ‘denoised’ low rank factorization method [2].+              Parameters     ----------     filt_params_signal : dict         Filtering for the frequencies of interst.     filt_params_noise  : dict         Filtering for the frequencies of non-interest.-    estimator : str-        Which covariance estimator to use. Defaults to "oas".-    n_components  : int, None-        How many components to keep. Default to 5.-    subtract_signal : bool-        Whether to subtract the noise from the signal to enhcane-        sptial filter.-    sort_by_spectral_ratio : bool-        Whether to sort by the spectral ratio. Defaults to True.-+    sampling_freq : float+        sampling frequency (in Hz) of the recordings.+    estimator : float | str | None (default 'oas')+        Which covariance estimator to use+        If not None (same as 'empirical'), allow regularization for+        covariance estimation. If float, shrinkage is used +        (0 <= shrinkage <= 1). For str options, estimator will be passed to method +        to mne.compute_covariance().    +    n_components : int| None (default None)+        The number of components to decompose the signals. +        If n_components is None no dimentionality reduction is made, and the +        transformed data is projected in the whole source space.+   picks: array| int | None  (default None)+       Indeces of good-channels. Can be the output of mne.pick_types+ +   sort_by_spectral_ratio: bool (default True)+       if set to True, the components are sorted according to the spectral ratio+       See [1] Nikulin 2011, Eq. (24)+       +   return_filtered : bool (default False)+        If return_filtered is True, data is bandpassed and projected onto +        the SSD components.+        +   n_fft: int (default None)+       if sort_by_spectral_ratio is set to True, then the sources will be sorted+       accordinly to their spectral ratio which is calculated based on +       "psd_array_welch" function. the n_fft set the length of FFT used.+       See mne.time_frequency.psd_array_welch for more information+    +   cov_method_params : TYPE, optional+        As in mne.decoding.SPoC +        The default is None.+   rank : None | dict | ‘info’ | ‘full’+        As in mne.decoding.SPoC +        This controls the rank computation that can be read from the+        measurement info or estimated from the data. +        See Notes of mne.compute_rank() for details.The default is None.+        The default is None.++    +    REFERENCES:+    [1] Nikulin, V. V., Nolte, G., & Curio, G. (2011). A novel method for +    reliable and fast extraction of neuronal EEG/MEG oscillations on the basis +    of spatio-spectral decomposition. NeuroImage, 55(4), 1528-1535.+    [2] Haufe, S., Dähne, S., & Nikulin, V. V. (2014). Dimensionality reduction+    for the analysis of brain oscillations. NeuroImage, 101, 583-597.+    +    +                 """ -    def __init__(self, filt_params_signal, filt_params_noise,-                 estimator='oas', n_components=None,-                 subtract_signal=True,-                 reject=None,-                 flat=None,-                 picks=None,-                 sort_by_spectral_ratio=True):+    def __init__(self, filt_params_signal, filt_params_noise, sampling_freq,+                 estimator='oas', n_components=None, picks=None,+                 sort_by_spectral_ratio=True, return_filtered=False, n_fft=None, cov_method_params=None, rank=None):+                 """Initialize instance"""          dicts = {"signal": filt_params_signal, "noise": filt_params_noise}         for param, dd in [('l', 0), ('h', 0), ('l', 1), ('h', 1)]:             key = ('signal', 'noise')[dd]             if  param + '_freq' not in dicts[key]:                 raise ValueError(-                    "'%' must be defined in filter parameters for %s" % key)+                    "'%%' must be defined in filter parameters for %s" % key)             val = dicts[key][param + '_freq']             if not isinstance(val, (int, float)):                 raise ValueError(                     "Frequencies must be numbers, got %s" % type(val))+       +          #check freq bands+        if (filt_params_noise['l_freq'] > filt_params_signal['l_freq'] or  +                filt_params_signal['h_freq']>filt_params_noise['h_freq']):+            raise ValueError('Wrongly specified frequency bands!\nThe signal band-pass must be within the t noise band-pass!')          self.freqs_signal = (filt_params_signal['l_freq'],                              filt_params_signal['h_freq'])         self.freqs_noise = (filt_params_noise['l_freq'],                             filt_params_noise['h_freq'])+        +        +                       self.filt_params_signal = filt_params_signal         self.filt_params_noise = filt_params_noise-        self.subtract_signal = subtract_signal-        self.picks = picks+        self.sort_by_spectral_ratio = sort_by_spectral_ratio+        if n_fft is None:+            self.n_fft= int(sampling_freq)+        else:+            self.n_fft=int(n_fft)+        self.picks_ = picks+        +        self.return_filtered=return_filtered+        +                self.estimator = estimator         self.n_components = n_components-+        self.rank = rank+        self.sampling_freq=sampling_freq      +        self.cov_method_params = cov_method_params+        +         def fit(self, inst):         """Fit"""-        if self.picks == None:-            self.picks_ = mne.pick_types(inst.info, meg=True, eeg=False, ref_meg=False)-        else:-            self.picks_ = self.picks-        if isinstance(inst, mne.io.base.BaseRaw):+        +        +        if isinstance(inst, BaseRaw):+            if self.picks_ is None:+                raise ValueError('picks should be provided')+            self.max_components=len(self.picks_)             inst_signal = inst.copy()             inst_signal.filter(picks=self.picks_, **self.filt_params_signal)-+            self.Xs=inst_signal+            #noise             inst_noise = inst.copy()             inst_noise.filter(picks=self.picks_, **self.filt_params_noise)-            if self.subtract_signal:-                inst_noise._data[self.picks_] -= inst_signal._data[self.picks_]-            cov_signal = mne.compute_raw_covariance(-                inst_signal, picks=self.picks_, method=self.estimator)-            cov_noise = mne.compute_raw_covariance(inst_noise, picks=self.picks_,-                method=self.estimator)+            # subtract signal:+            inst_noise._data[self.picks_] -= inst_signal._data[self.picks_]+           +            cov_signal = compute_raw_covariance(+                inst_signal, picks=self.picks_, method=self.estimator, rank=self.rank)+            cov_noise = compute_raw_covariance(inst_noise, picks=self.picks_,+                method=self.estimator, rank=self.rank)             del inst_noise             del inst_signal         else:-            raise NotImplementedError()+            if isinstance(inst, BaseEpochs)  or isinstance(inst, np.ndarray):+            # data X is epoched +            # part of the following code is copied from mne csp+                n_epochs, n_channels, n_samples = inst.shape+                self.max_components=n_channels+              +                #reshape for filtering+                X_aux=np.reshape(inst, [n_epochs, n_channels*n_samples])+                X_s=filter_data(X_aux, self.sampling_freq, **self.filt_params_signal)  +                +                #rephase for filtering+                X_aux=np.reshape(inst, [n_epochs, n_channels*n_samples])+                X_n=filter_data(X_aux, self.sampling_freq, **self.filt_params_noise)+                # subtract signal:+                X_n -= X_s+                +                # Estimate single trial covariance+                #reshape to original shape+                X_s=np.reshape(X_s, [n_epochs,n_channels,n_samples])+                self.Xs=X_s+                covs = np.empty((n_epochs, n_channels, n_channels))+                for ii, epoch in enumerate(X_s):+                    covs[ii] = _regularized_covariance(+                        epoch, reg=self.estimator, method_params=self.cov_method_params,+                        rank=self.rank)+                    +                cov_signal = covs.mean(0)+            +                #% Covariance matrix for the flanking frequencies (noise)+                        +                +                +                #reshape to original shape+                X_n=np.reshape(X_n, [n_epochs,n_channels,n_samples])+                # Estimate single trial covariance+                covs_n = np.empty((n_epochs, n_channels, n_channels))+                for ii, epoch in enumerate(X_n):+                    covs_n[ii] = _regularized_covariance(+                        epoch, reg=self.estimator, method_params=self.cov_method_params,+                        rank=self.rank)+        +                cov_noise = covs_n.mean(0)

Same logic applies here.

vpeterson

comment created time in 5 days

Pull request review commentdengemann/mne-python

added option to handle epoched data, sort component with respect to s…

 def freq_mask(freqs, fmin, fmax): fname = data_path() + '/SubjectCMC.ds' raw = mne.io.read_raw_ctf(fname) raw.crop(50., 250.).load_data()  # crop for memory purposes+picks=mne.pick_types(raw.info, meg=True, eeg=False, ref_meg=False)+sf=raw.info['sfreq']  freqs_sig = 9, 12 freqs_noise = 8, 13   class SSD(BaseEstimator, TransformerMixin):-    """Implement Spatio-Spectral Decomposision+    """+    +    This is a Python Implementation of Spatio Spectral Decomposition (SSD) +    method [1],[2] for both raw and epoched data. This source code is  based on+    the matlab implementation available at +    https://github.com/svendaehne/matlab_SPoC/tree/master/SSD and the PR MNE-based+    implementation of Denis A. Engemann <denis.engemann@gmail.com>+    +    SSD seeks at maximizing the power at a frequency band of interest while+    simultaneously minimizing it at the flanking (surrounding) frequency bins+    (considered noise). It extremizes the covariance matrices associated to +    signal and noise.+    +    Cosidering f as the freq. of interest, noise signals can be calculated+    either by filtering the signals in the frequency range [f−Δfb:f+Δfb] and then +    performing band-stop filtering around frequency f [f−Δfs:f+Δfs], where Δfb+    and Δfs generally are set equal to 2 and 1 Hz, or by filtering +    in the frequency range [f−Δf:f+Δf] with the following subtraction of +    the filtered signal around f [1]. +    +    SSD can either be used as a dimentionality reduction method or a denoised +    ‘denoised’ low rank factorization method [2].+              Parameters     ----------     filt_params_signal : dict         Filtering for the frequencies of interst.     filt_params_noise  : dict         Filtering for the frequencies of non-interest.-    estimator : str-        Which covariance estimator to use. Defaults to "oas".-    n_components  : int, None-        How many components to keep. Default to 5.-    subtract_signal : bool-        Whether to subtract the noise from the signal to enhcane-        sptial filter.-    sort_by_spectral_ratio : bool-        Whether to sort by the spectral ratio. Defaults to True.-+    sampling_freq : float+        sampling frequency (in Hz) of the recordings.+    estimator : float | str | None (default 'oas')+        Which covariance estimator to use+        If not None (same as 'empirical'), allow regularization for+        covariance estimation. If float, shrinkage is used +        (0 <= shrinkage <= 1). For str options, estimator will be passed to method +        to mne.compute_covariance().    +    n_components : int| None (default None)+        The number of components to decompose the signals. +        If n_components is None no dimentionality reduction is made, and the +        transformed data is projected in the whole source space.+   picks: array| int | None  (default None)+       Indeces of good-channels. Can be the output of mne.pick_types+ +   sort_by_spectral_ratio: bool (default True)+       if set to True, the components are sorted according to the spectral ratio+       See [1] Nikulin 2011, Eq. (24)+       +   return_filtered : bool (default False)+        If return_filtered is True, data is bandpassed and projected onto +        the SSD components.+        +   n_fft: int (default None)+       if sort_by_spectral_ratio is set to True, then the sources will be sorted+       accordinly to their spectral ratio which is calculated based on +       "psd_array_welch" function. the n_fft set the length of FFT used.+       See mne.time_frequency.psd_array_welch for more information+    +   cov_method_params : TYPE, optional+        As in mne.decoding.SPoC +        The default is None.+   rank : None | dict | ‘info’ | ‘full’+        As in mne.decoding.SPoC +        This controls the rank computation that can be read from the+        measurement info or estimated from the data. +        See Notes of mne.compute_rank() for details.The default is None.+        The default is None.++    +    REFERENCES:+    [1] Nikulin, V. V., Nolte, G., & Curio, G. (2011). A novel method for +    reliable and fast extraction of neuronal EEG/MEG oscillations on the basis +    of spatio-spectral decomposition. NeuroImage, 55(4), 1528-1535.+    [2] Haufe, S., Dähne, S., & Nikulin, V. V. (2014). Dimensionality reduction+    for the analysis of brain oscillations. NeuroImage, 101, 583-597.+    +    +                 """ -    def __init__(self, filt_params_signal, filt_params_noise,-                 estimator='oas', n_components=None,-                 subtract_signal=True,-                 reject=None,-                 flat=None,-                 picks=None,-                 sort_by_spectral_ratio=True):+    def __init__(self, filt_params_signal, filt_params_noise, sampling_freq,+                 estimator='oas', n_components=None, picks=None,+                 sort_by_spectral_ratio=True, return_filtered=False, n_fft=None, cov_method_params=None, rank=None):+                 """Initialize instance"""          dicts = {"signal": filt_params_signal, "noise": filt_params_noise}         for param, dd in [('l', 0), ('h', 0), ('l', 1), ('h', 1)]:             key = ('signal', 'noise')[dd]             if  param + '_freq' not in dicts[key]:                 raise ValueError(-                    "'%' must be defined in filter parameters for %s" % key)+                    "'%%' must be defined in filter parameters for %s" % key)             val = dicts[key][param + '_freq']             if not isinstance(val, (int, float)):                 raise ValueError(                     "Frequencies must be numbers, got %s" % type(val))+       +          #check freq bands+        if (filt_params_noise['l_freq'] > filt_params_signal['l_freq'] or  +                filt_params_signal['h_freq']>filt_params_noise['h_freq']):+            raise ValueError('Wrongly specified frequency bands!\nThe signal band-pass must be within the t noise band-pass!')          self.freqs_signal = (filt_params_signal['l_freq'],                              filt_params_signal['h_freq'])         self.freqs_noise = (filt_params_noise['l_freq'],                             filt_params_noise['h_freq'])+        +        +                       self.filt_params_signal = filt_params_signal         self.filt_params_noise = filt_params_noise-        self.subtract_signal = subtract_signal-        self.picks = picks+        self.sort_by_spectral_ratio = sort_by_spectral_ratio+        if n_fft is None:+            self.n_fft= int(sampling_freq)+        else:+            self.n_fft=int(n_fft)+        self.picks_ = picks+        +        self.return_filtered=return_filtered+        +                self.estimator = estimator         self.n_components = n_components-+        self.rank = rank+        self.sampling_freq=sampling_freq      +        self.cov_method_params = cov_method_params+        +         def fit(self, inst):         """Fit"""-        if self.picks == None:-            self.picks_ = mne.pick_types(inst.info, meg=True, eeg=False, ref_meg=False)-        else:-            self.picks_ = self.picks-        if isinstance(inst, mne.io.base.BaseRaw):+        +        +        if isinstance(inst, BaseRaw):+            if self.picks_ is None:+                raise ValueError('picks should be provided')+            self.max_components=len(self.picks_)             inst_signal = inst.copy()             inst_signal.filter(picks=self.picks_, **self.filt_params_signal)-+            self.Xs=inst_signal+            #noise             inst_noise = inst.copy()             inst_noise.filter(picks=self.picks_, **self.filt_params_noise)-            if self.subtract_signal:-                inst_noise._data[self.picks_] -= inst_signal._data[self.picks_]-            cov_signal = mne.compute_raw_covariance(-                inst_signal, picks=self.picks_, method=self.estimator)-            cov_noise = mne.compute_raw_covariance(inst_noise, picks=self.picks_,-                method=self.estimator)+            # subtract signal:+            inst_noise._data[self.picks_] -= inst_signal._data[self.picks_]+           +            cov_signal = compute_raw_covariance(+                inst_signal, picks=self.picks_, method=self.estimator, rank=self.rank)+            cov_noise = compute_raw_covariance(inst_noise, picks=self.picks_,+                method=self.estimator, rank=self.rank)             del inst_noise             del inst_signal         else:-            raise NotImplementedError()+            if isinstance(inst, BaseEpochs)  or isinstance(inst, np.ndarray):+            # data X is epoched +            # part of the following code is copied from mne csp+                n_epochs, n_channels, n_samples = inst.shape+                self.max_components=n_channels+              +                #reshape for filtering+                X_aux=np.reshape(inst, [n_epochs, n_channels*n_samples])+                X_s=filter_data(X_aux, self.sampling_freq, **self.filt_params_signal)  +                +                #rephase for filtering+                X_aux=np.reshape(inst, [n_epochs, n_channels*n_samples])+                X_n=filter_data(X_aux, self.sampling_freq, **self.filt_params_noise)+                # subtract signal:+                X_n -= X_s+                +                # Estimate single trial covariance+                #reshape to original shape+                X_s=np.reshape(X_s, [n_epochs,n_channels,n_samples])+                self.Xs=X_s+                covs = np.empty((n_epochs, n_channels, n_channels))+                for ii, epoch in enumerate(X_s):+                    covs[ii] = _regularized_covariance(+                        epoch, reg=self.estimator, method_params=self.cov_method_params,+                        rank=self.rank)+                    +                cov_signal = covs.mean(0)+            +                #% Covariance matrix for the flanking frequencies (noise)+                        +                +                +                #reshape to original shape+                X_n=np.reshape(X_n, [n_epochs,n_channels,n_samples])+                # Estimate single trial covariance+                covs_n = np.empty((n_epochs, n_channels, n_channels))+                for ii, epoch in enumerate(X_n):+                    covs_n[ii] = _regularized_covariance(+                        epoch, reg=self.estimator, method_params=self.cov_method_params,+                        rank=self.rank)+        +                cov_noise = covs_n.mean(0)+                       +            +            else:+                raise NotImplementedError()+        +        eigvals_,eigvects_ = eigh(cov_signal.data, cov_noise.data)+        # #sort in descencing order+        ix = np.argsort(eigvals_)[::-1]+        self.eigvals_=eigvals_[ix]+        self.filters_ = eigvects_[:,ix]+        # self.filters_ = eigvects_

please remove commented out code. Documentation-related comments are ok. For code: Either we used it or it does not exist.

vpeterson

comment created time in 5 days

Pull request review commentdengemann/mne-python

added option to handle epoched data, sort component with respect to s…

 def freq_mask(freqs, fmin, fmax): fname = data_path() + '/SubjectCMC.ds' raw = mne.io.read_raw_ctf(fname) raw.crop(50., 250.).load_data()  # crop for memory purposes+picks=mne.pick_types(raw.info, meg=True, eeg=False, ref_meg=False)+sf=raw.info['sfreq']  freqs_sig = 9, 12 freqs_noise = 8, 13   class SSD(BaseEstimator, TransformerMixin):-    """Implement Spatio-Spectral Decomposision+    """+    +    This is a Python Implementation of Spatio Spectral Decomposition (SSD) +    method [1],[2] for both raw and epoched data. This source code is  based on+    the matlab implementation available at +    https://github.com/svendaehne/matlab_SPoC/tree/master/SSD and the PR MNE-based+    implementation of Denis A. Engemann <denis.engemann@gmail.com>+    +    SSD seeks at maximizing the power at a frequency band of interest while+    simultaneously minimizing it at the flanking (surrounding) frequency bins+    (considered noise). It extremizes the covariance matrices associated to +    signal and noise.+    +    Cosidering f as the freq. of interest, noise signals can be calculated+    either by filtering the signals in the frequency range [f−Δfb:f+Δfb] and then +    performing band-stop filtering around frequency f [f−Δfs:f+Δfs], where Δfb+    and Δfs generally are set equal to 2 and 1 Hz, or by filtering +    in the frequency range [f−Δf:f+Δf] with the following subtraction of +    the filtered signal around f [1]. +    +    SSD can either be used as a dimentionality reduction method or a denoised +    ‘denoised’ low rank factorization method [2].+              Parameters     ----------     filt_params_signal : dict         Filtering for the frequencies of interst.     filt_params_noise  : dict         Filtering for the frequencies of non-interest.-    estimator : str-        Which covariance estimator to use. Defaults to "oas".-    n_components  : int, None-        How many components to keep. Default to 5.-    subtract_signal : bool-        Whether to subtract the noise from the signal to enhcane-        sptial filter.-    sort_by_spectral_ratio : bool-        Whether to sort by the spectral ratio. Defaults to True.-+    sampling_freq : float+        sampling frequency (in Hz) of the recordings.+    estimator : float | str | None (default 'oas')+        Which covariance estimator to use+        If not None (same as 'empirical'), allow regularization for+        covariance estimation. If float, shrinkage is used +        (0 <= shrinkage <= 1). For str options, estimator will be passed to method +        to mne.compute_covariance().    +    n_components : int| None (default None)+        The number of components to decompose the signals. +        If n_components is None no dimentionality reduction is made, and the +        transformed data is projected in the whole source space.+   picks: array| int | None  (default None)+       Indeces of good-channels. Can be the output of mne.pick_types+ +   sort_by_spectral_ratio: bool (default True)+       if set to True, the components are sorted according to the spectral ratio+       See [1] Nikulin 2011, Eq. (24)+       +   return_filtered : bool (default False)+        If return_filtered is True, data is bandpassed and projected onto +        the SSD components.+        +   n_fft: int (default None)+       if sort_by_spectral_ratio is set to True, then the sources will be sorted+       accordinly to their spectral ratio which is calculated based on +       "psd_array_welch" function. the n_fft set the length of FFT used.+       See mne.time_frequency.psd_array_welch for more information+    +   cov_method_params : TYPE, optional+        As in mne.decoding.SPoC +        The default is None.+   rank : None | dict | ‘info’ | ‘full’+        As in mne.decoding.SPoC +        This controls the rank computation that can be read from the+        measurement info or estimated from the data. +        See Notes of mne.compute_rank() for details.The default is None.+        The default is None.++    +    REFERENCES:+    [1] Nikulin, V. V., Nolte, G., & Curio, G. (2011). A novel method for +    reliable and fast extraction of neuronal EEG/MEG oscillations on the basis +    of spatio-spectral decomposition. NeuroImage, 55(4), 1528-1535.+    [2] Haufe, S., Dähne, S., & Nikulin, V. V. (2014). Dimensionality reduction+    for the analysis of brain oscillations. NeuroImage, 101, 583-597.+    +    +                 """ -    def __init__(self, filt_params_signal, filt_params_noise,-                 estimator='oas', n_components=None,-                 subtract_signal=True,-                 reject=None,-                 flat=None,-                 picks=None,-                 sort_by_spectral_ratio=True):+    def __init__(self, filt_params_signal, filt_params_noise, sampling_freq,+                 estimator='oas', n_components=None, picks=None,+                 sort_by_spectral_ratio=True, return_filtered=False, n_fft=None, cov_method_params=None, rank=None):+                 """Initialize instance"""          dicts = {"signal": filt_params_signal, "noise": filt_params_noise}         for param, dd in [('l', 0), ('h', 0), ('l', 1), ('h', 1)]:             key = ('signal', 'noise')[dd]             if  param + '_freq' not in dicts[key]:                 raise ValueError(-                    "'%' must be defined in filter parameters for %s" % key)+                    "'%%' must be defined in filter parameters for %s" % key)             val = dicts[key][param + '_freq']             if not isinstance(val, (int, float)):                 raise ValueError(                     "Frequencies must be numbers, got %s" % type(val))+       +          #check freq bands+        if (filt_params_noise['l_freq'] > filt_params_signal['l_freq'] or  +                filt_params_signal['h_freq']>filt_params_noise['h_freq']):+            raise ValueError('Wrongly specified frequency bands!\nThe signal band-pass must be within the t noise band-pass!')          self.freqs_signal = (filt_params_signal['l_freq'],                              filt_params_signal['h_freq'])         self.freqs_noise = (filt_params_noise['l_freq'],                             filt_params_noise['h_freq'])+        +        +                       self.filt_params_signal = filt_params_signal         self.filt_params_noise = filt_params_noise-        self.subtract_signal = subtract_signal-        self.picks = picks+        self.sort_by_spectral_ratio = sort_by_spectral_ratio+        if n_fft is None:+            self.n_fft= int(sampling_freq)+        else:+            self.n_fft=int(n_fft)+        self.picks_ = picks+        +        self.return_filtered=return_filtered+        +                self.estimator = estimator         self.n_components = n_components-+        self.rank = rank+        self.sampling_freq=sampling_freq      +        self.cov_method_params = cov_method_params+        +         def fit(self, inst):         """Fit"""-        if self.picks == None:-            self.picks_ = mne.pick_types(inst.info, meg=True, eeg=False, ref_meg=False)-        else:-            self.picks_ = self.picks-        if isinstance(inst, mne.io.base.BaseRaw):+        +        +        if isinstance(inst, BaseRaw):+            if self.picks_ is None:+                raise ValueError('picks should be provided')+            self.max_components=len(self.picks_)             inst_signal = inst.copy()             inst_signal.filter(picks=self.picks_, **self.filt_params_signal)-+            self.Xs=inst_signal+            #noise             inst_noise = inst.copy()             inst_noise.filter(picks=self.picks_, **self.filt_params_noise)-            if self.subtract_signal:-                inst_noise._data[self.picks_] -= inst_signal._data[self.picks_]-            cov_signal = mne.compute_raw_covariance(-                inst_signal, picks=self.picks_, method=self.estimator)-            cov_noise = mne.compute_raw_covariance(inst_noise, picks=self.picks_,-                method=self.estimator)+            # subtract signal:+            inst_noise._data[self.picks_] -= inst_signal._data[self.picks_]+           +            cov_signal = compute_raw_covariance(+                inst_signal, picks=self.picks_, method=self.estimator, rank=self.rank)+            cov_noise = compute_raw_covariance(inst_noise, picks=self.picks_,+                method=self.estimator, rank=self.rank)             del inst_noise             del inst_signal         else:-            raise NotImplementedError()+            if isinstance(inst, BaseEpochs)  or isinstance(inst, np.ndarray):+            # data X is epoched +            # part of the following code is copied from mne csp+                n_epochs, n_channels, n_samples = inst.shape+                self.max_components=n_channels+              +                #reshape for filtering+                X_aux=np.reshape(inst, [n_epochs, n_channels*n_samples])+                X_s=filter_data(X_aux, self.sampling_freq, **self.filt_params_signal)  +                +                #rephase for filtering+                X_aux=np.reshape(inst, [n_epochs, n_channels*n_samples])+                X_n=filter_data(X_aux, self.sampling_freq, **self.filt_params_noise)+                # subtract signal:+                X_n -= X_s+                +                # Estimate single trial covariance+                #reshape to original shape+                X_s=np.reshape(X_s, [n_epochs,n_channels,n_samples])+                self.Xs=X_s

same here.

vpeterson

comment created time in 5 days

Pull request review commentdengemann/mne-python

added option to handle epoched data, sort component with respect to s…

 def freq_mask(freqs, fmin, fmax): fname = data_path() + '/SubjectCMC.ds' raw = mne.io.read_raw_ctf(fname) raw.crop(50., 250.).load_data()  # crop for memory purposes+picks=mne.pick_types(raw.info, meg=True, eeg=False, ref_meg=False)+sf=raw.info['sfreq']  freqs_sig = 9, 12 freqs_noise = 8, 13   class SSD(BaseEstimator, TransformerMixin):-    """Implement Spatio-Spectral Decomposision+    """+    +    This is a Python Implementation of Spatio Spectral Decomposition (SSD) +    method [1],[2] for both raw and epoched data. This source code is  based on+    the matlab implementation available at +    https://github.com/svendaehne/matlab_SPoC/tree/master/SSD and the PR MNE-based+    implementation of Denis A. Engemann <denis.engemann@gmail.com>+    +    SSD seeks at maximizing the power at a frequency band of interest while+    simultaneously minimizing it at the flanking (surrounding) frequency bins+    (considered noise). It extremizes the covariance matrices associated to +    signal and noise.+    +    Cosidering f as the freq. of interest, noise signals can be calculated+    either by filtering the signals in the frequency range [f−Δfb:f+Δfb] and then +    performing band-stop filtering around frequency f [f−Δfs:f+Δfs], where Δfb+    and Δfs generally are set equal to 2 and 1 Hz, or by filtering +    in the frequency range [f−Δf:f+Δf] with the following subtraction of +    the filtered signal around f [1]. +    +    SSD can either be used as a dimentionality reduction method or a denoised +    ‘denoised’ low rank factorization method [2].+              Parameters     ----------     filt_params_signal : dict         Filtering for the frequencies of interst.     filt_params_noise  : dict         Filtering for the frequencies of non-interest.-    estimator : str-        Which covariance estimator to use. Defaults to "oas".-    n_components  : int, None-        How many components to keep. Default to 5.-    subtract_signal : bool-        Whether to subtract the noise from the signal to enhcane-        sptial filter.-    sort_by_spectral_ratio : bool-        Whether to sort by the spectral ratio. Defaults to True.-+    sampling_freq : float+        sampling frequency (in Hz) of the recordings.+    estimator : float | str | None (default 'oas')+        Which covariance estimator to use+        If not None (same as 'empirical'), allow regularization for+        covariance estimation. If float, shrinkage is used +        (0 <= shrinkage <= 1). For str options, estimator will be passed to method +        to mne.compute_covariance().    +    n_components : int| None (default None)+        The number of components to decompose the signals. +        If n_components is None no dimentionality reduction is made, and the +        transformed data is projected in the whole source space.+   picks: array| int | None  (default None)+       Indeces of good-channels. Can be the output of mne.pick_types+ +   sort_by_spectral_ratio: bool (default True)+       if set to True, the components are sorted according to the spectral ratio+       See [1] Nikulin 2011, Eq. (24)+       +   return_filtered : bool (default False)+        If return_filtered is True, data is bandpassed and projected onto +        the SSD components.+        +   n_fft: int (default None)+       if sort_by_spectral_ratio is set to True, then the sources will be sorted+       accordinly to their spectral ratio which is calculated based on +       "psd_array_welch" function. the n_fft set the length of FFT used.+       See mne.time_frequency.psd_array_welch for more information+    +   cov_method_params : TYPE, optional+        As in mne.decoding.SPoC +        The default is None.+   rank : None | dict | ‘info’ | ‘full’+        As in mne.decoding.SPoC +        This controls the rank computation that can be read from the+        measurement info or estimated from the data. +        See Notes of mne.compute_rank() for details.The default is None.+        The default is None.++    +    REFERENCES:+    [1] Nikulin, V. V., Nolte, G., & Curio, G. (2011). A novel method for +    reliable and fast extraction of neuronal EEG/MEG oscillations on the basis +    of spatio-spectral decomposition. NeuroImage, 55(4), 1528-1535.+    [2] Haufe, S., Dähne, S., & Nikulin, V. V. (2014). Dimensionality reduction+    for the analysis of brain oscillations. NeuroImage, 101, 583-597.+    +    +                 """ -    def __init__(self, filt_params_signal, filt_params_noise,-                 estimator='oas', n_components=None,-                 subtract_signal=True,-                 reject=None,-                 flat=None,-                 picks=None,-                 sort_by_spectral_ratio=True):+    def __init__(self, filt_params_signal, filt_params_noise, sampling_freq,+                 estimator='oas', n_components=None, picks=None,+                 sort_by_spectral_ratio=True, return_filtered=False, n_fft=None, cov_method_params=None, rank=None):+                 """Initialize instance"""          dicts = {"signal": filt_params_signal, "noise": filt_params_noise}         for param, dd in [('l', 0), ('h', 0), ('l', 1), ('h', 1)]:             key = ('signal', 'noise')[dd]             if  param + '_freq' not in dicts[key]:                 raise ValueError(-                    "'%' must be defined in filter parameters for %s" % key)+                    "'%%' must be defined in filter parameters for %s" % key)             val = dicts[key][param + '_freq']             if not isinstance(val, (int, float)):                 raise ValueError(                     "Frequencies must be numbers, got %s" % type(val))+       +          #check freq bands+        if (filt_params_noise['l_freq'] > filt_params_signal['l_freq'] or  +                filt_params_signal['h_freq']>filt_params_noise['h_freq']):+            raise ValueError('Wrongly specified frequency bands!\nThe signal band-pass must be within the t noise band-pass!')          self.freqs_signal = (filt_params_signal['l_freq'],                              filt_params_signal['h_freq'])         self.freqs_noise = (filt_params_noise['l_freq'],                             filt_params_noise['h_freq'])+        +        +                       self.filt_params_signal = filt_params_signal         self.filt_params_noise = filt_params_noise-        self.subtract_signal = subtract_signal-        self.picks = picks+        self.sort_by_spectral_ratio = sort_by_spectral_ratio+        if n_fft is None:+            self.n_fft= int(sampling_freq)+        else:+            self.n_fft=int(n_fft)+        self.picks_ = picks+        +        self.return_filtered=return_filtered+        +                self.estimator = estimator         self.n_components = n_components-+        self.rank = rank+        self.sampling_freq=sampling_freq      +        self.cov_method_params = cov_method_params+        +         def fit(self, inst):         """Fit"""-        if self.picks == None:-            self.picks_ = mne.pick_types(inst.info, meg=True, eeg=False, ref_meg=False)-        else:-            self.picks_ = self.picks-        if isinstance(inst, mne.io.base.BaseRaw):+        +        +        if isinstance(inst, BaseRaw):+            if self.picks_ is None:+                raise ValueError('picks should be provided')+            self.max_components=len(self.picks_)             inst_signal = inst.copy()             inst_signal.filter(picks=self.picks_, **self.filt_params_signal)-+            self.Xs=inst_signal+            #noise             inst_noise = inst.copy()             inst_noise.filter(picks=self.picks_, **self.filt_params_noise)-            if self.subtract_signal:-                inst_noise._data[self.picks_] -= inst_signal._data[self.picks_]-            cov_signal = mne.compute_raw_covariance(-                inst_signal, picks=self.picks_, method=self.estimator)-            cov_noise = mne.compute_raw_covariance(inst_noise, picks=self.picks_,-                method=self.estimator)+            # subtract signal:+            inst_noise._data[self.picks_] -= inst_signal._data[self.picks_]+           +            cov_signal = compute_raw_covariance(+                inst_signal, picks=self.picks_, method=self.estimator, rank=self.rank)+            cov_noise = compute_raw_covariance(inst_noise, picks=self.picks_,+                method=self.estimator, rank=self.rank)             del inst_noise             del inst_signal         else:-            raise NotImplementedError()+            if isinstance(inst, BaseEpochs)  or isinstance(inst, np.ndarray):+            # data X is epoched +            # part of the following code is copied from mne csp+                n_epochs, n_channels, n_samples = inst.shape+                self.max_components=n_channels+              +                #reshape for filtering+                X_aux=np.reshape(inst, [n_epochs, n_channels*n_samples])+                X_s=filter_data(X_aux, self.sampling_freq, **self.filt_params_signal)  +                +                #rephase for filtering+                X_aux=np.reshape(inst, [n_epochs, n_channels*n_samples])+                X_n=filter_data(X_aux, self.sampling_freq, **self.filt_params_noise)+                # subtract signal:+                X_n -= X_s+                +                # Estimate single trial covariance+                #reshape to original shape+                X_s=np.reshape(X_s, [n_epochs,n_channels,n_samples])+                self.Xs=X_s+                covs = np.empty((n_epochs, n_channels, n_channels))+                for ii, epoch in enumerate(X_s):+                    covs[ii] = _regularized_covariance(+                        epoch, reg=self.estimator, method_params=self.cov_method_params,+                        rank=self.rank)+                    +                cov_signal = covs.mean(0)

... it should allow us to get rid of averaging covariances.

vpeterson

comment created time in 5 days

Pull request review commentdengemann/mne-python

added option to handle epoched data, sort component with respect to s…

 def freq_mask(freqs, fmin, fmax): fname = data_path() + '/SubjectCMC.ds' raw = mne.io.read_raw_ctf(fname) raw.crop(50., 250.).load_data()  # crop for memory purposes+picks=mne.pick_types(raw.info, meg=True, eeg=False, ref_meg=False)+sf=raw.info['sfreq']  freqs_sig = 9, 12 freqs_noise = 8, 13   class SSD(BaseEstimator, TransformerMixin):-    """Implement Spatio-Spectral Decomposision+    """+    +    This is a Python Implementation of Spatio Spectral Decomposition (SSD) +    method [1],[2] for both raw and epoched data. This source code is  based on+    the matlab implementation available at +    https://github.com/svendaehne/matlab_SPoC/tree/master/SSD and the PR MNE-based+    implementation of Denis A. Engemann <denis.engemann@gmail.com>+    +    SSD seeks at maximizing the power at a frequency band of interest while+    simultaneously minimizing it at the flanking (surrounding) frequency bins+    (considered noise). It extremizes the covariance matrices associated to +    signal and noise.+    +    Cosidering f as the freq. of interest, noise signals can be calculated+    either by filtering the signals in the frequency range [f−Δfb:f+Δfb] and then +    performing band-stop filtering around frequency f [f−Δfs:f+Δfs], where Δfb+    and Δfs generally are set equal to 2 and 1 Hz, or by filtering +    in the frequency range [f−Δf:f+Δf] with the following subtraction of +    the filtered signal around f [1]. +    +    SSD can either be used as a dimentionality reduction method or a denoised +    ‘denoised’ low rank factorization method [2].+              Parameters     ----------     filt_params_signal : dict         Filtering for the frequencies of interst.     filt_params_noise  : dict         Filtering for the frequencies of non-interest.-    estimator : str-        Which covariance estimator to use. Defaults to "oas".-    n_components  : int, None-        How many components to keep. Default to 5.-    subtract_signal : bool-        Whether to subtract the noise from the signal to enhcane-        sptial filter.-    sort_by_spectral_ratio : bool-        Whether to sort by the spectral ratio. Defaults to True.-+    sampling_freq : float+        sampling frequency (in Hz) of the recordings.+    estimator : float | str | None (default 'oas')+        Which covariance estimator to use+        If not None (same as 'empirical'), allow regularization for+        covariance estimation. If float, shrinkage is used +        (0 <= shrinkage <= 1). For str options, estimator will be passed to method +        to mne.compute_covariance().    +    n_components : int| None (default None)+        The number of components to decompose the signals. +        If n_components is None no dimentionality reduction is made, and the +        transformed data is projected in the whole source space.+   picks: array| int | None  (default None)+       Indeces of good-channels. Can be the output of mne.pick_types+ +   sort_by_spectral_ratio: bool (default True)+       if set to True, the components are sorted according to the spectral ratio+       See [1] Nikulin 2011, Eq. (24)+       +   return_filtered : bool (default False)+        If return_filtered is True, data is bandpassed and projected onto +        the SSD components.+        +   n_fft: int (default None)+       if sort_by_spectral_ratio is set to True, then the sources will be sorted+       accordinly to their spectral ratio which is calculated based on +       "psd_array_welch" function. the n_fft set the length of FFT used.+       See mne.time_frequency.psd_array_welch for more information+    +   cov_method_params : TYPE, optional+        As in mne.decoding.SPoC +        The default is None.+   rank : None | dict | ‘info’ | ‘full’+        As in mne.decoding.SPoC +        This controls the rank computation that can be read from the+        measurement info or estimated from the data. +        See Notes of mne.compute_rank() for details.The default is None.+        The default is None.++    +    REFERENCES:+    [1] Nikulin, V. V., Nolte, G., & Curio, G. (2011). A novel method for +    reliable and fast extraction of neuronal EEG/MEG oscillations on the basis +    of spatio-spectral decomposition. NeuroImage, 55(4), 1528-1535.+    [2] Haufe, S., Dähne, S., & Nikulin, V. V. (2014). Dimensionality reduction+    for the analysis of brain oscillations. NeuroImage, 101, 583-597.+    +    +                 """ -    def __init__(self, filt_params_signal, filt_params_noise,-                 estimator='oas', n_components=None,-                 subtract_signal=True,-                 reject=None,-                 flat=None,-                 picks=None,-                 sort_by_spectral_ratio=True):+    def __init__(self, filt_params_signal, filt_params_noise, sampling_freq,+                 estimator='oas', n_components=None, picks=None,+                 sort_by_spectral_ratio=True, return_filtered=False, n_fft=None, cov_method_params=None, rank=None):+                 """Initialize instance"""          dicts = {"signal": filt_params_signal, "noise": filt_params_noise}         for param, dd in [('l', 0), ('h', 0), ('l', 1), ('h', 1)]:             key = ('signal', 'noise')[dd]             if  param + '_freq' not in dicts[key]:                 raise ValueError(-                    "'%' must be defined in filter parameters for %s" % key)+                    "'%%' must be defined in filter parameters for %s" % key)             val = dicts[key][param + '_freq']             if not isinstance(val, (int, float)):                 raise ValueError(                     "Frequencies must be numbers, got %s" % type(val))+       +          #check freq bands+        if (filt_params_noise['l_freq'] > filt_params_signal['l_freq'] or  +                filt_params_signal['h_freq']>filt_params_noise['h_freq']):+            raise ValueError('Wrongly specified frequency bands!\nThe signal band-pass must be within the t noise band-pass!')          self.freqs_signal = (filt_params_signal['l_freq'],                              filt_params_signal['h_freq'])         self.freqs_noise = (filt_params_noise['l_freq'],                             filt_params_noise['h_freq'])+        +        +                       self.filt_params_signal = filt_params_signal         self.filt_params_noise = filt_params_noise-        self.subtract_signal = subtract_signal-        self.picks = picks+        self.sort_by_spectral_ratio = sort_by_spectral_ratio+        if n_fft is None:+            self.n_fft= int(sampling_freq)+        else:+            self.n_fft=int(n_fft)+        self.picks_ = picks+        +        self.return_filtered=return_filtered+        +                self.estimator = estimator         self.n_components = n_components-+        self.rank = rank+        self.sampling_freq=sampling_freq      +        self.cov_method_params = cov_method_params+        +         def fit(self, inst):         """Fit"""-        if self.picks == None:-            self.picks_ = mne.pick_types(inst.info, meg=True, eeg=False, ref_meg=False)-        else:-            self.picks_ = self.picks-        if isinstance(inst, mne.io.base.BaseRaw):+        +        +        if isinstance(inst, BaseRaw):+            if self.picks_ is None:+                raise ValueError('picks should be provided')+            self.max_components=len(self.picks_)             inst_signal = inst.copy()             inst_signal.filter(picks=self.picks_, **self.filt_params_signal)-+            self.Xs=inst_signal+            #noise             inst_noise = inst.copy()             inst_noise.filter(picks=self.picks_, **self.filt_params_noise)-            if self.subtract_signal:-                inst_noise._data[self.picks_] -= inst_signal._data[self.picks_]-            cov_signal = mne.compute_raw_covariance(-                inst_signal, picks=self.picks_, method=self.estimator)-            cov_noise = mne.compute_raw_covariance(inst_noise, picks=self.picks_,-                method=self.estimator)+            # subtract signal:+            inst_noise._data[self.picks_] -= inst_signal._data[self.picks_]+           +            cov_signal = compute_raw_covariance(+                inst_signal, picks=self.picks_, method=self.estimator, rank=self.rank)+            cov_noise = compute_raw_covariance(inst_noise, picks=self.picks_,+                method=self.estimator, rank=self.rank)             del inst_noise             del inst_signal         else:-            raise NotImplementedError()+            if isinstance(inst, BaseEpochs)  or isinstance(inst, np.ndarray):+            # data X is epoched +            # part of the following code is copied from mne csp+                n_epochs, n_channels, n_samples = inst.shape+                self.max_components=n_channels+              +                #reshape for filtering+                X_aux=np.reshape(inst, [n_epochs, n_channels*n_samples])+                X_s=filter_data(X_aux, self.sampling_freq, **self.filt_params_signal)  +                +                #rephase for filtering+                X_aux=np.reshape(inst, [n_epochs, n_channels*n_samples])+                X_n=filter_data(X_aux, self.sampling_freq, **self.filt_params_noise)+                # subtract signal:+                X_n -= X_s+                +                # Estimate single trial covariance+                #reshape to original shape+                X_s=np.reshape(X_s, [n_epochs,n_channels,n_samples])+                self.Xs=X_s+                covs = np.empty((n_epochs, n_channels, n_channels))+                for ii, epoch in enumerate(X_s):

I am wondering if this is really necessary. Why not just use mne.compute_covariance based on the epochs, or at least the approach of concatenating the signals before covariance computation ...

vpeterson

comment created time in 5 days

Pull request review commentdengemann/mne-python

added option to handle epoched data, sort component with respect to s…

 def freq_mask(freqs, fmin, fmax): fname = data_path() + '/SubjectCMC.ds' raw = mne.io.read_raw_ctf(fname) raw.crop(50., 250.).load_data()  # crop for memory purposes+picks=mne.pick_types(raw.info, meg=True, eeg=False, ref_meg=False)+sf=raw.info['sfreq']  freqs_sig = 9, 12 freqs_noise = 8, 13   class SSD(BaseEstimator, TransformerMixin):-    """Implement Spatio-Spectral Decomposision+    """+    +    This is a Python Implementation of Spatio Spectral Decomposition (SSD) +    method [1],[2] for both raw and epoched data. This source code is  based on+    the matlab implementation available at +    https://github.com/svendaehne/matlab_SPoC/tree/master/SSD and the PR MNE-based+    implementation of Denis A. Engemann <denis.engemann@gmail.com>+    +    SSD seeks at maximizing the power at a frequency band of interest while+    simultaneously minimizing it at the flanking (surrounding) frequency bins+    (considered noise). It extremizes the covariance matrices associated to +    signal and noise.+    +    Cosidering f as the freq. of interest, noise signals can be calculated+    either by filtering the signals in the frequency range [f−Δfb:f+Δfb] and then +    performing band-stop filtering around frequency f [f−Δfs:f+Δfs], where Δfb+    and Δfs generally are set equal to 2 and 1 Hz, or by filtering +    in the frequency range [f−Δf:f+Δf] with the following subtraction of +    the filtered signal around f [1]. +    +    SSD can either be used as a dimentionality reduction method or a denoised +    ‘denoised’ low rank factorization method [2].+              Parameters     ----------     filt_params_signal : dict         Filtering for the frequencies of interst.     filt_params_noise  : dict         Filtering for the frequencies of non-interest.-    estimator : str-        Which covariance estimator to use. Defaults to "oas".-    n_components  : int, None-        How many components to keep. Default to 5.-    subtract_signal : bool-        Whether to subtract the noise from the signal to enhcane-        sptial filter.-    sort_by_spectral_ratio : bool-        Whether to sort by the spectral ratio. Defaults to True.-+    sampling_freq : float+        sampling frequency (in Hz) of the recordings.+    estimator : float | str | None (default 'oas')+        Which covariance estimator to use+        If not None (same as 'empirical'), allow regularization for+        covariance estimation. If float, shrinkage is used +        (0 <= shrinkage <= 1). For str options, estimator will be passed to method +        to mne.compute_covariance().    +    n_components : int| None (default None)+        The number of components to decompose the signals. +        If n_components is None no dimentionality reduction is made, and the +        transformed data is projected in the whole source space.+   picks: array| int | None  (default None)+       Indeces of good-channels. Can be the output of mne.pick_types+ +   sort_by_spectral_ratio: bool (default True)+       if set to True, the components are sorted according to the spectral ratio+       See [1] Nikulin 2011, Eq. (24)+       +   return_filtered : bool (default False)+        If return_filtered is True, data is bandpassed and projected onto +        the SSD components.+        +   n_fft: int (default None)+       if sort_by_spectral_ratio is set to True, then the sources will be sorted+       accordinly to their spectral ratio which is calculated based on +       "psd_array_welch" function. the n_fft set the length of FFT used.+       See mne.time_frequency.psd_array_welch for more information+    +   cov_method_params : TYPE, optional+        As in mne.decoding.SPoC +        The default is None.+   rank : None | dict | ‘info’ | ‘full’+        As in mne.decoding.SPoC +        This controls the rank computation that can be read from the+        measurement info or estimated from the data. +        See Notes of mne.compute_rank() for details.The default is None.+        The default is None.++    +    REFERENCES:+    [1] Nikulin, V. V., Nolte, G., & Curio, G. (2011). A novel method for +    reliable and fast extraction of neuronal EEG/MEG oscillations on the basis +    of spatio-spectral decomposition. NeuroImage, 55(4), 1528-1535.+    [2] Haufe, S., Dähne, S., & Nikulin, V. V. (2014). Dimensionality reduction+    for the analysis of brain oscillations. NeuroImage, 101, 583-597.+    +    +                 """ -    def __init__(self, filt_params_signal, filt_params_noise,-                 estimator='oas', n_components=None,-                 subtract_signal=True,-                 reject=None,-                 flat=None,-                 picks=None,-                 sort_by_spectral_ratio=True):+    def __init__(self, filt_params_signal, filt_params_noise, sampling_freq,+                 estimator='oas', n_components=None, picks=None,+                 sort_by_spectral_ratio=True, return_filtered=False, n_fft=None, cov_method_params=None, rank=None):+                 """Initialize instance"""          dicts = {"signal": filt_params_signal, "noise": filt_params_noise}         for param, dd in [('l', 0), ('h', 0), ('l', 1), ('h', 1)]:             key = ('signal', 'noise')[dd]             if  param + '_freq' not in dicts[key]:                 raise ValueError(-                    "'%' must be defined in filter parameters for %s" % key)+                    "'%%' must be defined in filter parameters for %s" % key)             val = dicts[key][param + '_freq']             if not isinstance(val, (int, float)):                 raise ValueError(                     "Frequencies must be numbers, got %s" % type(val))+       +          #check freq bands+        if (filt_params_noise['l_freq'] > filt_params_signal['l_freq'] or  +                filt_params_signal['h_freq']>filt_params_noise['h_freq']):+            raise ValueError('Wrongly specified frequency bands!\nThe signal band-pass must be within the t noise band-pass!')          self.freqs_signal = (filt_params_signal['l_freq'],                              filt_params_signal['h_freq'])         self.freqs_noise = (filt_params_noise['l_freq'],                             filt_params_noise['h_freq'])+        +        +                       self.filt_params_signal = filt_params_signal         self.filt_params_noise = filt_params_noise-        self.subtract_signal = subtract_signal-        self.picks = picks+        self.sort_by_spectral_ratio = sort_by_spectral_ratio+        if n_fft is None:+            self.n_fft= int(sampling_freq)+        else:+            self.n_fft=int(n_fft)+        self.picks_ = picks+        +        self.return_filtered=return_filtered+        +                self.estimator = estimator         self.n_components = n_components-+        self.rank = rank+        self.sampling_freq=sampling_freq      +        self.cov_method_params = cov_method_params+        +         def fit(self, inst):         """Fit"""-        if self.picks == None:-            self.picks_ = mne.pick_types(inst.info, meg=True, eeg=False, ref_meg=False)-        else:-            self.picks_ = self.picks-        if isinstance(inst, mne.io.base.BaseRaw):+        +        +        if isinstance(inst, BaseRaw):+            if self.picks_ is None:+                raise ValueError('picks should be provided')+            self.max_components=len(self.picks_)             inst_signal = inst.copy()             inst_signal.filter(picks=self.picks_, **self.filt_params_signal)-+            self.Xs=inst_signal+            #noise             inst_noise = inst.copy()             inst_noise.filter(picks=self.picks_, **self.filt_params_noise)-            if self.subtract_signal:-                inst_noise._data[self.picks_] -= inst_signal._data[self.picks_]-            cov_signal = mne.compute_raw_covariance(-                inst_signal, picks=self.picks_, method=self.estimator)-            cov_noise = mne.compute_raw_covariance(inst_noise, picks=self.picks_,-                method=self.estimator)+            # subtract signal:+            inst_noise._data[self.picks_] -= inst_signal._data[self.picks_]+           +            cov_signal = compute_raw_covariance(+                inst_signal, picks=self.picks_, method=self.estimator, rank=self.rank)+            cov_noise = compute_raw_covariance(inst_noise, picks=self.picks_,+                method=self.estimator, rank=self.rank)             del inst_noise             del inst_signal         else:-            raise NotImplementedError()+            if isinstance(inst, BaseEpochs)  or isinstance(inst, np.ndarray):+            # data X is epoched +            # part of the following code is copied from mne csp+                n_epochs, n_channels, n_samples = inst.shape+                self.max_components=n_channels+              +                #reshape for filtering+                X_aux=np.reshape(inst, [n_epochs, n_channels*n_samples])+                X_s=filter_data(X_aux, self.sampling_freq, **self.filt_params_signal)  +                +                #rephase for filtering+                X_aux=np.reshape(inst, [n_epochs, n_channels*n_samples])+                X_n=filter_data(X_aux, self.sampling_freq, **self.filt_params_noise)

Here whitespaces are ok.

vpeterson

comment created time in 5 days

Pull request review commentdengemann/mne-python

added option to handle epoched data, sort component with respect to s…

 def freq_mask(freqs, fmin, fmax): fname = data_path() + '/SubjectCMC.ds' raw = mne.io.read_raw_ctf(fname) raw.crop(50., 250.).load_data()  # crop for memory purposes+picks=mne.pick_types(raw.info, meg=True, eeg=False, ref_meg=False)+sf=raw.info['sfreq']  freqs_sig = 9, 12 freqs_noise = 8, 13   class SSD(BaseEstimator, TransformerMixin):-    """Implement Spatio-Spectral Decomposision+    """+    +    This is a Python Implementation of Spatio Spectral Decomposition (SSD) +    method [1],[2] for both raw and epoched data. This source code is  based on+    the matlab implementation available at +    https://github.com/svendaehne/matlab_SPoC/tree/master/SSD and the PR MNE-based+    implementation of Denis A. Engemann <denis.engemann@gmail.com>+    +    SSD seeks at maximizing the power at a frequency band of interest while+    simultaneously minimizing it at the flanking (surrounding) frequency bins+    (considered noise). It extremizes the covariance matrices associated to +    signal and noise.+    +    Cosidering f as the freq. of interest, noise signals can be calculated+    either by filtering the signals in the frequency range [f−Δfb:f+Δfb] and then +    performing band-stop filtering around frequency f [f−Δfs:f+Δfs], where Δfb+    and Δfs generally are set equal to 2 and 1 Hz, or by filtering +    in the frequency range [f−Δf:f+Δf] with the following subtraction of +    the filtered signal around f [1]. +    +    SSD can either be used as a dimentionality reduction method or a denoised +    ‘denoised’ low rank factorization method [2].+              Parameters     ----------     filt_params_signal : dict         Filtering for the frequencies of interst.     filt_params_noise  : dict         Filtering for the frequencies of non-interest.-    estimator : str-        Which covariance estimator to use. Defaults to "oas".-    n_components  : int, None-        How many components to keep. Default to 5.-    subtract_signal : bool-        Whether to subtract the noise from the signal to enhcane-        sptial filter.-    sort_by_spectral_ratio : bool-        Whether to sort by the spectral ratio. Defaults to True.-+    sampling_freq : float+        sampling frequency (in Hz) of the recordings.+    estimator : float | str | None (default 'oas')+        Which covariance estimator to use+        If not None (same as 'empirical'), allow regularization for+        covariance estimation. If float, shrinkage is used +        (0 <= shrinkage <= 1). For str options, estimator will be passed to method +        to mne.compute_covariance().    +    n_components : int| None (default None)+        The number of components to decompose the signals. +        If n_components is None no dimentionality reduction is made, and the +        transformed data is projected in the whole source space.+   picks: array| int | None  (default None)+       Indeces of good-channels. Can be the output of mne.pick_types+ +   sort_by_spectral_ratio: bool (default True)+       if set to True, the components are sorted according to the spectral ratio+       See [1] Nikulin 2011, Eq. (24)+       +   return_filtered : bool (default False)+        If return_filtered is True, data is bandpassed and projected onto +        the SSD components.+        +   n_fft: int (default None)+       if sort_by_spectral_ratio is set to True, then the sources will be sorted+       accordinly to their spectral ratio which is calculated based on +       "psd_array_welch" function. the n_fft set the length of FFT used.+       See mne.time_frequency.psd_array_welch for more information+    +   cov_method_params : TYPE, optional+        As in mne.decoding.SPoC +        The default is None.+   rank : None | dict | ‘info’ | ‘full’+        As in mne.decoding.SPoC +        This controls the rank computation that can be read from the+        measurement info or estimated from the data. +        See Notes of mne.compute_rank() for details.The default is None.+        The default is None.++    +    REFERENCES:+    [1] Nikulin, V. V., Nolte, G., & Curio, G. (2011). A novel method for +    reliable and fast extraction of neuronal EEG/MEG oscillations on the basis +    of spatio-spectral decomposition. NeuroImage, 55(4), 1528-1535.+    [2] Haufe, S., Dähne, S., & Nikulin, V. V. (2014). Dimensionality reduction+    for the analysis of brain oscillations. NeuroImage, 101, 583-597.+    +    +                 """ -    def __init__(self, filt_params_signal, filt_params_noise,-                 estimator='oas', n_components=None,-                 subtract_signal=True,-                 reject=None,-                 flat=None,-                 picks=None,-                 sort_by_spectral_ratio=True):+    def __init__(self, filt_params_signal, filt_params_noise, sampling_freq,+                 estimator='oas', n_components=None, picks=None,+                 sort_by_spectral_ratio=True, return_filtered=False, n_fft=None, cov_method_params=None, rank=None):+                 """Initialize instance"""          dicts = {"signal": filt_params_signal, "noise": filt_params_noise}         for param, dd in [('l', 0), ('h', 0), ('l', 1), ('h', 1)]:             key = ('signal', 'noise')[dd]             if  param + '_freq' not in dicts[key]:                 raise ValueError(-                    "'%' must be defined in filter parameters for %s" % key)+                    "'%%' must be defined in filter parameters for %s" % key)             val = dicts[key][param + '_freq']             if not isinstance(val, (int, float)):                 raise ValueError(                     "Frequencies must be numbers, got %s" % type(val))+       +          #check freq bands+        if (filt_params_noise['l_freq'] > filt_params_signal['l_freq'] or  +                filt_params_signal['h_freq']>filt_params_noise['h_freq']):+            raise ValueError('Wrongly specified frequency bands!\nThe signal band-pass must be within the t noise band-pass!')          self.freqs_signal = (filt_params_signal['l_freq'],                              filt_params_signal['h_freq'])         self.freqs_noise = (filt_params_noise['l_freq'],                             filt_params_noise['h_freq'])+        +        +                       self.filt_params_signal = filt_params_signal         self.filt_params_noise = filt_params_noise-        self.subtract_signal = subtract_signal-        self.picks = picks+        self.sort_by_spectral_ratio = sort_by_spectral_ratio+        if n_fft is None:+            self.n_fft= int(sampling_freq)+        else:+            self.n_fft=int(n_fft)+        self.picks_ = picks+        +        self.return_filtered=return_filtered+        +                self.estimator = estimator         self.n_components = n_components-+        self.rank = rank+        self.sampling_freq=sampling_freq      +        self.cov_method_params = cov_method_params+        +         def fit(self, inst):         """Fit"""-        if self.picks == None:-            self.picks_ = mne.pick_types(inst.info, meg=True, eeg=False, ref_meg=False)-        else:-            self.picks_ = self.picks-        if isinstance(inst, mne.io.base.BaseRaw):+        +        +        if isinstance(inst, BaseRaw):+            if self.picks_ is None:+                raise ValueError('picks should be provided')+            self.max_components=len(self.picks_)             inst_signal = inst.copy()             inst_signal.filter(picks=self.picks_, **self.filt_params_signal)-+            self.Xs=inst_signal+            #noise             inst_noise = inst.copy()             inst_noise.filter(picks=self.picks_, **self.filt_params_noise)-            if self.subtract_signal:-                inst_noise._data[self.picks_] -= inst_signal._data[self.picks_]-            cov_signal = mne.compute_raw_covariance(-                inst_signal, picks=self.picks_, method=self.estimator)-            cov_noise = mne.compute_raw_covariance(inst_noise, picks=self.picks_,-                method=self.estimator)+            # subtract signal:+            inst_noise._data[self.picks_] -= inst_signal._data[self.picks_]+           +            cov_signal = compute_raw_covariance(+                inst_signal, picks=self.picks_, method=self.estimator, rank=self.rank)+            cov_noise = compute_raw_covariance(inst_noise, picks=self.picks_,+                method=self.estimator, rank=self.rank)             del inst_noise             del inst_signal         else:-            raise NotImplementedError()+            if isinstance(inst, BaseEpochs)  or isinstance(inst, np.ndarray):+            # data X is epoched +            # part of the following code is copied from mne csp+                n_epochs, n_channels, n_samples = inst.shape+                self.max_components=n_channels+              +                #reshape for filtering+                X_aux=np.reshape(inst, [n_epochs, n_channels*n_samples])+                X_s=filter_data(X_aux, self.sampling_freq, **self.filt_params_signal)  +                +                #rephase for filtering+                X_aux=np.reshape(inst, [n_epochs, n_channels*n_samples])

Please have a look at the canonical handling of whitespaces. Between operators there should be whitespaces in cases such as multiplication, addition etc.

vpeterson

comment created time in 5 days

Pull request review commentdengemann/mne-python

added option to handle epoched data, sort component with respect to s…

 def freq_mask(freqs, fmin, fmax): fname = data_path() + '/SubjectCMC.ds' raw = mne.io.read_raw_ctf(fname) raw.crop(50., 250.).load_data()  # crop for memory purposes+picks=mne.pick_types(raw.info, meg=True, eeg=False, ref_meg=False)+sf=raw.info['sfreq']  freqs_sig = 9, 12 freqs_noise = 8, 13   class SSD(BaseEstimator, TransformerMixin):-    """Implement Spatio-Spectral Decomposision+    """+    +    This is a Python Implementation of Spatio Spectral Decomposition (SSD) +    method [1],[2] for both raw and epoched data. This source code is  based on+    the matlab implementation available at +    https://github.com/svendaehne/matlab_SPoC/tree/master/SSD and the PR MNE-based+    implementation of Denis A. Engemann <denis.engemann@gmail.com>+    +    SSD seeks at maximizing the power at a frequency band of interest while+    simultaneously minimizing it at the flanking (surrounding) frequency bins+    (considered noise). It extremizes the covariance matrices associated to +    signal and noise.+    +    Cosidering f as the freq. of interest, noise signals can be calculated+    either by filtering the signals in the frequency range [f−Δfb:f+Δfb] and then +    performing band-stop filtering around frequency f [f−Δfs:f+Δfs], where Δfb+    and Δfs generally are set equal to 2 and 1 Hz, or by filtering +    in the frequency range [f−Δf:f+Δf] with the following subtraction of +    the filtered signal around f [1]. +    +    SSD can either be used as a dimentionality reduction method or a denoised +    ‘denoised’ low rank factorization method [2].+              Parameters     ----------     filt_params_signal : dict         Filtering for the frequencies of interst.     filt_params_noise  : dict         Filtering for the frequencies of non-interest.-    estimator : str-        Which covariance estimator to use. Defaults to "oas".-    n_components  : int, None-        How many components to keep. Default to 5.-    subtract_signal : bool-        Whether to subtract the noise from the signal to enhcane-        sptial filter.-    sort_by_spectral_ratio : bool-        Whether to sort by the spectral ratio. Defaults to True.-+    sampling_freq : float+        sampling frequency (in Hz) of the recordings.+    estimator : float | str | None (default 'oas')+        Which covariance estimator to use+        If not None (same as 'empirical'), allow regularization for+        covariance estimation. If float, shrinkage is used +        (0 <= shrinkage <= 1). For str options, estimator will be passed to method +        to mne.compute_covariance().    +    n_components : int| None (default None)+        The number of components to decompose the signals. +        If n_components is None no dimentionality reduction is made, and the +        transformed data is projected in the whole source space.+   picks: array| int | None  (default None)+       Indeces of good-channels. Can be the output of mne.pick_types+ +   sort_by_spectral_ratio: bool (default True)+       if set to True, the components are sorted according to the spectral ratio+       See [1] Nikulin 2011, Eq. (24)+       +   return_filtered : bool (default False)+        If return_filtered is True, data is bandpassed and projected onto +        the SSD components.+        +   n_fft: int (default None)+       if sort_by_spectral_ratio is set to True, then the sources will be sorted+       accordinly to their spectral ratio which is calculated based on +       "psd_array_welch" function. the n_fft set the length of FFT used.+       See mne.time_frequency.psd_array_welch for more information+    +   cov_method_params : TYPE, optional+        As in mne.decoding.SPoC +        The default is None.+   rank : None | dict | ‘info’ | ‘full’+        As in mne.decoding.SPoC +        This controls the rank computation that can be read from the+        measurement info or estimated from the data. +        See Notes of mne.compute_rank() for details.The default is None.+        The default is None.++    +    REFERENCES:+    [1] Nikulin, V. V., Nolte, G., & Curio, G. (2011). A novel method for +    reliable and fast extraction of neuronal EEG/MEG oscillations on the basis +    of spatio-spectral decomposition. NeuroImage, 55(4), 1528-1535.+    [2] Haufe, S., Dähne, S., & Nikulin, V. V. (2014). Dimensionality reduction+    for the analysis of brain oscillations. NeuroImage, 101, 583-597.+    +    +                 """ -    def __init__(self, filt_params_signal, filt_params_noise,-                 estimator='oas', n_components=None,-                 subtract_signal=True,-                 reject=None,-                 flat=None,-                 picks=None,-                 sort_by_spectral_ratio=True):+    def __init__(self, filt_params_signal, filt_params_noise, sampling_freq,+                 estimator='oas', n_components=None, picks=None,+                 sort_by_spectral_ratio=True, return_filtered=False, n_fft=None, cov_method_params=None, rank=None):+                 """Initialize instance"""          dicts = {"signal": filt_params_signal, "noise": filt_params_noise}         for param, dd in [('l', 0), ('h', 0), ('l', 1), ('h', 1)]:             key = ('signal', 'noise')[dd]             if  param + '_freq' not in dicts[key]:                 raise ValueError(-                    "'%' must be defined in filter parameters for %s" % key)+                    "'%%' must be defined in filter parameters for %s" % key)             val = dicts[key][param + '_freq']             if not isinstance(val, (int, float)):                 raise ValueError(                     "Frequencies must be numbers, got %s" % type(val))+       +          #check freq bands+        if (filt_params_noise['l_freq'] > filt_params_signal['l_freq'] or  +                filt_params_signal['h_freq']>filt_params_noise['h_freq']):+            raise ValueError('Wrongly specified frequency bands!\nThe signal band-pass must be within the t noise band-pass!')          self.freqs_signal = (filt_params_signal['l_freq'],                              filt_params_signal['h_freq'])         self.freqs_noise = (filt_params_noise['l_freq'],                             filt_params_noise['h_freq'])+        +        +                       self.filt_params_signal = filt_params_signal         self.filt_params_noise = filt_params_noise-        self.subtract_signal = subtract_signal-        self.picks = picks+        self.sort_by_spectral_ratio = sort_by_spectral_ratio+        if n_fft is None:+            self.n_fft= int(sampling_freq)+        else:+            self.n_fft=int(n_fft)+        self.picks_ = picks+        +        self.return_filtered=return_filtered+        +                self.estimator = estimator         self.n_components = n_components-+        self.rank = rank+        self.sampling_freq=sampling_freq      +        self.cov_method_params = cov_method_params+        +         def fit(self, inst):         """Fit"""-        if self.picks == None:-            self.picks_ = mne.pick_types(inst.info, meg=True, eeg=False, ref_meg=False)-        else:-            self.picks_ = self.picks-        if isinstance(inst, mne.io.base.BaseRaw):+        +        +        if isinstance(inst, BaseRaw):+            if self.picks_ is None:+                raise ValueError('picks should be provided')+            self.max_components=len(self.picks_)             inst_signal = inst.copy()             inst_signal.filter(picks=self.picks_, **self.filt_params_signal)-+            self.Xs=inst_signal+            #noise             inst_noise = inst.copy()             inst_noise.filter(picks=self.picks_, **self.filt_params_noise)-            if self.subtract_signal:-                inst_noise._data[self.picks_] -= inst_signal._data[self.picks_]-            cov_signal = mne.compute_raw_covariance(-                inst_signal, picks=self.picks_, method=self.estimator)-            cov_noise = mne.compute_raw_covariance(inst_noise, picks=self.picks_,-                method=self.estimator)+            # subtract signal:+            inst_noise._data[self.picks_] -= inst_signal._data[self.picks_]+           +            cov_signal = compute_raw_covariance(+                inst_signal, picks=self.picks_, method=self.estimator, rank=self.rank)+            cov_noise = compute_raw_covariance(inst_noise, picks=self.picks_,+                method=self.estimator, rank=self.rank)             del inst_noise             del inst_signal         else:-            raise NotImplementedError()+            if isinstance(inst, BaseEpochs)  or isinstance(inst, np.ndarray):+            # data X is epoched +            # part of the following code is copied from mne csp+                n_epochs, n_channels, n_samples = inst.shape+                self.max_components=n_channels+              +                #reshape for filtering+                X_aux=np.reshape(inst, [n_epochs, n_channels*n_samples])+                X_s=filter_data(X_aux, self.sampling_freq, **self.filt_params_signal)  +                +                #rephase for filtering+                X_aux=np.reshape(inst, [n_epochs, n_channels*n_samples])+                X_n=filter_data(X_aux, self.sampling_freq, **self.filt_params_noise)+                # subtract signal:+                X_n -= X_s+                +                # Estimate single trial covariance+                #reshape to original shape+                X_s=np.reshape(X_s, [n_epochs,n_channels,n_samples])

This is another situation where whitespaces are needed: equals operator and commas. I would recommend installing style-checker plugins for the editor of choice.

vpeterson

comment created time in 5 days

PullRequestReviewEvent
PullRequestReviewEvent

pull request commentmne-tools/mne-python

Add spectro-spatial decomposition SSD example

@vpeterson I rebased the pull request to allow us to continue working on this. Shall we give it another try to let you do a PR into this one? We can work through the necessary steps. It would be nice to give credit to your work through commits. I'd also have few discussion points regarding the code you have shared with me.

dengemann

comment created time in 6 days

push eventdengemann/mne-python

Jussi Nurminen

commit sha 50cc4f28f8ed0dfae8e78139ddabe93a80b6d1f9

millimeters -> meters (#7074)

view details

Robert Luke

commit sha f784fde5d4ee738eff603bdc3823cfc3ca12b5bd

Change way NIRS frequency is encoded (#7064)

view details

Robert Luke

commit sha 3091cac2e780a3baf1763fc888da22660e5554a2

MRG: Add support for NIRS to plot_topomap (#7063) * Add support for NIRS to plot_topomap * Add plot_topomap to NIRS tutorial * Add newline to tutorial * Do not modify nirs channel names * Update mne/viz/topomap.py Co-Authored-By: Eric Larson <larson.eric.d@gmail.com> * Add another example to nirs tutorial * Add fnirs_raw and fnirs_od to topomap * Change nirs channel naming. Instead of modifying clean_names * Fix new nirs name in beerlambert test * Add combine evoked to tutorial * Remove repeated code in nirs tutorial * Add back removed whitespace * Fix whitespace error * Extract only choma of choice in ch_type * Reuse evoked objects to save memory

view details

Eric Larson

commit sha 01d964670e502f497670e7653512dc05689a59d4

MAINT: Fix a few install issues (#7076) * MAINT: Fix a few install issues * FIX: Import * FIX: Modernize script install

view details

Alexandre Gramfort

commit sha 1e8c30d4969050a9313d720ba1feb41226a4e303

fix : don't require git to install master (#7078)

view details

Guillaume Favelier

commit sha ec6df570e59d05ab4c5d35d74f9c153ba1fc7af0

[MRG] Fix plot_vector_source_estimates (#7084) * Initial fix * Update mesh is not necessary * Choose to modify scale_factor as post-post-process * Add simple test for fix * Use mean of hemi's width

view details

Eric Larson

commit sha a62d596be99949f104360b4ba794105d35bf94c7

MRG, BUG: Fix running subprocesses in Jupyter notebooks (#7086) * BUG: Fix running subprocesses in Jupyter notebooks * FIX: Flake [ci skip]

view details

Adam Li

commit sha 6861595ea11e30db2a4cb1262d90518f1a01bfcf

FIX: Adding use_scalebars as a parameter. (#7091) * Adding use_scalebars as a parameter. * Fixed to adhere to mne-coding standards. * Fixing formatting issues. * Fixing show_scalebars in viz ica from the original naming of use_scalebars. * Update mne/viz/ica.py Co-Authored-By: Daniel McCloy <dan.mccloy@gmail.com> * Update mne/viz/raw.py Co-Authored-By: Daniel McCloy <dan.mccloy@gmail.com> * DOC: Correct version [ci skip]

view details

mathurinm

commit sha 8e0a423d9b62268e2dc8e03cbb1810a3cab34391

[MRG] Implement iterative reweighted TF-MxNE (#5075) * ir scheme * Squash commits * messed up my rebase * Address comments Alex * flake * implement filtering and write more readable math code * fix pydocstyle * High pass filter, remove upsampling, get 4 sources * TFMxnE > TF-MxNE + rm comment example

view details

Eric Larson

commit sha f7e7bd3d460a609f22cca7166ddef9dd5311acea

MAINT: Ensure that meas_date=None round-trips if `anonymize_info` is used (#7090) * BUG: Write out meas_date=None * FIX: Maybe better? * DOC: Document

view details

Marijn van Vliet

commit sha b12a220d2b6d5b5c89b05e5536be28bb21cfc361

[WIP] Make equalize_channels capable of operating on Forward, Covariance and CrossSpectralDensity (#7029) * Add more capabilites to equalize_channels * Add unit tests for improved equalize_channels functionality * Fix docstring of equalize_channels * Add Info capabilities to equalize_channels * Fix Forward.pick_channels docstring * Update combine_evokeds unit test * Fix edge case of pick_channels_cov * Add dedicated pick_channels_cov unit test * Add copy parameter to equalize_channels * Make copy=False the default * Make grand_average also equalize TFR channels * Make copy=True the default in equalize_channels * PEP8 * Update docstring * Update what's new * Update unit tests * Update links to methods in whats_new * Spell out new supported object types * Fix links in whats_new again * Remove attribute links

view details

Daniel McCloy

commit sha fbd75733e1d57f3fdbb65b01500de18d05185fc5

MRG, DOC: revise tutorial: overview of Epoching (#7011) * rename file * WIP tutorial overhaul [ci skip] * link targets * finish tutorial revisions * fix glossary ref * formatting/flow tweaks [skip travis] * fix codespell * address neurolaunch review comments

view details

Guillaume Favelier

commit sha 6ca8ec3786d864f53ab379f59e1f6668afd1ff5e

[MRG] Refactor mayavi/mlab out report (#7008) * Start refactoring of report * Fix figure_size bug * Fix undefined function bug * Remove unnecessary 3d functions from public API * Refactor _fig_to_img * Unify 3d backend testing * Fix 3d backend testing variable * Minor refactoring * Improve _check_3d_figure * TST: Trigger plot_make_report.py * TST: Trigger plot_make_report.py * Fix typo * Fix bug with figure not closed * TST: Trigger plot_make_report.py * Integrate reviews

view details

Daniel McCloy

commit sha c59c5d959bd13715dc0ae7801ef95e7bc846bb4b

crop raw to save memory (#7100)

view details

Daniel McCloy

commit sha 76f38bdd351627504618516be29cf03947096a85

MRG, DOC: Update contrib guide (#7097) * WIP update contributing guide * refine bug reporting guidelines * add git setup diagram * mention dangers of PYTHONPATH * fix typo * more on PYTHONPATH * clarify dev environment setup steps * tweaks * remove self-referential crossref * add "origin"

view details

Chun-Hui Li

commit sha 3459c84cc7cc76c37356dbf163c7768f03c81182

ENH: Adding support of GridSearchCV for mne.decoding.LinearModel (#7089) * ENH: Adding support of GridSearchCV for mne.decoding.LinearModel * (1) adds the GridSearchCV tests for LinearModel class. (2) adds Classification/Regression/GridSearchCV estimators' tests for get_coef function. * fixed some flake8 errors. * speeds up the tests. * tweaks some tests. * adds an entry to changelog. * (1) generates the random values under RandomState. (2) uses `with block` to catch exceptions.

view details

Luke Bloy

commit sha 538597485f8f69b343690cdc5911665b4b98c131

BUG: CTF - set meas_date (#7104) * BUG: CTF - set meas_date * Comment: not to revisit testing post potential mne-c updates * Whats New

view details

Daniel McCloy

commit sha 27e3f1d75f3c8605272d9071b5d5a2d77a7d1f22

MRG, DOC: revise tutorial: epochs visualization (#7102) * delete redundant tutorial * add explanation of dropped epoch & crossref to drop_log section * add crossref target * overhaul epochs viz tutorial * fix sidebar * avoid warning * update crossrefs * formatting & flow tweaks * rename file for proper ordering * fix crossrefs * make plots look better * fix codespell

view details

Guillaume Favelier

commit sha e51e2cd5c3244f6d9b6aae4da713d838089cfa63

[MRG] Improve Renderer API (#6761) * Fix minor bug in sphere() * Fix dimension in tube() * Update doc for color * Add color management as str * Find better default value for tube() radius * Correct colorConvertex syntax * Fix import nesting * Refactor colro code * Rework text2d() (x,y) parameter * Refactor _parse_str_color to _check_color * Add some tests * Improve doc * Add the radius parameter for pyvista * Fix import

view details

Eric Larson

commit sha 701312c2f66dbe6910d0845169d259afdfbd814a

FIX: Avoid deadlocking (#7103)

view details

push time in 6 days

pull request commentmne-tools/mne-python

Add spectro-spatial decomposition SSD example

Yes I will get to it this week.

On 9 Sep 2020, at 16:25, Eric Larson notifications@github.com wrote:

Have any time for this @dengemann ? If not let's push to 0.22

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub, or unsubscribe.

dengemann

comment created time in 11 days

startedStatisticalRethinkingJulia/TuringModels.jl

started time in 25 days

pull request commentmne-tools/mne-python

Add spectro-spatial decomposition SSD example

Thank you @vpeterson for your review, I shall get back to you during this week. I have marked this PR as a potential candidate for our next release, hoping that we can merge a first version within the next 3 weeks.

dengemann

comment created time in a month

issue commentmne-tools/mne-python

MAINT: Release 0.21

September 15 ? @larsoner

larsoner

comment created time in a month

push eventbanilo/inf_vs_pred_2020

dengemann

commit sha fba326f15173cc38890de07e949e84d82d67b3f0

add hexbin supp figures

view details

dengemann

commit sha 2e8461ae640149f4f8efaed3ffcc0ac30341eab2

Merge branch 'new_sims'

view details

push time in a month

push eventbanilo/inf_vs_pred_2020

dengemann

commit sha 8a22310bf3405edc5375f450369fc19a40b30cb7

add new simulation results and imrove PDF outputs

view details

dengemann

commit sha 803fe99574fa31f631aa584de1d4d1e721a2aef7

add bonferroni figures @banilo

view details

dengemann

commit sha a2feec44d725d900d0f0b0c66f68bb34447344f6

add concept figure elements @banilo

view details

Denis A. Engemann

commit sha 8e9459c8d1269ef69d8bc8065dfae36f577d158a

Merge pull request #1 from dengemann/new_sims ENH/VIZ: add new simulation results and improve PDF outputs

view details

push time in a month

PR merged banilo/inf_vs_pred_2020

ENH/VIZ: add new simulation results and improve PDF outputs

New results and improvements (comments, PDF sizes) to existing viz code.

+1056 -5

0 comment

12 changed files

dengemann

pr closed time in a month

push eventdengemann/inf_vs_pred_2020

dengemann

commit sha a2feec44d725d900d0f0b0c66f68bb34447344f6

add concept figure elements @banilo

view details

push time in a month

push eventdengemann/inf_vs_pred_2020

dengemann

commit sha 803fe99574fa31f631aa584de1d4d1e721a2aef7

add bonferroni figures @banilo

view details

push time in a month

Pull request review commentbanilo/inf_vs_pred_2020

ENH/VIZ: add new simulation results and improve PDF outputs

 def compute_lasso_regpath(X, y, C_grid, metric=None, verbose=True):         sample_accs_unbiased = []         sample_coef = []         for i_subsample in range(100):-            folder = ShuffleSplit(n=len(y), n_iter=100, test_size=0.1,+            folder = ShuffleSplit(n_splits=100, test_size=0.1,                                   random_state=i_subsample)-            train_inds, test_inds = next(iter(folder))+            train_inds, test_inds = next(folder.split(X, y))

Edit needed to make it run with recent sklearn API.

dengemann

comment created time in a month

PR opened banilo/inf_vs_pred_2020

ENH/VIZ: add new simulation results and improve PDF outputs

New results and improvements (comments, PDF sizes) to existing viz code.

+523 -4

0 comment

8 changed files

pr created time in a month

create barnchdengemann/inf_vs_pred_2020

branch : new_sims

created branch time in a month

push eventbanilo/inf_vs_pred_2020

Denis A. Engemann

commit sha 3eeba9b23123ab3bc90e9aa068bda0340ed767c5

Update README.md

view details

push time in a month

issue commentmne-tools/mne-r

Problem installing MNE-R under R version 4.0.2 on macOS Catalina

Thanks for reporting and solving :) I hope to spend a moment soon on maintenance work and overhauling some internals while in the processes adding more tests and documentation.

On 30 Jul 2020, at 08:41, Alexander Enge notifications@github.com wrote:

Closed #17.

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub, or unsubscribe.

alexenge

comment created time in 2 months

issue commentmne-tools/mne-python

to_data_frame() method for EpochsTFR objects

Sounds cool! Keep me in the loop. We can then add simultaneously a related vignette to mne-r: https://mne.tools/mne-r

On 7 Jul 2020, at 21:33, eioe notifications@github.com wrote:

Thanks! Yes, I worked through the guide and set up a local dev enviroment. I'll come back when I hit a wall.

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub, or unsubscribe.

eioe

comment created time in 2 months

startedJuliaStats/GLM.jl

started time in 3 months

startedJunoLab/Weave.jl

started time in 3 months

more