A 64-channel EEG system generates 64 simultaneous time series. But these signals are highly correlated — neighbouring electrodes “see” much of the same brain activity. Principal Component Analysis (PCA) finds the orthogonal directions of maximum variance in this high-dimensional space, letting you represent the same data in far fewer dimensions without losing the signal that matters.
The Eigen-Decomposition Intuition
Finding Directions of Maximum Variance
Imagine your 64-channel data as a cloud of points in 64-dimensional space (each time point is one point). PCA finds the axis along which this cloud is most stretched — that’s PC1, the direction of maximum variance. PC2 is the direction of maximum variance orthogonal to PC1, and so on.
Mathematically, PCA eigen-decomposes the covariance matrix C = XTX / (n−1). The eigenvectors are the principal directions; the eigenvalues tell you how much variance each direction captures.
Cohen’s perspective (ANTS Ch. 27): PCA components are like ICA components but with a different objective. PCA maximizes explained variance (decorrelation); ICA maximizes statistical independence (non-Gaussianity). PCA is a rotation; ICA is a rotation plus a scaling that seeks independent sources.
The Scree Plot
How Many Components to Keep?
A scree plot shows eigenvalues (explained variance) versus component number. You look for the “elbow” — the point where adding more components gives diminishing returns. In EEG, the first 10–20 PCs typically capture >95% of total variance because of the high spatial correlation between neighbouring electrodes.
from sklearn.decomposition import PCA import numpy as np # data shape: (n_channels, n_times) - transpose for sklearn X = raw.get_data().T # (n_times, n_channels) pca = PCA() pca.fit(X) # Cumulative explained variance cumvar = np.cumsum(pca.explained_variance_ratio_) n_95 = np.argmax(cumvar >= 0.95) + 1 print(f"Components for 95% variance: {n_95}") # Scree plot import matplotlib.pyplot as plt plt.plot(pca.explained_variance_ratio_, 'o-') plt.xlabel('Component'); plt.ylabel('Explained Variance Ratio') plt.axvline(n_95, color='r', ls='--', label=f'95% at PC{n_95}') plt.legend(); plt.show()
PCA in EEG Preprocessing
Rank Reduction Before ICA
PCA is often used as a preprocessing step for ICA. After interpolating bad channels or re-referencing to average, your data becomes rank-deficient (the number of linearly independent channels is less than the total). Running ICA on rank-deficient data produces unstable, noisy components.
The solution: reduce to the true rank with PCA first, then run ICA on the reduced data.
MNE handles this automatically when you set n_components in the ICA constructor.
# Check rank after interpolation + average reference rank = mne.compute_rank(raw, rank='info') print(f"Data rank: {rank}") # ICA with explicit rank-aware component count n_components = rank['eeg'] - 1 # minus 1 for avg ref ica = ICA(n_components=n_components, method='infomax') ica.fit(raw_filt)
PCA vs. ICA at a glance: PCA finds orthogonal directions of maximum variance (best for compression). ICA finds statistically independent sources (best for source separation). They are often used sequentially: PCA to reduce rank, then ICA to unmix sources.