<jupyter_start><jupyter_text>==============================================Compute effect-matched-spatial filtering (EMS)==============================================This example computes the EMS to reconstruct the time course of theexperimental effect as described in [1]_.This technique is used to create spatial filters based on the differencebetween two conditions. By projecting the trial onto the corresponding spatialfilters, surrogate single trials are created in which multi-sensor activity isreduced to one time series which exposes experimental effects, if present.We will first plot a trials x times image of the single trials and order thetrials by condition. A second plot shows the average time series for eachcondition. Finally a topographic plot is created which exhibits the temporalevolution of the spatial filters.References----------.. [1] <NAME>, <NAME>, and <NAME>, "Reducing       multi-sensor data to a single time course that reveals experimental       effects", BMC Neuroscience 2013, 14:122.<jupyter_code># Author: <NAME> <<EMAIL>>
#         <NAME> <<EMAIL>>
#
# License: BSD (3-clause)

import numpy as np
import matplotlib.pyplot as plt

import mne
from mne import io, EvokedArray
from mne.datasets import sample
from mne.decoding import EMS, compute_ems
from sklearn.model_selection import StratifiedKFold

print(__doc__)

data_path = sample.data_path()

# Preprocess the data
raw_fname = data_path + '/MEG/sample/sample_audvis_filt-0-40_raw.fif'
event_fname = data_path + '/MEG/sample/sample_audvis_filt-0-40_raw-eve.fif'
event_ids = {'AudL': 1, 'VisL': 3}

# Read data and create epochs
raw = io.read_raw_fif(raw_fname, preload=True)
raw.filter(0.5, 45, fir_design='firwin')
events = mne.read_events(event_fname)

picks = mne.pick_types(raw.info, meg='grad', eeg=False, stim=False, eog=True,
                       exclude='bads')

epochs = mne.Epochs(raw, events, event_ids, tmin=-0.2, tmax=0.5, picks=picks,
                    baseline=None, reject=dict(grad=4000e-13, eog=150e-6),
                    preload=True)
epochs.drop_bad()
epochs.pick_types(meg='grad')

# Setup the data to use it a scikit-learn way:
X = epochs.get_data()  # The MEG data
y = epochs.events[:, 2]  # The conditions indices
n_epochs, n_channels, n_times = X.shape
# Initialize EMS transformer
ems = EMS()

# Initialize the variables of interest
X_transform = np.zeros((n_epochs, n_times))  # Data after EMS transformation
filters = list()  # Spatial filters at each time point

# In the original paper, the cross-validation is a leave-one-out. However,
# we recommend using a Stratified KFold, because leave-one-out tends
# to overfit and cannot be used to estimate the variance of the
# prediction within a given fold.

for train, test in StratifiedKFold().split(X, y):
    # In the original paper, the z-scoring is applied outside the CV.
    # However, we recommend to apply this preprocessing inside the CV.
    # Note that such scaling should be done separately for each channels if the
    # data contains multiple channel types.
    X_scaled = X / np.std(X[train])

    # Fit and store the spatial filters
    ems.fit(X_scaled[train], y[train])

    # Store filters for future plotting
    filters.append(ems.filters_)

    # Generate the transformed data
    X_transform[test] = ems.transform(X_scaled[test])

# Average the spatial filters across folds
filters = np.mean(filters, axis=0)

# Plot individual trials
plt.figure()
plt.title('single trial surrogates')
plt.imshow(X_transform[y.argsort()], origin='lower', aspect='auto',
           extent=[epochs.times[0], epochs.times[-1], 1, len(X_transform)],
           cmap='RdBu_r')
plt.xlabel('Time (ms)')
plt.ylabel('Trials (reordered by condition)')

# Plot average response
plt.figure()
plt.title('Average EMS signal')
mappings = [(key, value) for key, value in event_ids.items()]
for key, value in mappings:
    ems_ave = X_transform[y == value]
    plt.plot(epochs.times, ems_ave.mean(0), label=key)
plt.xlabel('Time (ms)')
plt.ylabel('a.u.')
plt.legend(loc='best')
plt.show()

# Visualize spatial filters across time
evoked = EvokedArray(filters, epochs.info, tmin=epochs.tmin)
evoked.plot_topomap(time_unit='s')<jupyter_output><empty_output><jupyter_text>Note that a similar transformation can be applied with `compute_ems`However, this function replicates Schurger et al's original paper, and thusapplies the normalization outside a leave-one-out cross-validation, which werecommend not to do.<jupyter_code>epochs.equalize_event_counts(event_ids)
X_transform, filters, classes = compute_ems(epochs)<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.1197656758515947, 'fraction_numerical': 0.00954653937947494, 'mean_word_length': 4.705445544554456, 'pattern_counts': {'":': 0, '<': 18, '<?xml version=': 0, '>': 18, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '2', 'dir': 'jupyter-structured-clean-dedup', 'id': '113320', 'license': 'BSD-3-Clause', 'n_tokens_mistral': 1472, 'n_tokens_neox': 1396, 'n_words': 468, 'path': '0.16/_downloads/plot_ems_filtering.ipynb', 'repo_name': 'drammock/mne-tools.github.io', 'size': '4686'}