✦ Day 08 · Dimensionality Reduction

Principal Component
Analysis (PCA)

Find the orthogonal directions of maximum variance in high-dimensional electrode space — compress 64 correlated channels into a handful of meaningful dimensions without losing the signal that matters.

📊 Eigenvalues & Eigenvectors 📉 Scree Plot 🧹 Rank Reduction 🐍 sklearn.decomposition.PCA

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.


1

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.


2

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.

Python
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()

3

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.

Python
# 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.