Phase 2 · Classical ML, built by you · Topic 2.15

PCA in practice

In practice, PCA is used to compress features, remove noise, speed up other models and plot high-dimensional data, keeping just enough components to hold most of the variance.

Not started

Step 1 Understand it

The problem it solves. You now know how works; the hard part is using it well. How many components should you keep? Should you scale first? When does it help a downstream , and when does it throw away the very signal you need? Those practical choices decide whether PCA helps or hurts.

New words in this topic (tap one to see what it means)

Watch it happen

AnimationChoosing how many components to keep, and when PCA hurts
Read the animation as text
  1. Data with 8 features. PCA's first component alone holds 53% of the variance.
  2. The rest hold less and less. This is a scree plot: share of variance per component.
  3. Add them up (green). 4 components reach the 95% line, so you can keep 4 numbers per sample instead of 8 and lose only 5% of the spread.

The idea

Use PCA to compress data, remove , or plot high- data in 2D. Always first, and scale it if use different units.

How it works, step by step

  1. Fit on only: compute the (and, if units differ, the ) from the rows.
  2. Centre (and scale) the data, then run .
  3. Plot the ratio per component (a scree plot) and its running total.
  4. Pick k where the running total reaches your target, often 90–99%, or at the elbow of the scree plot.
  5. Transform: keep the component scores as the new features. Apply the same transform to validation and test data.
  6. For visualisation, plot the first two or three components, coloured by .
  7. To check what was lost, reconstruct the data from k components and compare it with the original.

Picture it

xychart-beta
  title "Share of the variance kept by each component"
  x-axis "principal component" [1, 2, 3, 4]
  y-axis "% of variance" 0 --> 70
  bar [62, 24, 9, 5]
The first few components usually hold most of the spread. Keep enough to reach your target (often around 95%) and drop the rest.

Analogy

Photographing a 3D object from the angle that shows the most detail.

Where the analogy breaks

The angle with the most spread is not always the most useful one. PCA ignores the labels, so the direction that separates your classes might be dropped.

Worked example

images have 784 pixels. About 150 principal components keep around 95% of the .

python
explained = S**2 / np.sum(S**2)
k = np.searchsorted(np.cumsum(explained), 0.95) + 1   # components for 95%

Must-know points

  • Centre always; when features have different units.
  • Cumulative explained variance chooses k.
  • PCA ignores labels: maximum spread is not always maximum usefulness.
  • It removes correlated, redundant features and can denoise data.
  • structure needs other (t-SNE or UMAP for plotting, in Phase 7).
  • For MNIST digits, about 150 of 784 components keep around 95% of the variance.

Common mistakes

  • Fitting PCA on the full , test set included.
  • Not scaling mixed-unit features.
  • Assuming components have a human meaning.
  • Dropping low-variance components that actually separate the classes.

Step 2 Go further (optional)

Optional. The lesson above is written to be enough on its own. If you want a second explanation, start with the one marked Worth it.

Step 3 Practise

Try each exercise yourself first: on paper, out loud or in code. Then open the answer and compare it with yours.

  1. ExplainSay it in plain words, with no notes.

    Explain when PCA helps and when it hurts, with the camera-angle picture.

    Show answer

    Photographing a 3D object: you get to keep only a 2D picture, so you choose the angle that shows the most detail. A teapot photographed from the side shows its spout and handle; from directly above, it looks like a circle. PCA chooses the camera angle that keeps the most spread in the data, so the flattened picture loses as little as possible.

    It helps when most of the spread is the interesting part: compressing images, removing near-duplicate features, speeding up a model, or plotting high-dimensional data. It hurts when the important detail is small: if the one thing you care about is a tiny mark on the teapot's lid, the "best" side view hides it. PCA keeps the biggest variation, not the most useful one.

  2. DeriveWrite the maths, or the steps, from memory.

    The are [5, 3, 1.5, 0.5]. What fraction of the variance do the top 2 components keep?

    Show answer

    The eigenvalues of the covariance matrix are the variances along each principal direction, so the share of variance a component keeps is its eigenvalue divided by the total.

    Total: 5 + 3 + 1.5 + 0.5 = 10.
    Top two: 5 + 3 = 8.
    Fraction kept: 8 / 10 = 80%.

    The first component alone keeps 50%, and adding the third would bring it to 95%.

  3. BuildCode it from scratch in NumPy, with no ML library.

    Compress MNIST digits to 10, 50 and 150 components and reconstruct them. Show the images side by side with their explained variance.

    Show answer

    Flatten each 28 × 28 image into 784 numbers, centre the data, take the SVD, keep the top k directions, and reconstruct each image as mean + (coordinates × directions).

    On 10,000 MNIST training images, 10 components keep about half the variance and give blurry but recognisable ; 50 keep about 80% and the digits are clear; 150 keep about 95% and look almost like the originals, from 784 numbers down to 150.

    python
    import numpy as np
    import matplotlib.pyplot as plt
    from torchvision import datasets             # only to download MNIST
    
    mnist = datasets.MNIST("data", train=True, download=True)
    X = mnist.data[:10_000].numpy().reshape(10_000, -1) / 255.0      # (10000, 784)
    mean = X.mean(axis=0)
    U, S, Vt = np.linalg.svd(X - mean, full_matrices=False)
    ratio = np.cumsum(S**2) / np.sum(S**2)
    
    ks = [10, 50, 150]
    fig, axes = plt.subplots(4, len(ks) + 1, figsize=(8, 8))
    for row in range(4):
        axes[row, 0].imshow(X[row].reshape(28, 28), cmap="gray")
        for col, k in enumerate(ks, start=1):
            recon = mean + (X[row] - mean) @ Vt[:k].T @ Vt[:k]
            axes[row, col].imshow(recon.reshape(28, 28), cmap="gray")
    for col, k in enumerate(ks, start=1):
        axes[0, col].set_title(f"{k}: {ratio[k - 1]:.0%}")
    axes[0, 0].set_title("original")
    for ax in axes.flat:
        ax.axis("off")
    plt.show()
    print({k: round(float(ratio[k - 1]), 3) for k in ks})
  4. BreakShow when it fails, and why.

    Make a dataset where the class difference lies in a low-variance direction. Show that PCA to 1 component destroys the separation.

    Show answer

    Make two features: x₁ varies a lot (standard deviation 10) but is the same for both classes, and x₂ varies little (standard deviation 0.5) but its mean is −1 for one class and +1 for the other. All the class information is in the small, quiet direction.

    PCA keeps the direction with the most variance, so with one component it keeps x₁ and throws x₂ away. A simple on that one component does no better than a coin flip, about 50%, while the same classifier on x₂ alone gets about 98%.

    The lesson: PCA is unsupervised. It looks for spread, not for what predicts the label, and "most variance" is not the same as "most useful". Check how a downstream model performs after reducing dimensions.

    python
    import numpy as np
    
    rng = np.random.default_rng(0)
    n = 1000
    y = rng.integers(0, 2, n)
    X = np.column_stack([rng.normal(0, 10, n),                      # big spread, no signal
                         np.where(y == 1, 1.0, -1.0) + rng.normal(0, 0.5, n)])   # small spread, all signal
    Xc = X - X.mean(axis=0)
    first = np.linalg.svd(Xc, full_matrices=False)[2][0]
    z = Xc @ first
    print("first component:", first.round(3))                     # ≈ [±1, 0]: it kept x₁
    accuracy = lambda feature: max(np.mean((feature > 0) == y), np.mean((feature < 0) == y))
    print(f"on the PCA component: {accuracy(z):.0%}, on x₂: {accuracy(Xc[:, 1]):.0%}")

Step 4 Prove it

Check you understood

The eigenvalues are [6, 2, 1, 1]. What share do the top 2 components keep?

(6 + 2) / 10 = 80%.

Why might PCA hurt a classifier?

It keeps the directions of largest spread, ignoring labels. If the classes differ along a low-variance direction, that difference can be thrown away.

When must you standardise before PCA?

When features are in different units or scales; otherwise the one with the largest numbers dominates the first component.

Should PCA be fitted before or after splitting the data?

After: fit it on the training rows only, then apply it to the rest.

Tick each check when you can do it without notes

A topic is finished when you pass all four checks, not when you finish reading. Be strict: if you needed your notes, it is not ticked yet.

  • Explain Say it in plain words, with no notes.
  • Derive Write the maths, or the steps, from memory.
  • Build Code it from scratch in NumPy, with no ML library.
  • Break Show when it fails, and why.

0 of 4 checks ticked.

Saved in this browser. Back it up or move it to another device.