Part II: Classical Signal Processing and Feature Engineering
Chapter 8: Feature Engineering and Dimensionality Reduction

PCA, ICA, and manifold methods (UMAP, t-SNE) for sensors

"Give me two hundred correlated channels and I will hand you back the three that were doing all the talking."

A Parsimonious AI Agent

The Big Picture

The feature selection of Section 8.5 keeps a subset of your original columns intact. This section does something different: it transforms many correlated columns into a few new coordinates built as combinations of the originals. Sensor feature tables beg for this: a twelve-axis inertial rig, a sixteen-electrode electromyography sleeve, or a tsfresh table with eight hundred columns is drenched in redundancy, because physically coupled sensors and overlapping features measure the same underlying phenomena again and again. Three tools dominate. Principal component analysis (PCA) finds the linear directions of greatest variance and is your default compressor. Independent component analysis (ICA) separates a mixture into statistically independent sources, which is how you pull an eye-blink artifact out of an EEG trace. Manifold methods, t-SNE and UMAP, unfold nonlinear structure into two or three dimensions so you can see whether your classes cluster at all. Knowing which one to reach for, and where each quietly lies to you, is the point of this section.

This section assumes the covariance and eigen-decomposition background from Chapter 4, and it inherits the windowed feature tables built across the rest of this chapter. Every method here is unsupervised: it never sees your labels, which is both its strength (it works before you have labels) and its risk (the axis of greatest variance is not always the axis that matters).

PCA: rotate to the axes of maximum variance

PCA answers one question: if I must describe each feature vector with only \(k\) numbers instead of \(d\), which \(k\) linear directions preserve the most variance? Center the data, form the covariance matrix \(\mathbf{C} = \tfrac{1}{N}\mathbf{X}^\top\mathbf{X}\), and take its eigenvectors. The eigenvector with the largest eigenvalue is the first principal component, the direction along which the data spreads most; the second is the orthogonal direction of next-most spread, and so on. Projecting onto the top \(k\) eigenvectors gives the best possible \(k\)-dimensional linear approximation in a least-squares sense:

$$\mathbf{C}\,\mathbf{v}_j = \lambda_j \mathbf{v}_j, \qquad \text{variance explained by } k = \frac{\sum_{j=1}^{k}\lambda_j}{\sum_{j=1}^{d}\lambda_j}.$$

Why it works for sensors: physically coupled channels are highly correlated, so a handful of components typically recover 90 to 99 percent of the variance of a table with hundreds of columns. That buys you faster models, less overfitting, and a natural denoising step, because the smallest components are usually where broadband sensor noise hides. When to use it: as a first-line compressor before a classifier, as a whitening stage in front of ICA, and as a sanity check on redundancy. The one non-negotiable preprocessing step is standardization. PCA chases variance, so a feature measured in raw accelerometer counts (variance in the thousands) will swamp a feature measured as a dimensionless ratio unless you first scale every column to unit variance.

Key Insight: Maximum Variance Is Not Maximum Relevance

PCA optimizes for variance, and it is blind to your labels. Nothing guarantees that the direction of greatest spread is the direction that separates your classes; a large, label-irrelevant nuisance (subject-to-subject amplitude differences, changing motor load) can easily own the first component while the discriminative signal sits in component seven. This is the single most common way PCA hurts a sensor pipeline: people keep the top few components, throw away the rest, and discard the class signal along with the noise. If you have labels and want a supervised projection, reach for Linear Discriminant Analysis instead, which maximizes between-class over within-class scatter. Use PCA to compress and denoise, not to guarantee separability.

ICA: unmix statistically independent sources

PCA finds uncorrelated directions; ICA finds independent ones, a strictly stronger and often more physically meaningful goal. The setting is the classic cocktail party: several sensors each record a linear mixture \(\mathbf{x} = \mathbf{A}\mathbf{s}\) of several underlying sources \(\mathbf{s}\), and you want to recover an unmixing matrix \(\mathbf{W}\approx\mathbf{A}^{-1}\) so that \(\hat{\mathbf{s}} = \mathbf{W}\mathbf{x}\) gives back the sources. The trick that makes it possible is non-Gaussianity: by the central limit theorem a mixture of independent sources is more Gaussian than any single source, so algorithms like FastICA search for the projection directions that are maximally non-Gaussian (maximizing kurtosis or negentropy). Order and sign of the recovered sources are arbitrary: FastICA's non-Gaussianity objective is unchanged by permuting the rows of \(\mathbf{W}\) or flipping any row's sign, so the algorithm cannot know that channel two is the eye blink or that it should point positive. You resolve this by correlating each component against a reference signal, a co-recorded EOG channel for instance, and by fixing a sign convention such as "largest peak positive," since a deployed pipeline that refits \(\mathbf{W}\) fresh each session can silently swap which channel holds yesterday's eye-blink artifact for today's heart rate.

Where ICA earns its keep in sensing is artifact removal and source separation. In electroencephalography, eye blinks and cardiac interference are independent of brain activity and mix linearly across the scalp electrodes, so ICA can isolate them into their own components that you zero out before reconstructing a clean signal, a workhorse technique for the brain-computer interfaces of Chapter 31. It also separates overlapping motor-unit trains in high-density electromyography and untangles crosstalk in multi-antenna radio arrays. Standard practice is to whiten with PCA first (which also lets you drop the noise dimensions), then run ICA on the whitened, dimension-reduced data.

import numpy as np
from sklearn.decomposition import PCA, FastICA

rng = np.random.default_rng(0)
t = np.linspace(0, 8, 4000)
s1 = np.sin(2 * np.pi * 1.0 * t)            # a slow oscillation
s2 = np.sign(np.sin(2 * np.pi * 3.0 * t))   # a square wave
s3 = rng.uniform(-1, 1, t.size)             # noise-like source
S = np.c_[s1, s2, s3]
A = np.array([[1.0, 0.8, 0.4],              # unknown mixing matrix
              [0.6, 1.0, 0.7],
              [0.9, 0.5, 1.0]])
X = S @ A.T                                 # 3 "sensors", each a mixture

X = (X - X.mean(0)) / X.std(0)              # standardize before either method
pcs = PCA(n_components=3).fit_transform(X)  # uncorrelated, variance-ranked
src = FastICA(n_components=3, random_state=0).fit_transform(X)  # independent

def corr_to_truth(est):
    return np.abs(np.corrcoef(est.T, S.T)[:3, 3:]).max(1).round(2)
print("PCA best match to each true source:", corr_to_truth(pcs))
print("ICA best match to each true source:", corr_to_truth(src))
Three sources are linearly mixed into three sensor channels. PCA returns variance-ranked but still-blended directions, while FastICA recovers each original source almost exactly (correlations near 1.0). Run it to see ICA succeed at unmixing where PCA, which only decorrelates, cannot.

The code above makes the distinction concrete: PCA hands back components that are uncorrelated yet still mixtures of the true sources, whereas ICA recovers the individual square wave, sinusoid, and noise source, because independence is a stronger constraint than mere decorrelation.

Manifold methods: t-SNE and UMAP for seeing structure

PCA is linear: it can only rotate and project. Real sensor data often lies on a curved, low-dimensional manifold embedded in high-dimensional feature space (think of the smooth loop a gait cycle traces), and a linear projection smears that structure. Manifold methods embed the data into two or three dimensions while preserving local neighborhoods. t-SNE (t-distributed stochastic neighbor embedding) models pairwise similarities as probabilities and arranges points so near neighbors stay near; its perplexity parameter sets the effective neighborhood size. UMAP (uniform manifold approximation and projection) builds a fuzzy nearest-neighbor graph and optimizes a low-dimensional layout that matches it; it is faster, scales to millions of points, better preserves global structure, and (unlike classic t-SNE) can transform new points with a fitted model.

When to use them: almost exclusively for visualization and diagnosis, not as features for a downstream model. A UMAP plot of your windowed features colored by class tells you at a glance whether the classes are separable at all, whether two labels are hopelessly overlapping, and whether one subject or device forms its own island (a red flag for the leakage discipline of Chapter 5). What they are not: a metric space.

Misconception: Cluster Distance Means Something

The most common misreading of a t-SNE or UMAP plot treats it like an ordinary scatter plot of real distances: assuming two clusters twice as far apart are "twice as different," or that a tight cluster means low variance back in the original feature space. Neither holds. t-SNE's cost function only tries to keep nearby points nearby, free to stretch or compress the space between far-apart clusters however the optimization prefers, and UMAP's layout is shaped by n_neighbors and min_dist at least as much as by the true geometry of your sensor features. Treat the plot as a neighbor graph, not a ruler: "these points are neighbors" is valid, "this gap is twice that gap" is not.

Practical Example: A UMAP Plot That Exposed a Leaky Wearable Split

A team building a human-activity classifier for a wrist wearable had 563 features per window from a nine-axis inertial unit worn by thirty volunteers, and their model hit a suspiciously high 97 percent accuracy in cross-validation. Before trusting it, an engineer ran UMAP on the standardized feature table and colored the embedding two ways. Colored by activity (walk, run, sit, stairs) the clusters were sensible but overlapping; colored by subject ID, the plot fractured into thirty tight, well-separated islands, meaning the features encoded who was wearing the device far more strongly than what they were doing. The random split had leaked subjects across train and test, so the model was partly recognizing wrists, not motion. A subject-disjoint split (the discipline of Chapter 26) dropped honest accuracy to 84 percent; the two-minute plot had saved the team from shipping a fantasy.

Right Tool: PCA Whitening plus UMAP in Four Lines

A correct pipeline that standardizes, PCA-whitens to strip noise dimensions, then embeds with a neighbor graph is easily 120 to 150 lines of hand-written linear algebra, nearest-neighbor search, and gradient optimization. scikit-learn and umap-learn collapse it:

from sklearn.pipeline import make_pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.decomposition import PCA
import umap
emb = make_pipeline(StandardScaler(), PCA(n_components=30),
                    umap.UMAP(n_neighbors=15, min_dist=0.1)).fit_transform(X)

The libraries own the eigensolver, the approximate nearest-neighbor index, and the layout optimizer. You still own the choices no library can make: standardize first, fit the scaler and PCA on the training split only, and treat the plot as a diagnostic, not a distance map.

Standardization, PCA whitening, and a UMAP embedding in four lines, replacing roughly 120 to 150 lines of error-prone numerical code.

Research Frontier: Learned Nonlinear Unmixing

Classical ICA only identifies sources under a linear mixing assumption; recovering sources from a genuinely nonlinear mixture was long believed impossible without extra structure. Recent identifiability results, building on Hyvärinen's work relating time-contrastive prediction to nonlinear ICA, show that self-supervised objectives trained on time-shifted sensor windows can recover the true underlying sources up to permutation and a simple elementwise transform, the theoretical seed behind the contrastive sensor representations of Chapter 17, best understood as ICA's nonlinear, learned-from-data descendant.

Using them correctly for sensors

Three cautions keep these methods from betraying you. First, fit on train only: a PCA basis, an ICA unmixing matrix, and a UMAP model are all fitted objects with learned parameters, and fitting any of them on the full dataset before splitting leaks test information into your reported accuracy, the exact trap Chapter 5 warns against. Fit on the training fold, then transform validation and test. Second, match the tool to the goal: PCA to compress and denoise, LDA when you have labels and want separation, ICA to recover physical sources, manifold methods to look. Third, resist using t-SNE or UMAP coordinates as model inputs; they are non-deterministic across runs and distort the metric, so a classifier trained on them is standing on sand. Compress with PCA, unmix with ICA, look with UMAP: three different questions, and answering the wrong one is how a careful sensor pipeline quietly goes wrong.

Exercise

Using the three-source mixing setup from the code block: (1) Add a fourth, purely Gaussian source and rerun FastICA; explain why the algorithm struggles to separate it and what non-Gaussianity has to do with it. (2) On a labeled sensor feature table of your choice, keep enough PCA components for 95 percent variance, train a classifier, then repeat with LDA to the same number of dimensions; compare accuracy and explain the gap. (3) Run UMAP twice with n_neighbors of 5 and 50; describe how the global versus local structure changes and why you cannot read cluster distances as meaningful.

Self-Check

  1. PCA and ICA both produce a linear transform of the data. What does ICA achieve that PCA cannot, and what property of the sources makes it possible?
  2. Why should you almost never feed t-SNE or UMAP coordinates into a downstream classifier, and what should you use instead when you need learned low-dimensional features?
  3. Your first principal component explains 80 percent of the variance but a classifier built on it performs terribly. What is the most likely explanation, and which method would you switch to?

What's Next

In Section 8.7, we step back and ask the honest question that hangs over this entire chapter: when do these carefully handcrafted, dimensionality-reduced features still beat an end-to-end deep network, and when is it time to let a model learn its own representation from the raw signal?