Cross-Session on Multiple Datasets#

This example shows how to perform a cross-session analysis on two MI datasets using a CSP+LDA pipeline

The cross session evaluation context will evaluate performance using a leave one session out cross-validation. For each session in the dataset, a model is trained on every other session and performance are evaluated on the current session.

# Authors: Sylvain Chevallier <sylvain.chevallier@uvsq.fr>
#
# License: BSD (3-clause)

import warnings

import matplotlib.pyplot as plt
import seaborn as sns
from mne.decoding import CSP
from sklearn.discriminant_analysis import LinearDiscriminantAnalysis as LDA
from sklearn.pipeline import make_pipeline

import moabb
from moabb.datasets import BNCI2014_001, Zhou2016
from moabb.evaluations import CrossSessionEvaluation
from moabb.paradigms import LeftRightImagery


warnings.simplefilter(action="ignore", category=FutureWarning)
warnings.simplefilter(action="ignore", category=RuntimeWarning)
moabb.set_log_level("info")
/home/runner/work/moabb/moabb/.venv/lib/python3.10/site-packages/optuna/integration/sklearn.py:14: FutureWarning: `optuna.integration.sklearn` has been deprecated in v4.9.0. This feature will be removed in v6.0.0. See https://github.com/optuna/optuna/releases/tag/v4.9.0. Use `optuna_integration.sklearn` instead.
  optuna_warn(f"{msg} Use `optuna_integration.sklearn` instead.", FutureWarning)

Loading Dataset#

Load 2 subjects of BNCI 2014-004 and Zhou2016 datasets, with 2 session each

subjects_list = [1, 2]

datasets = [Zhou2016(), BNCI2014_001()]

for d in datasets:
    # replace the subject list
    d.subject_list = subjects_list

Choose Paradigm#

We select the paradigm MI, applying a bandpass filter (8-35 Hz) on the data and we will keep only left- and right-hand motor imagery

paradigm = LeftRightImagery(fmin=8, fmax=35)

Create Pipelines#

Use the Common Spatial Patterns with 8 components and a Linear Discriminant Analysis classifier.

pipeline = {}
pipeline["CSP+LDA"] = make_pipeline(CSP(n_components=8), LDA())

Get Data (optional)#

To get access to the EEG signals downloaded from the dataset, you could use dataset.get_data(subjects=[subject_id]) to obtain the EEG under an MNE format, stored in a dictionary of sessions and runs. Otherwise, paradigm.get_data(dataset=dataset, subjects=[subject_id]) allows to obtain the EEG data in sklearn format, the labels and the meta information. The data are preprocessed according to the paradigm requirements.

# X_all, labels_all, meta_all = [], [], []
# for d in datasets:
#     # sessions = d.get_data(subjects=[2])
#     X, labels, meta = paradigm.get_data(dataset=d, subjects=[2])
#     X_all.append(X)
#     labels_all.append(labels)
#     meta_all.append(meta)

Evaluation#

The evaluation will return a DataFrame containing a single AUC score for each subject / session of the dataset, and for each pipeline.

overwrite = True  # set to True if we want to overwrite cached results

evaluation = CrossSessionEvaluation(
    paradigm=paradigm, datasets=datasets, suffix="examples", overwrite=overwrite
)
results = evaluation.process(pipeline)

print(results.head())
[codecarbon WARNING @ 12:02:14] Multiple instances of codecarbon are allowed to run at the same time.
2026-06-29 12:02:35,479 INFO MainThread moabb.evaluations.base CSP+LDA | Zhou2016 | 1 | 0: Score 0.851
2026-06-29 12:02:35,479 INFO MainThread moabb.evaluations.base CSP+LDA | Zhou2016 | 1 | 1: Score 0.936
2026-06-29 12:02:35,479 INFO MainThread moabb.evaluations.base CSP+LDA | Zhou2016 | 1 | 2: Score 0.940
2026-06-29 12:02:35,479 INFO MainThread moabb.evaluations.base CSP+LDA | Zhou2016 | 2 | 0: Score 0.908
2026-06-29 12:02:35,479 INFO MainThread moabb.evaluations.base CSP+LDA | Zhou2016 | 2 | 1: Score 0.770
2026-06-29 12:02:35,479 INFO MainThread moabb.evaluations.base CSP+LDA | Zhou2016 | 2 | 2: Score 0.936
/home/runner/work/moabb/moabb/moabb/analysis/results.py:189: H5pyDeprecationWarning: Creating a dataset without passing data or dtype is deprecated. Pass an explicit dtype. Using dtype='f4' will keep the current default behaviour.
  dset.create_dataset(
2026-06-29 12:02:52,892 INFO MainThread moabb.evaluations.base CSP+LDA | BNCI2014-001 | 1 | 0train: Score 0.931
2026-06-29 12:02:52,892 INFO MainThread moabb.evaluations.base CSP+LDA | BNCI2014-001 | 1 | 1test: Score 0.957
2026-06-29 12:02:52,892 INFO MainThread moabb.evaluations.base CSP+LDA | BNCI2014-001 | 2 | 0train: Score 0.527
2026-06-29 12:02:52,892 INFO MainThread moabb.evaluations.base CSP+LDA | BNCI2014-001 | 2 | 1test: Score 0.650
/home/runner/work/moabb/moabb/moabb/analysis/results.py:189: H5pyDeprecationWarning: Creating a dataset without passing data or dtype is deprecated. Pass an explicit dtype. Using dtype='f4' will keep the current default behaviour.
  dset.create_dataset(
     score      time  ...  pipeline                  codecarbon_task_name
0  0.85113  0.163924  ...   CSP+LDA  75c9a397-ff49-46c4-9b45-f1e89cabd1e3
1  0.93640  0.195938  ...   CSP+LDA  9da85a7a-5588-4c31-8dff-c09a749c200f
2  0.93960  0.188563  ...   CSP+LDA  c088f34a-7710-4f9e-9a12-392e21d7e37e
3  0.90800  0.179689  ...   CSP+LDA  46e7a239-2a7f-43a3-92c0-c8dced703d1a
4  0.77037  0.171664  ...   CSP+LDA  2b8ec1fe-c7e4-4494-9762-f0a4f933fa3e

[5 rows x 13 columns]

Plot Results#

Here we plot the results, indicating the score for each session and subject

sns.catplot(
    data=results,
    x="session",
    y="score",
    hue="subject",
    col="dataset",
    kind="bar",
    palette="viridis",
)
plt.show()
dataset = Zhou2016, dataset = BNCI2014-001

Total running time of the script: (0 minutes 44.066 seconds)

Gallery generated by Sphinx-Gallery