Tutorial 0: Getting Started#

This tutorial takes you through a basic working example of how to use this codebase, including all the different components, up to the results generation. If you’d like to know about the statistics and plotting, see the next tutorial.

# Authors: Vinay Jayaram <vinayjayaram13@gmail.com>
#
# License: BSD (3-clause)

Introduction#

To use the codebase you need an evaluation and a paradigm, some algorithms, and a list of datasets to run it all on. You can find those in the following submodules; detailed tutorials are given for each of them.

import numpy as np
from sklearn.discriminant_analysis import LinearDiscriminantAnalysis as LDA
from sklearn.metrics import accuracy_score, roc_auc_score
from sklearn.model_selection import GridSearchCV
from sklearn.pipeline import make_pipeline
from sklearn.svm import SVC

If you would like to specify the logging level when it is running, you can use the standard python logging commands through the top-level moabb module

import moabb
from moabb.datasets import BNCI2014_001, utils
from moabb.evaluations import CrossSessionEvaluation
from moabb.paradigms import LeftRightImagery
from moabb.pipelines.features import LogVariance

In order to create pipelines within a script, you will likely need at least the make_pipeline function. They can also be specified via a .yml file. Here we will make a couple pipelines just for convenience

Create pipelines#

We create two pipelines: channel-wise log variance followed by LDA, and channel-wise log variance followed by a cross-validated SVM (note that a cross-validation via scikit-learn cannot be described in a .yml file). For later in the process, the pipelines need to be in a dictionary where the key is the name of the pipeline and the value is the Pipeline object

pipelines = {}
pipelines["AM+LDA"] = make_pipeline(LogVariance(), LDA())
parameters = {"C": np.logspace(-2, 2, 10)}
clf = GridSearchCV(SVC(kernel="linear"), parameters)
pipe = make_pipeline(LogVariance(), clf)

pipelines["AM+SVM"] = pipe

Datasets#

Datasets can be specified in many ways: Each paradigm has a property ‘datasets’ which returns the datasets that are appropriate for that paradigm

[<moabb.datasets.bnci.bnci_2014.BNCI2014_001 object at 0x7f65d10c2440>, <moabb.datasets.bnci.bnci_2014.BNCI2014_004 object at 0x7f65d10c21a0>, <moabb.datasets.beetl.Beetl2021_A object at 0x7f65d10c2350>, <moabb.datasets.beetl.Beetl2021_B object at 0x7f65d10c2170>, <moabb.datasets.brandl2020.Brandl2020 object at 0x7f65d10c2260>, <moabb.datasets.chang2025.Chang2025 object at 0x7f65d10c22c0>, <moabb.datasets.gigadb.Cho2017 object at 0x7f65d10c2200>, <moabb.datasets.dreyer2023.Dreyer2023 object at 0x7f65d10c23b0>, <moabb.datasets.dreyer2023.Dreyer2023A object at 0x7f65d10c2320>, <moabb.datasets.dreyer2023.Dreyer2023B object at 0x7f65d10c0b80>, <moabb.datasets.dreyer2023.Dreyer2023C object at 0x7f65d10c1750>, <moabb.datasets.forenzo2023.Forenzo2023 object at 0x7f65d10c1e70>, <moabb.datasets.mpi_mi.GrosseWentrup2009 object at 0x7f65d10c1690>, <moabb.datasets.guttmann_flury2025.GuttmannFlury2025_ME object at 0x7f65d10c1e40>, <moabb.datasets.guttmann_flury2025.GuttmannFlury2025_MI object at 0x7f65d10c1810>, <moabb.datasets.hefmi_ich2025.HefmiIch2025 object at 0x7f65d10c17e0>, <moabb.datasets.kaya2018.Kaya2018 object at 0x7f65d10c1cc0>, <moabb.datasets.kumar2024.Kumar2024 object at 0x7f65d10c2050>, <moabb.datasets.Lee2019.Lee2019_MI object at 0x7f65d10c2230>, <moabb.datasets.liu2024.Liu2024 object at 0x7f65d10c1f30>, <moabb.datasets.physionet_mi.PhysionetMI object at 0x7f65d45baa40>, <moabb.datasets.schirrmeister2017.Schirrmeister2017 object at 0x7f65d10c1d50>, <moabb.datasets.bbci_eeg_fnirs.Shin2017A object at 0x7f65d18ceaa0>, <moabb.datasets.stieger2021.Stieger2021 object at 0x7f65d10c2380>, <moabb.datasets.wairagkar2018.Wairagkar2018 object at 0x7f65d10c2140>, <moabb.datasets.Weibo2014.Weibo2014 object at 0x7f65d10c1b10>, <moabb.datasets.wu2020.Wu2020 object at 0x7f65d10c1ba0>, <moabb.datasets.yang2025.Yang2025 object at 0x7f65d10c20b0>, <moabb.datasets.Zhou2016.Zhou2016 object at 0x7f65d10c1840>, <moabb.datasets.zhou2020.Zhou2020 object at 0x7f65d10c1db0>]

Or you can run a search through the available datasets:

print(utils.dataset_search(paradigm="imagery", min_subjects=6))
[<moabb.datasets.alex_mi.AlexMI object at 0x7f65d10c17e0>, <moabb.datasets.bnci.bnci_2014.BNCI2014_001 object at 0x7f65d10c1690>, <moabb.datasets.bnci.bnci_2014.BNCI2014_002 object at 0x7f65d10c1e40>, <moabb.datasets.bnci.bnci_2014.BNCI2014_004 object at 0x7f65d10c1750>, <moabb.datasets.bnci.bnci_2015.BNCI2015_001 object at 0x7f65d10c1810>, <moabb.datasets.bnci.bnci_2015.BNCI2015_004 object at 0x7f65d10c1e70>, <moabb.datasets.bnci.bnci_2019.BNCI2019_001 object at 0x7f65d10c1f00>, <moabb.datasets.bnci.bnci_2020.BNCI2020_001 object at 0x7f65d10c0b80>, <moabb.datasets.bnci.bnci_2022_001.BNCI2022_001 object at 0x7f65d10c22f0>, <moabb.datasets.bnci.bnci_2024_001.BNCI2024_001 object at 0x7f65d10c2260>, <moabb.datasets.bnci.bnci_2025.BNCI2025_001 object at 0x7f65d10c22c0>, <moabb.datasets.bnci.bnci_2025.BNCI2025_002 object at 0x7f65d10c2320>, <moabb.datasets.brandl2020.Brandl2020 object at 0x7f65d10c2200>, <moabb.datasets.chang2025.Chang2025 object at 0x7f65d10c2440>, <moabb.datasets.gigadb.Cho2017 object at 0x7f65d10c23b0>, <moabb.datasets.dreyer2023.Dreyer2023 object at 0x7f65d10c2230>, <moabb.datasets.dreyer2023.Dreyer2023A object at 0x7f65d10c21a0>, <moabb.datasets.dreyer2023.Dreyer2023B object at 0x7f65d10c1f30>, <moabb.datasets.dreyer2023.Dreyer2023C object at 0x7f65d10c2380>, <moabb.datasets.fake.FakeDataset object at 0x7f65d10c1b10>, <moabb.datasets.forenzo2023.Forenzo2023 object at 0x7f65d10c2140>, <moabb.datasets.gao2026.Gao2026 object at 0x7f65d10c1d50>, <moabb.datasets.mpi_mi.GrosseWentrup2009 object at 0x7f65d10c1ba0>, <moabb.datasets.guttmann_flury2025.GuttmannFlury2025_ME object at 0x7f65d10c20b0>, <moabb.datasets.guttmann_flury2025.GuttmannFlury2025_MI object at 0x7f65d10c1db0>, <moabb.datasets.hefmi_ich2025.HefmiIch2025 object at 0x7f65d10c1960>, <moabb.datasets.jeong2020.Jeong2020 object at 0x7f65d10c1840>, <moabb.datasets.kaya2018.Kaya2018 object at 0x7f65d10c1e10>, <moabb.datasets.kumar2024.Kumar2024 object at 0x7f65d10c1c00>, <moabb.datasets.Lee2019.Lee2019_MI object at 0x7f65d10c24a0>, <moabb.datasets.liu2024.Liu2024 object at 0x7f65d10c2410>, <moabb.datasets.liu2025.Liu2025 object at 0x7f65d10c2290>, <moabb.datasets.ma2020.Ma2020 object at 0x7f65d10c2110>, <moabb.datasets.upper_limb.Ofner2017 object at 0x7f65d10c20e0>, <moabb.datasets.physionet_mi.PhysionetMI object at 0x7f65d10c23e0>, <moabb.datasets.rozado2015.Rozado2015 object at 0x7f65d10c1ed0>, <moabb.datasets.schirrmeister2017.Schirrmeister2017 object at 0x7f65d10c18d0>, <moabb.datasets.bbci_eeg_fnirs.Shin2017A object at 0x7f65d10c1720>, <moabb.datasets.bbci_eeg_fnirs.Shin2017B object at 0x7f65d10c19c0>, <moabb.datasets.stieger2021.Stieger2021 object at 0x7f65d10c1990>, <moabb.datasets.tavakolan2017.Tavakolan2017 object at 0x7f65d10c1a80>, <moabb.datasets.triana_guzman2024.TrianaGuzman2024 object at 0x7f65d10c24d0>, <moabb.datasets.wairagkar2018.Wairagkar2018 object at 0x7f65d10c1ae0>, <moabb.datasets.Weibo2014.Weibo2014 object at 0x7f65d10c2080>, <moabb.datasets.wu2020.Wu2020 object at 0x7f65d10c1b40>, <moabb.datasets.yang2025.Yang2025 object at 0x7f65d10c1ab0>, <moabb.datasets.yi2025.Yi2025 object at 0x7f65d10c1c60>, <moabb.datasets.zhang2017.Zhang2017 object at 0x7f65d10c1a50>, <moabb.datasets.zhou2020.Zhou2020 object at 0x7f65d10c1bd0>, <moabb.datasets.zuo2025.Zuo2025 object at 0x7f65d10c1b70>]

Or you can simply make your own list (which we do here due to computational constraints)

Paradigm#

Paradigms define the events, epoch time, bandpass, and other preprocessing parameters. They have defaults that you can read in the documentation, or you can simply set them as we do here. A single paradigm defines a method for going from continuous data to trial data of a fixed size. To learn more look at the tutorial Exploring Paradigms

fmin = 8
fmax = 35
# You can inject custom scoring directly into the paradigm (single or multi-metric).
custom_scorer = [accuracy_score, (roc_auc_score, {"needs_threshold": True})]
paradigm = LeftRightImagery(fmin=fmin, fmax=fmax, scorer=custom_scorer)

Evaluation#

An evaluation defines how the training and test sets are chosen. This could be cross-validated within a single recording, or across days, or sessions, or subjects. This also is the correct place to specify multiple threads.

[codecarbon WARNING @ 15:08:15] Multiple instances of codecarbon are allowed to run at the same time.
2026-04-10 15:08:42,234 INFO MainThread moabb.evaluations.base AM+LDA | BNCI2014-001 | 1 | 0train: Score 0.729
2026-04-10 15:08:42,234 INFO MainThread moabb.evaluations.base AM+SVM | BNCI2014-001 | 1 | 0train: Score 0.743
2026-04-10 15:08:42,234 INFO MainThread moabb.evaluations.base AM+LDA | BNCI2014-001 | 1 | 1test: Score 0.715
2026-04-10 15:08:42,234 INFO MainThread moabb.evaluations.base AM+SVM | BNCI2014-001 | 1 | 1test: Score 0.715
2026-04-10 15:08:42,234 INFO MainThread moabb.evaluations.base AM+LDA | BNCI2014-001 | 2 | 0train: Score 0.597
2026-04-10 15:08:42,234 INFO MainThread moabb.evaluations.base AM+SVM | BNCI2014-001 | 2 | 0train: Score 0.500
2026-04-10 15:08:42,234 INFO MainThread moabb.evaluations.base AM+LDA | BNCI2014-001 | 2 | 1test: Score 0.521
2026-04-10 15:08:42,234 INFO MainThread moabb.evaluations.base AM+SVM | BNCI2014-001 | 2 | 1test: Score 0.500
/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(

Results are returned as a pandas DataFrame. When multiple metrics are provided, MOABB adds a primary score plus one column per metric (e.g., score_accuracy_score, score_roc_auc_score).

print(results.head())
      score      time  ...  pipeline                  codecarbon_task_name
0  0.743056  0.143632  ...    AM+SVM  e5d96c08-28a4-4346-bc66-5d680f0b92a5
1  0.715278  0.133760  ...    AM+SVM  e648480c-d4fa-4d9e-ab53-078161fb83c4
2  0.500000  0.248059  ...    AM+SVM  362ff0e3-ce92-4726-9ede-52c2ef88f7a1
3  0.500000  0.163305  ...    AM+SVM  08a920e8-0deb-41c4-a9e2-6c99c20c0881
4  0.729167  0.015114  ...    AM+LDA  3751e6aa-af9f-4517-a8cc-1f102683fec3

[5 rows x 15 columns]

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

Gallery generated by Sphinx-Gallery