Automated rejection and repair of bad trials/sensors in M/EEG
Materials for MNE tutorials at Practical MEEG workshop Paris 2019
dengemann/meeg-preprocessing 6
Preprocessing tools for MEG/EEG
MNE scripting with Python
agramfort/mne-python-notebooks 1
IPython notebooks for EEG/MEG data processing using mne-python
ggplot for python
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 <[email protected]>++ 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
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 <[email protected]>++ 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!')
comment created time in 2 days
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?
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.
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 <[email protected]>++ 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 ?
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 <[email protected]>++ 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
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 <[email protected]>++ 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.
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 <[email protected]>++ 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
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 <[email protected]>++ 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
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 <[email protected]>++ 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
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 <[email protected]>++ 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.
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 <[email protected]>++ 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
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 <[email protected]>++ 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
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 <[email protected]>++ 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 *
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 <[email protected]>++ 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.
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 <[email protected]>++ 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.
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 <[email protected]>++ 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.
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 <[email protected]>++ 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.
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 <[email protected]>
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.
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")
What is this? It looks computer specific and should not be there.
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 <[email protected]>-#+# Author: Denis A. Engemann <[email protected]>, &+# Victoria Peterson <[email protected]>
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.
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.
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 <[email protected]>-#+# Author: Denis A. Engemann <[email protected]>, &+# Victoria Peterson <[email protected]>
Very good. I was gonna suggest this.
comment created time in 2 days
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
comment created time in 4 days
push eventdengemann/mne-python
commit sha 8c0cd0fa6889567fac0815559eaf2b4c4ca264f6
some more footcite
commit sha cc1122da52119b7cc3a438738fe51e93666ea644
fix
push time in 4 days
push eventdengemann/mne-python
commit sha b3b36c5808426366aefe42c9a0321e54ef02fc9f
Update examples/inverse/plot_mne_cov_power.py Co-authored-by: Daniel McCloy <[email protected]>
push time in 4 days
push eventdengemann/mne-python
commit sha 00358d0bddf8e195024e285fd04ff28f3d92b72a
Update doc/references.bib Co-authored-by: Daniel McCloy <[email protected]>
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
comment created time in 4 days
push eventdengemann/mne-python
commit sha 19c070e558b4968c872850126574eae1d99a0f16
fix bib
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.
comment created time in 4 days
push eventdengemann/mne-python
commit sha 019a0ed6be0067c3409d1957d68708c923168544
footcite & improve wording
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 <[email protected]>+ + 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.
comment created time in 4 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)+#%%
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.
comment created time in 4 days
PR opened mne-tools/mne-python
This PR adds a reference for the recently introduced apply_inverse_covfunction.
cc @agramfort
pr created 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 <[email protected]>+ + 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
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 <[email protected]>+ + 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.
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.
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 <[email protected]>+ + 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
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 <[email protected]>+ + 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
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 <[email protected]>+ + 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.
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 <[email protected]>+ + 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
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 <[email protected]>+ + 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
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 <[email protected]>+ + 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
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 <[email protected]>+ + 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.
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 <[email protected]>+ + 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
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 <[email protected]>+ + 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.
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 <[email protected]>+ + 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.
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 <[email protected]>+ + 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.
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 <[email protected]>+ + 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.
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 <[email protected]>+ + 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.
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 <[email protected]>+ + 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.
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 <[email protected]>+ + 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 ...
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 <[email protected]>+ + 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.
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 <[email protected]>+ + 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.
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 <[email protected]>+ + 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.
comment created time in 5 days
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.
comment created time in 6 days
push eventdengemann/mne-python
commit sha 50cc4f28f8ed0dfae8e78139ddabe93a80b6d1f9
millimeters -> meters (#7074)
commit sha f784fde5d4ee738eff603bdc3823cfc3ca12b5bd
Change way NIRS frequency is encoded (#7064)
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 <[email protected]> * 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
commit sha 01d964670e502f497670e7653512dc05689a59d4
MAINT: Fix a few install issues (#7076) * MAINT: Fix a few install issues * FIX: Import * FIX: Modernize script install
commit sha 1e8c30d4969050a9313d720ba1feb41226a4e303
fix : don't require git to install master (#7078)
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
commit sha a62d596be99949f104360b4ba794105d35bf94c7
MRG, BUG: Fix running subprocesses in Jupyter notebooks (#7086) * BUG: Fix running subprocesses in Jupyter notebooks * FIX: Flake [ci skip]
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 <[email protected]> * Update mne/viz/raw.py Co-Authored-By: Daniel McCloy <[email protected]> * DOC: Correct version [ci skip]
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
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
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
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
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
commit sha c59c5d959bd13715dc0ae7801ef95e7bc846bb4b
crop raw to save memory (#7100)
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"
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.
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
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
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
commit sha 701312c2f66dbe6910d0845169d259afdfbd814a
FIX: Avoid deadlocking (#7103)
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 [email protected] 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.
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.
comment created time in a month
push eventbanilo/inf_vs_pred_2020
commit sha fba326f15173cc38890de07e949e84d82d67b3f0
add hexbin supp figures
commit sha 2e8461ae640149f4f8efaed3ffcc0ac30341eab2
Merge branch 'new_sims'
push time in a month
push eventbanilo/inf_vs_pred_2020
commit sha 8a22310bf3405edc5375f450369fc19a40b30cb7
add new simulation results and imrove PDF outputs
commit sha 803fe99574fa31f631aa584de1d4d1e721a2aef7
add bonferroni figures @banilo
commit sha a2feec44d725d900d0f0b0c66f68bb34447344f6
add concept figure elements @banilo
commit sha 8e9459c8d1269ef69d8bc8065dfae36f577d158a
Merge pull request #1 from dengemann/new_sims ENH/VIZ: add new simulation results and improve PDF outputs
push time in a month
PR merged banilo/inf_vs_pred_2020
New results and improvements (comments, PDF sizes) to existing viz code.
pr closed time in a month
push eventdengemann/inf_vs_pred_2020
commit sha a2feec44d725d900d0f0b0c66f68bb34447344f6
add concept figure elements @banilo
push time in a month
push eventdengemann/inf_vs_pred_2020
commit sha 803fe99574fa31f631aa584de1d4d1e721a2aef7
add bonferroni figures @banilo
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.
comment created time in a month
PR opened banilo/inf_vs_pred_2020
New results and improvements (comments, PDF sizes) to existing viz code.
pr created time in a month
push eventbanilo/inf_vs_pred_2020
commit sha 3eeba9b23123ab3bc90e9aa068bda0340ed767c5
Update README.md
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 [email protected] 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.
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 [email protected] 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.
comment created time in 2 months
startedJuliaStats/GLM.jl
started time in 3 months
startedJunoLab/Weave.jl
started time in 3 months