{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "\n\n# Decoding source space data\n\nDecoding to MEG data in source space on the left cortical surface. Here\nunivariate feature selection is employed for speed purposes to confine the\nclassification to a small number of potentially relevant features. The\nclassifier then is trained to selected features of epochs in source space.\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "# Author: Denis A. Engemann \n# Alexandre Gramfort \n# Jean-R\u00e9mi King \n# Eric Larson \n#\n# License: BSD-3-Clause\n# Copyright the MNE-Python contributors." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "import matplotlib.pyplot as plt\nimport numpy as np\nfrom sklearn.feature_selection import SelectKBest, f_classif\nfrom sklearn.linear_model import LogisticRegression\nfrom sklearn.pipeline import make_pipeline\nfrom sklearn.preprocessing import StandardScaler\n\nimport mne\nfrom mne.decoding import LinearModel, SlidingEstimator, cross_val_multiscore, get_coef\nfrom mne.minimum_norm import apply_inverse_epochs, read_inverse_operator\n\nprint(__doc__)\n\ndata_path = mne.datasets.sample.data_path()\nmeg_path = data_path / \"MEG\" / \"sample\"\nfname_fwd = meg_path / \"sample_audvis-meg-oct-6-fwd.fif\"\nfname_evoked = meg_path / \"sample_audvis-ave.fif\"\nsubjects_dir = data_path / \"subjects\"" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Set parameters\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "raw_fname = meg_path / \"sample_audvis_filt-0-40_raw.fif\"\nevent_fname = meg_path / \"sample_audvis_filt-0-40_raw-eve.fif\"\nfname_cov = meg_path / \"sample_audvis-cov.fif\"\nfname_inv = meg_path / \"sample_audvis-meg-oct-6-meg-inv.fif\"\n\ntmin, tmax = -0.2, 0.8\nevent_id = dict(aud_r=2, vis_r=4) # load contra-lateral conditions\n\n# Setup for reading the raw data\nraw = mne.io.read_raw_fif(raw_fname, preload=True)\nraw.filter(None, 10.0, fir_design=\"firwin\")\nevents = mne.read_events(event_fname)\n\n# Set up pick list: MEG - bad channels (modify to your needs)\nraw.info[\"bads\"] += [\"MEG 2443\"] # mark bads\npicks = mne.pick_types(\n raw.info, meg=True, eeg=False, stim=True, eog=True, exclude=\"bads\"\n)\n\n# Read epochs\nepochs = mne.Epochs(\n raw,\n events,\n event_id,\n tmin,\n tmax,\n proj=True,\n picks=picks,\n baseline=(None, 0),\n preload=True,\n reject=dict(grad=4000e-13, eog=150e-6),\n decim=5,\n) # decimate to save memory and increase speed" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Compute inverse solution\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "snr = 3.0\nnoise_cov = mne.read_cov(fname_cov)\ninverse_operator = read_inverse_operator(fname_inv)\n\nstcs = apply_inverse_epochs(\n epochs,\n inverse_operator,\n lambda2=1.0 / snr**2,\n verbose=False,\n method=\"dSPM\",\n pick_ori=\"normal\",\n)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Decoding in sensor space using a logistic regression\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "# Retrieve source space data into an array\nX = np.array([stc.lh_data for stc in stcs]) # only keep left hemisphere\ny = epochs.events[:, 2]\n\n# prepare a series of classifier applied at each time sample\nclf = make_pipeline(\n StandardScaler(), # z-score normalization\n SelectKBest(f_classif, k=500), # select features for speed\n LinearModel(LogisticRegression(C=1, solver=\"liblinear\")),\n)\ntime_decod = SlidingEstimator(clf, scoring=\"roc_auc\")\n\n# Run cross-validated decoding analyses:\nscores = cross_val_multiscore(time_decod, X, y, cv=5, n_jobs=None)\n\n# Plot average decoding scores of 5 splits\nfig, ax = plt.subplots(1)\nax.plot(epochs.times, scores.mean(0), label=\"score\")\nax.axhline(0.5, color=\"k\", linestyle=\"--\", label=\"chance\")\nax.axvline(0, color=\"k\")\nplt.legend()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "To investigate weights, we need to retrieve the patterns of a fitted model\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "# The fitting needs not be cross validated because the weights are based on\n# the training sets\ntime_decod.fit(X, y)\n\n# Retrieve patterns after inversing the z-score normalization step:\npatterns = get_coef(time_decod, \"patterns_\", inverse_transform=True)\n\nstc = stcs[0] # for convenience, lookup parameters from first stc\nvertices = [stc.lh_vertno, np.array([], int)] # empty array for right hemi\nstc_feat = mne.SourceEstimate(\n np.abs(patterns),\n vertices=vertices,\n tmin=stc.tmin,\n tstep=stc.tstep,\n subject=\"sample\",\n)\n\nbrain = stc_feat.plot(\n views=[\"lat\"],\n transparent=True,\n initial_time=0.1,\n time_unit=\"s\",\n subjects_dir=subjects_dir,\n)" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.12.2" } }, "nbformat": 4, "nbformat_minor": 0 }