Classification done honestly
Features, LDA, CSP, and Riemannian classifiers, then the part that matters more than the algorithm, which is how you split the data. Leakage, chance levels, calibration drift, and information transfer rate.
You are skimming: the title, the first figure, and the short version. Switch to Read in the header for the full page, or Deep to open every deep dive.
A classifierClassifierAn algorithm that assigns each trial a label, such as left hand or right hand, after being trained on labelled examples. Glossary entry learns a rule from labelled examples and applies it to new ones. Every BCI is one. The algorithms are the easy part and this page covers them in a few paragraphs. The hard part, the part where most student projects and a distressing number of papers go wrong, is evaluation: making sure the number you report is the number a new person on a new day would get. That takes most of the page, because it deserves it.
Features
A classifier wants a short vector of numbers per trial. For EMG and oscillatory EEG: band powers or log-variances per channel, sometimes after a spatial filter. For ERPs: the downsampled voltage waveform, channels concatenated. For SSVEP: correlations with reference frequencies. Good features make simple classifiers work; no classifier rescues bad features. The most reliable way to improve a BCI is still to improve the signal.
Three classifiers that cover the field
Linear discriminant analysisLinear discriminant analysis (LDA)A simple, robust classifier that draws a straight boundary between classes; the workhorse of EEG decoding for two decades. Glossary entry fits a Gaussian to each class with a shared covariance and draws the boundary where they are equally likely. Few parameters, hard to overfit, fast, and the default in BCI for two decades. With shrinkage regularization it handles more features than trials, which is the usual EEG situation.
Common spatial patternsCommon spatial patterns (CSP)Spatial filters that maximize the variance of one class while minimizing the other, the classic feature extractor for motor imagery. Glossary entry is a feature extractor for two-class oscillatory problems: it finds spatial filters whose output variance is large for one class and small for the other. The log-variance of a few CSP components, then LDA, is the classic motor imagery pipeline.
Riemannian geometryRiemannian geometry classifiersMethods that treat each trial's covariance matrix as a point on a curved space and classify by distance there; the strongest simple baseline for EEG today. Glossary entry classifiers skip feature engineering: each trial is represented by its channel covariance matrix, which lives on a curved space where the natural distance is not Euclidean. Map the matrices to the tangent space at their mean and run logistic regression. This is the strongest simple baseline on nearly every public EEG dataset and it is three lines in pyRiemann. Learn it after LDA, and use it by default.
from pyriemann.estimation import Covariances
from pyriemann.tangentspace import TangentSpace
from sklearn.linear_model import LogisticRegression
from sklearn.pipeline import make_pipeline
clf = make_pipeline(Covariances('oas'), TangentSpace(), LogisticRegression())
Support vector machines, random forests, and neural networks exist too. On EEG-sized datasets they rarely beat the three above by more than noise, and they overfit more. The deep learning page is about when they do and do not help.
Now the part that matters
You have 200 trials from one session. You shuffle them, train on 160, test on 40, and get 88 percent. Tomorrow, with the same classifier, what do you expect?
Substantially lower, and today’s data cannot tell you how much. Shuffled trials from one session share everything that drifts slowly: electrode impedances, the participant’s state, the exact cap position. The test set is not a new day; it is the same day with a few trials hidden. Only a second session tells you the cross-session number, and it is typically five to twenty points lower.
Leakage. Any information from the test set that reaches training is leakageData leakageInformation from the test set sneaking into training, for example by shuffling trials from one session across both; it inflates accuracy and is the most common flaw in student BCI papers. Glossary entry, and it inflates the number. Shuffling trials across sessions. Fitting the CSP filters, the normalization, or the ICA on all the data before splitting. Choosing hyperparameters on the test set. Choosing which subjects to include after seeing results. Each of these is common, each is easy to do by accident, and scikit-learn’s pipelines exist to prevent the second one: put every fitted step inside the pipeline so cross-validation fits it on training folds only.
The right splits, in increasing honesty. Shuffled trials within a session: the wrong way, useful only to check the code runs. Grouped by run or block within a session: honest within-session. Train on session one, test on session two: the cross-session number, which is what a user experiences. Leave one subject out: the cross-subject number, which is what a calibration-free product would need. Report the one that matches the claim you are making, and say which.
Chance is not 50 percent. With two classes and forty trials, a coin-flip classifier scores above 62 percent one time in twenty. The binomial distribution gives the upper bound for any trial count; the statistics page has it. Always report the chance bound next to the accuracy. With unbalanced classes, use balanced accuracy or report the confusion matrix, because 80 percent on a task with 80 percent standards is chance.
Calibration and drift. Signals change within a session (electrodes settle, attention fades) and between sessions (cap position, mood, sleep). A deployed BCI recalibrates at the start of each session and often adapts during it. If your evaluation does not include the cost of that, it is not evaluating the system.
Information transfer rate
Accuracy alone misleads: 90 percent on two targets in ten seconds is worse than 70 percent on eight targets in three. Wolpaw’s information transfer rate combines them. Bits per selection:
B = log₂N + P·log₂P + (1−P)·log₂((1−P)/(N−1))
for N targets and accuracy P, and ITR is B times selections per minute. A good SSVEP speller reaches 40 to 60 bits per minute; a P300 speller 10 to 25; motor imagery under 10. Report it, and report the time per selection it assumes.
Deep dive Why LDA works so well on EEG 3 min
EEG features are roughly Gaussian, classes differ mostly in their means, and trials are few. LDA’s assumptions match, and its parameter count is small (a mean per class and one shared covariance), so it does not overfit. Shrinkage LDA regularizes the covariance toward the identity, which is essential when features outnumber trials, and the shrinkage amount can be set analytically (Ledoit-Wolf) with no cross-validation. It is hard to beat, and any method that claims to should be compared against it with the same split.
Deep dive Nested cross-validation for hyperparameters 3 min
If you tune anything (the number of CSP components, the regularization strength) you must tune it inside each training fold, using an inner cross-validation, and evaluate on the outer test fold that never saw the tuning. Tuning on the same folds you report is leakage and adds several points. scikit-learn’s GridSearchCV inside cross_val_score does this correctly.
Deep dive Transfer learning and calibration-free BCIs 3 min
Aligning each session’s covariance to a common reference (Riemannian alignment) before classification lets data from other sessions and other people help, and cuts calibration time. It works better for SSVEP and P300 than for motor imagery. The dream of a BCI that works for a new person with no calibration is the field’s current frontier, and it is measured by leave-one-subject-out accuracy, which is currently far below within-subject for everything but SSVEP.
Explain what this page was about to your roommate in three sentences. No jargon they would not know.