Bayesian LDA - Bayesian Linear Discriminant Analysis
Python:NimbusLDA | Julia: NimbusLDAMathematical Model: Pooled Gaussian Classifier (PGC) Bayesian LDA is a Bayesian classification model with uncertainty quantification. It uses a shared precision matrix across all classes, making it fast and efficient for BCI classification.
Python Personalizer head: use as
Personalizer(head="lda") (default), or standalone as NimbusLDA. See Personalizer & Middleware.Available in Both SDKs:
- Python SDK:
NimbusLDAclass (sklearn-compatible) - Julia SDK:
NimbusLDA(RxInfer.jl-based)
Start Here
Quickstart
Start with SDK setup and first inference workflow.
Model Selection
Compare Nimbus models by data characteristics and use case.
Examples
See practical BCI examples for training and inference.
Overview
Bayesian LDA extends traditional Linear Discriminant Analysis with full Bayesian inference, providing: ✅ Posterior probability distributions (not just point estimates)✅ Uncertainty quantification for each prediction
✅ Probabilistic confidence scores
✅ Fast inference (<20ms per trial)
✅ Training and calibration support
✅ Batch and streaming inference modes
Quick Start
- Python
- Julia
When to Use Bayesian LDA
Bayesian LDA is ideal for:- Motor Imagery classification (2-4 classes)
- Well-separated class distributions
- Fast inference requirements (<20ms)
- Interpretable results for medical applications
- When classes have similar covariance structures
- Classes have significantly different covariance structures
- Complex, overlapping distributions
- Need more flexibility in modeling per-class variances
Model Architecture
Mathematical Foundation (Pooled Gaussian Classifier)
Bayesian LDA implements a Pooled Gaussian Classifier (PGC), which models class-conditional distributions with a shared precision matrix:μ_k= mean vector for class k (learned from data)W= shared precision matrix (same for all classes)- Assumes classes have similar covariance structure
Hyperparameters
Bayesian LDA supports configurable hyperparameters for optimal performance tuning: Available Hyperparameters (training):
Parameter Effects:
-
dof_offset: Controls regularization strength
- Lower values (1) → More data-driven, less regularization
- Higher values (3-5) → More regularization, more conservative
-
mean_prior_precision: Controls prior strength on class means
- Lower values (0.001) → Weaker prior, trusts data more
- Higher values (0.05-0.1) → Stronger prior, more regularization
Model Structure
RxInfer Implementation
The Bayesian LDA model uses RxInfer.jl for variational Bayesian inference: Learning Phase:Usage
1. Load Pre-trained Model
Python SDK: The Python SDK (
nimbus-bci) trains models locally and doesn’t require pre-trained model loading. See Python SDK Quickstart for training examples.- Python
- Julia
2. Train Custom Model
- Python
- Julia
iterations: Number of variational inference iterations (default: 50)- More iterations = better convergence but slower training
- 50-100 is typically sufficient
showprogress: Display progress bar during trainingname: Model identifierdescription: Model description for documentationdof_offset: Degrees of freedom offset (default: 2, range: [1, 5])mean_prior_precision: Prior precision for means (default: 0.01, range: [0.001, 0.1])
3. Subject-Specific Calibration
Fine-tune a pre-trained model with subject-specific data (much faster than training from scratch):- Python
- Julia
- Requires only 10-20 trials per class (vs 50-100 for training from scratch)
- Faster: 20 iterations vs 50-100
- Better generalization: Uses pre-trained model as prior
- Typical accuracy improvement: 5-15% over generic model
- Hyperparameters automatically preserved:
calibrate_model()inherits training hyperparameters from the base model (dof_offset,mean_prior_precision) ensuring consistency
Important: You don’t need to specify hyperparameters when calibrating - they are automatically inherited from the base model. This ensures the calibrated model uses the same regularization strategy that worked well during initial training.
4. Batch Inference
Process multiple trials efficiently:- Python
- Julia
5. Streaming Inference
Real-time chunk-by-chunk processing:For detailed Python streaming examples, see Python SDK Streaming Inference.
- Python
- Julia
Hyperparameter Tuning (v0.2.0+)
Fine-tune Bayesian LDA for optimal performance on your specific dataset.When to Tune Hyperparameters
Consider tuning when:- Default performance is unsatisfactory
- You have specific data characteristics (very noisy or very clean)
- You have limited or extensive training data
- You want to optimize for your specific paradigm
Tuning Strategies
For High SNR / Clean Data / Many Trials
Use lower regularization to let the data drive the model:- Python
- Julia
- SNR > 5 dB
- 100+ trials per class
- Clean, artifact-free data
- Well-controlled experimental conditions
For Low SNR / Noisy Data / Few Trials
Use higher regularization for stability:- Python
- Julia
- SNR < 2 dB
- 40-80 trials per class
- Noisy data or limited artifact removal
- Challenging recording conditions
Balanced / Default Settings
The defaults work well for most scenarios:- Moderate SNR (2-5 dB)
- 80-150 trials per class
- Standard BCI recording conditions
- Starting point for experimentation
Hyperparameter Search Example
Systematically search for optimal hyperparameters:- Python
- Julia
Quick Tuning Guidelines
Training Requirements
Data Requirements
- Minimum: 40 trials per class (160 total for 4-class)
- Recommended: 80+ trials per class (320+ total for 4-class)
- For calibration: 10-20 trials per class sufficient
Feature Normalization
- Python
- Julia
Feature Requirements
Bayesian LDA expects preprocessed features, not raw EEG: ✅ Required preprocessing:- Bandpass filtering (8-30 Hz for motor imagery)
- Artifact removal (ICA recommended)
- Spatial filtering (CSP for motor imagery)
- Feature extraction (log-variance for CSP features)
- Temporal aggregation (handled automatically during training/inference)
- Raw EEG channels
- Unfiltered data
- Non-extracted features
Temporal Aggregation
The aggregation method depends on your feature type and paradigm:- CSP features: Log-variance aggregation (default for motor imagery)
- Power spectral features: Mean or median aggregation
- Other features: Configurable via
BCIMetadata.temporal_aggregation
train_model() and predict_batch() calls.
Performance Characteristics
Computational Performance
All measurements on standard CPU (no GPU required).
Classification Accuracy
Accuracy is highly subject-dependent. Subject-specific calibration typically improves accuracy by 5-15%.
Model Inspection
View Model Parameters
- Python
- Julia
Accessing model parameters: The SDK stores full posterior distributions (not just point estimates) for proper Bayesian inference. To get point estimates, use
mean(posterior) to extract the mean of the posterior distribution. For precision matrices, use mean(precision_posterior) to get the expected precision matrix.Compare Models
- Python
- Julia
Advantages & Limitations
Advantages
✅ Fast Training: Shared covariance estimation is efficient✅ Fast Inference: Analytical posterior computation (<20ms)
✅ Interpretable: Clear probabilistic formulation
✅ Memory Efficient: Single shared precision matrix
✅ Robust: Handles uncertainty naturally via Bayesian inference
✅ Production-Ready: Battle-tested in real BCI applications
Limitations
❌ Shared Covariance Assumption: May not fit well if classes have very different spreads❌ Linear Decision Boundary: Cannot capture non-linear class boundaries
❌ Gaussian Assumption: Assumes normal class distributions
❌ Not Ideal for Overlapping Classes: Use NimbusQDA for complex distributions
Model Selection Context
UseNimbusLDA when classes are mostly stationary and well separated, and speed or interpretability matter. If classes overlap with different covariance structure, consider NimbusQDA. If the decision boundary is non-Gaussian, consider NimbusSoftmax in Python or NimbusProbit in Julia. If distributions drift over time, consider NimbusSTS in Python.
For the canonical side-by-side comparison, see Model Specification.
Next Read
Bayesian QDA (NimbusQDA)
More flexible classifier with class-specific covariances
NimbusSoftmax (Python)
Python non-Gaussian static classifier for complex decision boundaries
NimbusProbit (Julia)
Julia non-Gaussian static classifier for complex decision boundaries
Bayesian STS (NimbusSTS)
Adaptive model for non-stationary data and long sessions
Training Tutorial
Complete training walkthrough
Code Examples
Working examples
References
Implementation:- RxInfer.jl: https://rxinfer.com/
- Source code:
src/models/nimbus_lda/in NimbusSDKCore
- Fisher, R. A. (1936). “The use of multiple measurements in taxonomic problems”
- Bishop, C. M. (2006). “Pattern Recognition and Machine Learning” (Chapter 4)
- Pooled Gaussian Classifier (PGC) with shared covariance structure
- Blankertz et al. (2008). “Optimizing spatial filters for robust EEG single-trial analysis”
- Lotte et al. (2018). “A review of classification algorithms for EEG-based BCI”