Note
Go to the end to download the full example code.
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.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
moabb.set_log_level("info")
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
print(LeftRightImagery().datasets)
/home/runner/work/moabb/moabb/moabb/datasets/fake.py:93: RuntimeWarning: Setting non-standard config type: "MNE_DATASETS_FAKEDATASET-IMAGERY-10-2--60-60--120-120--FAKE1-FAKE2-FAKE3--C3-CZ-C4_PATH"
set_config(key, temp_dir)
/home/runner/work/moabb/moabb/moabb/datasets/fake.py:93: RuntimeWarning: Setting non-standard config type: "MNE_DATASETS_FAKEVIRTUALREALITYDATASET-P300-21-1--60-60-60-60-60-60-60-60-60-60-60-60-60-60-60-60-60-60-60-60-60-60-60-60-60-60-60-60-60-60-60-60-60-60-60-60-60-60-60-60-60-60-60-60-60-60-60-60-60-60-60-60-60-60-60-60-60-60-60-60--120-120-120-120-120-120-120-120-120-120-120-120-120-120-120-120-120-120-120-120-120-120-120-120-120-120-120-120-120-120-120-120-120-120-120-120-120-120-120-120-120-120-120-120-120-120-120-120-120-120-120-120-120-120-120-120-120-120-120-120--TARGET-NONTARGET--C3-CZ-C4_PATH"
set_config(key, temp_dir)
[<moabb.datasets.bnci.BNCI2014_001 object at 0x7fb2dfff98d0>, <moabb.datasets.bnci.BNCI2014_004 object at 0x7fb2dfffb0a0>, <moabb.datasets.beetl.Beetl2021_A object at 0x7fb2dfffa590>, <moabb.datasets.beetl.Beetl2021_B object at 0x7fb2e47d2bf0>, <moabb.datasets.gigadb.Cho2017 object at 0x7fb2e4518bb0>, <moabb.datasets.dreyer2023.Dreyer2023 object at 0x7fb2e451ae90>, <moabb.datasets.dreyer2023.Dreyer2023A object at 0x7fb2e4518c40>, <moabb.datasets.dreyer2023.Dreyer2023B object at 0x7fb2e451b460>, <moabb.datasets.dreyer2023.Dreyer2023C object at 0x7fb2e451b3d0>, <moabb.datasets.mpi_mi.GrosseWentrup2009 object at 0x7fb2e451b400>, <moabb.datasets.Lee2019.Lee2019_MI object at 0x7fb2dfff98a0>, <moabb.datasets.liu2024.Liu2024 object at 0x7fb2e44c9fc0>, <moabb.datasets.physionet_mi.PhysionetMI object at 0x7fb2e44cb340>, <moabb.datasets.schirrmeister2017.Schirrmeister2017 object at 0x7fb2e44c8580>, <moabb.datasets.bbci_eeg_fnirs.Shin2017A object at 0x7fb2e44cb700>, <moabb.datasets.stieger2021.Stieger2021 object at 0x7fb2e44cb070>, <moabb.datasets.Weibo2014.Weibo2014 object at 0x7fb2e44c82e0>, <moabb.datasets.Zhou2016.Zhou2016 object at 0x7fb2e44ca9b0>]
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 0x7fb2dfff9de0>, <moabb.datasets.bnci.BNCI2014_001 object at 0x7fb2dfffa5c0>, <moabb.datasets.bnci.BNCI2014_002 object at 0x7fb2dfffbeb0>, <moabb.datasets.bnci.BNCI2014_004 object at 0x7fb2dfffa950>, <moabb.datasets.bnci.BNCI2015_001 object at 0x7fb2dfff9990>, <moabb.datasets.bnci.BNCI2015_004 object at 0x7fb2dfff9630>, <moabb.datasets.gigadb.Cho2017 object at 0x7fb2dfffa590>, <moabb.datasets.dreyer2023.Dreyer2023 object at 0x7fb2e44c8580>, <moabb.datasets.dreyer2023.Dreyer2023A object at 0x7fb2dfffa500>, <moabb.datasets.dreyer2023.Dreyer2023B object at 0x7fb2e44c9750>, <moabb.datasets.dreyer2023.Dreyer2023C object at 0x7fb2e44cb160>, <moabb.datasets.fake.FakeDataset object at 0x7fb2e44ca9b0>, <moabb.datasets.mpi_mi.GrosseWentrup2009 object at 0x7fb2e44c82e0>, <moabb.datasets.Lee2019.Lee2019_MI object at 0x7fb2e44cb340>, <moabb.datasets.liu2024.Liu2024 object at 0x7fb2e44c9fc0>, <moabb.datasets.upper_limb.Ofner2017 object at 0x7fb2e44cb070>, <moabb.datasets.physionet_mi.PhysionetMI object at 0x7fb2df95ed70>, <moabb.datasets.schirrmeister2017.Schirrmeister2017 object at 0x7fb2df95e860>, <moabb.datasets.bbci_eeg_fnirs.Shin2017A object at 0x7fb2df95e080>, <moabb.datasets.bbci_eeg_fnirs.Shin2017B object at 0x7fb2df95e800>, <moabb.datasets.stieger2021.Stieger2021 object at 0x7fb2df95cd30>, <moabb.datasets.Weibo2014.Weibo2014 object at 0x7fb2df95d930>]
Or you can simply make your own list (which we do here due to computational constraints)
dataset = BNCI2014_001()
dataset.subject_list = dataset.subject_list[:2]
datasets = [dataset]
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
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.
evaluation = CrossSessionEvaluation(
paradigm=paradigm, datasets=datasets, suffix="examples", overwrite=False
)
results = evaluation.process(pipelines)
/home/runner/work/moabb/moabb/moabb/analysis/results.py:95: RuntimeWarning: Setting non-standard config type: "MOABB_RESULTS"
set_config("MOABB_RESULTS", osp.join(osp.expanduser("~"), "mne_data"))
BNCI2014-001-CrossSession: 0%| | 0/2 [00:00<?, ?it/s]2025-08-22 17:51:20,023 INFO MainThread moabb.datasets.download MNE_DATA is not already configured. It will be set to default location in the home directory - /home/runner/mne_data
All datasets will be downloaded to this location, if anything is already downloaded, please move manually to this location
/home/runner/work/moabb/moabb/moabb/datasets/download.py:60: RuntimeWarning: Setting non-standard config type: "MNE_DATASETS_BNCI_PATH"
set_config(key, get_config("MNE_DATA"))
/home/runner/work/moabb/moabb/.venv/lib/python3.10/site-packages/urllib3/connectionpool.py:1064: InsecureRequestWarning: Unverified HTTPS request is being made to host 'lampx.tugraz.at'. Adding certificate verification is strongly advised. See: https://urllib3.readthedocs.io/en/1.26.x/advanced-usage.html#ssl-warnings
warnings.warn(
0%| | 0.00/42.8M [00:00<?, ?B/s]
0%| | 8.19k/42.8M [00:00<10:11, 70.0kB/s]
0%| | 56.3k/42.8M [00:00<02:40, 266kB/s]
0%| | 88.1k/42.8M [00:00<02:42, 264kB/s]
0%|▏ | 209k/42.8M [00:00<01:16, 556kB/s]
1%|▍ | 465k/42.8M [00:00<00:37, 1.12MB/s]
2%|▊ | 969k/42.8M [00:00<00:19, 2.16MB/s]
5%|█▋ | 1.98M/42.8M [00:00<00:09, 4.22MB/s]
9%|███▍ | 4.01M/42.8M [00:00<00:04, 8.22MB/s]
14%|█████▎ | 6.11M/42.8M [00:01<00:03, 11.1MB/s]
19%|███████ | 8.20M/42.8M [00:01<00:02, 13.0MB/s]
24%|████████▉ | 10.3M/42.8M [00:01<00:02, 14.5MB/s]
29%|██████████▋ | 12.4M/42.8M [00:01<00:01, 15.4MB/s]
34%|████████████▌ | 14.6M/42.8M [00:01<00:01, 16.1MB/s]
41%|███████████████ | 17.4M/42.8M [00:01<00:01, 18.3MB/s]
46%|█████████████████▏ | 19.9M/42.8M [00:01<00:01, 19.1MB/s]
52%|███████████████████▏ | 22.2M/42.8M [00:01<00:01, 19.1MB/s]
58%|█████████████████████▎ | 24.7M/42.8M [00:02<00:00, 19.5MB/s]
64%|███████████████████████▍ | 27.2M/42.8M [00:02<00:00, 19.9MB/s]
69%|█████████████████████████▌ | 29.6M/42.8M [00:02<00:00, 19.8MB/s]
75%|███████████████████████████▋ | 32.0M/42.8M [00:02<00:00, 19.9MB/s]
81%|██████████████████████████████ | 34.8M/42.8M [00:02<00:00, 20.9MB/s]
88%|████████████████████████████████▍ | 37.5M/42.8M [00:02<00:00, 21.3MB/s]
93%|██████████████████████████████████▌ | 40.0M/42.8M [00:02<00:00, 21.3MB/s]
99%|████████████████████████████████████▊| 42.6M/42.8M [00:02<00:00, 21.3MB/s]
0%| | 0.00/42.8M [00:00<?, ?B/s]
100%|██████████████████████████████████████| 42.8M/42.8M [00:00<00:00, 215GB/s]
/home/runner/work/moabb/moabb/.venv/lib/python3.10/site-packages/urllib3/connectionpool.py:1064: InsecureRequestWarning: Unverified HTTPS request is being made to host 'lampx.tugraz.at'. Adding certificate verification is strongly advised. See: https://urllib3.readthedocs.io/en/1.26.x/advanced-usage.html#ssl-warnings
warnings.warn(
0%| | 0.00/43.8M [00:00<?, ?B/s]
0%| | 8.19k/43.8M [00:00<10:26, 69.9kB/s]
0%| | 48.1k/43.8M [00:00<03:11, 228kB/s]
0%|▏ | 144k/43.8M [00:00<01:27, 497kB/s]
1%|▎ | 329k/43.8M [00:00<00:47, 908kB/s]
2%|▌ | 688k/43.8M [00:00<00:25, 1.67MB/s]
3%|█▏ | 1.42M/43.8M [00:00<00:13, 3.19MB/s]
7%|██▍ | 2.87M/43.8M [00:00<00:06, 6.16MB/s]
11%|████▎ | 5.03M/43.8M [00:00<00:03, 10.5MB/s]
14%|█████▏ | 6.13M/43.8M [00:01<00:03, 10.1MB/s]
17%|██████▏ | 7.37M/43.8M [00:01<00:03, 10.7MB/s]
20%|███████▌ | 8.94M/43.8M [00:01<00:02, 12.0MB/s]
23%|████████▌ | 10.2M/43.8M [00:01<00:02, 11.8MB/s]
26%|█████████▌ | 11.4M/43.8M [00:01<00:02, 11.5MB/s]
30%|███████████ | 13.0M/43.8M [00:01<00:02, 13.0MB/s]
34%|████████████▍ | 14.8M/43.8M [00:01<00:02, 14.2MB/s]
39%|██████████████▌ | 17.3M/43.8M [00:01<00:01, 17.2MB/s]
44%|████████████████▍ | 19.4M/43.8M [00:01<00:01, 18.6MB/s]
49%|██████████████████▎ | 21.6M/43.8M [00:01<00:01, 19.4MB/s]
55%|████████████████████▎ | 24.1M/43.8M [00:02<00:00, 20.9MB/s]
60%|██████████████████████▎ | 26.4M/43.8M [00:02<00:00, 21.4MB/s]
65%|████████████████████████▏ | 28.6M/43.8M [00:02<00:00, 20.0MB/s]
70%|█████████████████████████▊ | 30.6M/43.8M [00:02<00:00, 19.3MB/s]
74%|███████████████████████████▌ | 32.6M/43.8M [00:02<00:00, 19.4MB/s]
79%|█████████████████████████████▎ | 34.6M/43.8M [00:02<00:00, 19.6MB/s]
84%|██████████████████████████████▉ | 36.6M/43.8M [00:02<00:00, 16.9MB/s]
88%|████████████████████████████████▍ | 38.3M/43.8M [00:02<00:00, 13.1MB/s]
91%|█████████████████████████████████▋ | 39.8M/43.8M [00:03<00:00, 9.74MB/s]
94%|██████████████████████████████████▋ | 41.0M/43.8M [00:03<00:00, 7.96MB/s]
96%|███████████████████████████████████▍ | 42.0M/43.8M [00:03<00:00, 7.44MB/s]
98%|████████████████████████████████████▏| 42.8M/43.8M [00:03<00:00, 7.43MB/s]
100%|████████████████████████████████████▉| 43.7M/43.8M [00:03<00:00, 7.35MB/s]
0%| | 0.00/43.8M [00:00<?, ?B/s]
100%|██████████████████████████████████████| 43.8M/43.8M [00:00<00:00, 179GB/s]
BNCI2014-001-CrossSession: 50%|█████ | 1/2 [00:14<00:14, 14.33s/it]/home/runner/work/moabb/moabb/.venv/lib/python3.10/site-packages/urllib3/connectionpool.py:1064: InsecureRequestWarning: Unverified HTTPS request is being made to host 'lampx.tugraz.at'. Adding certificate verification is strongly advised. See: https://urllib3.readthedocs.io/en/1.26.x/advanced-usage.html#ssl-warnings
warnings.warn(
0%| | 0.00/43.1M [00:00<?, ?B/s]
0%| | 8.19k/43.1M [00:00<10:28, 68.5kB/s]
0%| | 56.3k/43.1M [00:00<02:43, 264kB/s]
0%| | 136k/43.1M [00:00<01:36, 447kB/s]
1%|▎ | 321k/43.1M [00:00<00:48, 875kB/s]
2%|▌ | 673k/43.1M [00:00<00:26, 1.61MB/s]
3%|█▏ | 1.38M/43.1M [00:00<00:13, 3.07MB/s]
7%|██▍ | 2.81M/43.1M [00:00<00:06, 5.94MB/s]
12%|████▎ | 5.03M/43.1M [00:00<00:03, 9.93MB/s]
16%|██████ | 7.09M/43.1M [00:01<00:02, 12.2MB/s]
22%|████████ | 9.32M/43.1M [00:01<00:02, 14.1MB/s]
27%|█████████▊ | 11.4M/43.1M [00:01<00:02, 15.2MB/s]
32%|███████████▋ | 13.6M/43.1M [00:01<00:01, 16.1MB/s]
38%|██████████████▏ | 16.4M/43.1M [00:01<00:01, 18.3MB/s]
44%|████████████████▎ | 19.0M/43.1M [00:01<00:01, 19.1MB/s]
50%|██████████████████▎ | 21.4M/43.1M [00:01<00:01, 19.4MB/s]
56%|████████████████████▌ | 23.9M/43.1M [00:01<00:00, 19.9MB/s]
61%|██████████████████████▋ | 26.5M/43.1M [00:02<00:00, 20.3MB/s]
67%|████████████████████████▉ | 29.0M/43.1M [00:02<00:00, 20.5MB/s]
73%|███████████████████████████ | 31.5M/43.1M [00:02<00:00, 20.6MB/s]
79%|█████████████████████████████▏ | 34.0M/43.1M [00:02<00:00, 20.7MB/s]
85%|███████████████████████████████▍ | 36.6M/43.1M [00:02<00:00, 20.8MB/s]
91%|█████████████████████████████████▌ | 39.1M/43.1M [00:02<00:00, 20.9MB/s]
97%|███████████████████████████████████▊ | 41.6M/43.1M [00:02<00:00, 20.9MB/s]
0%| | 0.00/43.1M [00:00<?, ?B/s]
100%|██████████████████████████████████████| 43.1M/43.1M [00:00<00:00, 192GB/s]
/home/runner/work/moabb/moabb/.venv/lib/python3.10/site-packages/urllib3/connectionpool.py:1064: InsecureRequestWarning: Unverified HTTPS request is being made to host 'lampx.tugraz.at'. Adding certificate verification is strongly advised. See: https://urllib3.readthedocs.io/en/1.26.x/advanced-usage.html#ssl-warnings
warnings.warn(
0%| | 0.00/44.2M [00:00<?, ?B/s]
0%| | 8.19k/44.2M [00:00<10:28, 70.3kB/s]
0%| | 56.3k/44.2M [00:00<02:43, 270kB/s]
0%|▏ | 153k/44.2M [00:00<01:24, 519kB/s]
1%|▎ | 344k/44.2M [00:00<00:45, 955kB/s]
2%|▋ | 728k/44.2M [00:00<00:24, 1.79MB/s]
3%|█▎ | 1.50M/44.2M [00:00<00:12, 3.41MB/s]
7%|██▌ | 3.06M/44.2M [00:00<00:06, 6.60MB/s]
12%|████▎ | 5.15M/44.2M [00:00<00:03, 10.2MB/s]
16%|█████▉ | 7.06M/44.2M [00:01<00:03, 12.1MB/s]
21%|███████▌ | 9.09M/44.2M [00:01<00:02, 13.6MB/s]
25%|█████████▎ | 11.1M/44.2M [00:01<00:02, 14.6MB/s]
30%|███████████▏ | 13.3M/44.2M [00:01<00:01, 15.9MB/s]
35%|████████████▉ | 15.4M/44.2M [00:01<00:01, 16.6MB/s]
40%|██████████████▋ | 17.6M/44.2M [00:01<00:01, 17.0MB/s]
45%|████████████████▌ | 19.8M/44.2M [00:01<00:01, 17.5MB/s]
50%|██████████████████▎ | 21.9M/44.2M [00:01<00:01, 17.7MB/s]
54%|████████████████████▏ | 24.1M/44.2M [00:02<00:01, 17.9MB/s]
59%|█████████████████████▉ | 26.2M/44.2M [00:02<00:00, 18.0MB/s]
64%|███████████████████████▊ | 28.4M/44.2M [00:02<00:00, 18.1MB/s]
69%|█████████████████████████▌ | 30.5M/44.2M [00:02<00:00, 18.1MB/s]
74%|███████████████████████████▎ | 32.7M/44.2M [00:02<00:00, 18.2MB/s]
80%|█████████████████████████████▋ | 35.5M/44.2M [00:02<00:00, 19.9MB/s]
86%|███████████████████████████████▊ | 38.0M/44.2M [00:02<00:00, 20.3MB/s]
92%|█████████████████████████████████▊ | 40.5M/44.2M [00:02<00:00, 20.5MB/s]
97%|███████████████████████████████████▉ | 43.0M/44.2M [00:02<00:00, 20.7MB/s]
0%| | 0.00/44.2M [00:00<?, ?B/s]
100%|██████████████████████████████████████| 44.2M/44.2M [00:00<00:00, 198GB/s]
BNCI2014-001-CrossSession: 100%|██████████| 2/2 [00:26<00:00, 13.03s/it]
BNCI2014-001-CrossSession: 100%|██████████| 2/2 [00:26<00:00, 13.22s/it]
2025-08-22 17:51:46,218 INFO MainThread moabb.evaluations.base AM+LDA | BNCI2014-001 | 1 | 0train: Score 0.786
2025-08-22 17:51:46,334 INFO MainThread moabb.evaluations.base AM+LDA | BNCI2014-001 | 1 | 1test: Score 0.802
2025-08-22 17:51:46,448 INFO MainThread moabb.evaluations.base AM+SVM | BNCI2014-001 | 1 | 0train: Score 0.797
2025-08-22 17:51:46,581 INFO MainThread moabb.evaluations.base AM+SVM | BNCI2014-001 | 1 | 1test: Score 0.774
2025-08-22 17:51:46,710 INFO MainThread moabb.evaluations.base AM+LDA | BNCI2014-001 | 2 | 0train: Score 0.577
2025-08-22 17:51:46,823 INFO MainThread moabb.evaluations.base AM+LDA | BNCI2014-001 | 2 | 1test: Score 0.499
2025-08-22 17:51:46,941 INFO MainThread moabb.evaluations.base AM+SVM | BNCI2014-001 | 2 | 0train: Score 0.551
2025-08-22 17:51:47,069 INFO MainThread moabb.evaluations.base AM+SVM | BNCI2014-001 | 2 | 1test: Score 0.471
Results are returned as a pandas DataFrame, and from here you can do as you want with them
print(results.head())
score time samples ... n_sessions dataset pipeline
0 0.797068 0.144809 144.0 ... 2 BNCI2014-001 AM+SVM
1 0.773920 0.138142 144.0 ... 2 BNCI2014-001 AM+SVM
2 0.550733 0.242238 144.0 ... 2 BNCI2014-001 AM+SVM
3 0.471451 0.159744 144.0 ... 2 BNCI2014-001 AM+SVM
4 0.786458 0.028622 144.0 ... 2 BNCI2014-001 AM+LDA
[5 rows x 9 columns]
Total running time of the script: (0 minutes 28.787 seconds)
Estimated memory usage: 770 MB