100% Free Forever
AI-Powered Learning
Industry Expert Content
Certificates & Badges
Learn At Your Own Pace
Machine Learning with Scikit-learn
25 minintermediate

PCA for Dimensionality Reduction

PCA for Dimensionality Reduction

In Course 3 you met PCA as a pre-processing step inside supervised pipelines — you used it to reduce feature count before feeding data to a classifier or regressor. In this lesson you return to PCA from a purely unsupervised perspective: no labels, no target variable. Here PCA is used for two intrinsically unsupervised tasks — visualisation (projecting high-dimensional data onto 2–3 axes so you can see cluster structure with your eyes) and compression (representing data with fewer numbers while retaining most information). Both tasks are essential companions to the clustering algorithms you learned in Lessons 25–27.

Analogy🏏Cricket
🏏 Think of it like cricket: a full scorecard has 30+ statistics per player — runs, average, strike rate, economy, dot balls, boundary percentage, and on. PCA is like a stats commentator who says: 'Actually, most of the variation boils down to two things — how aggressive an attacker they are and how economical a bowler they are.' These two composite axes (principal components) capture most of the story. Plot every player on those two axes and suddenly the archetypes pop out visually: power hitters cluster top-left, all-rounders cluster centre, economy bowlers cluster bottom-right. Thirty numbers compressed to two, with most of the pattern preserved.

How PCA Works — A Geometric View

PCA finds the directions (principal components) along which the data varies most. The first principal component (PC1) points in the direction of maximum variance in the dataset. The second component (PC2) points in the direction of maximum remaining variance, subject to being perpendicular to PC1. Each subsequent component captures the next highest variance while remaining orthogonal to all previous components. Because real datasets often have correlated features, a few components can capture most of the total variance, letting you safely discard the rest.

Analogy🏏Cricket
🏏 Think of it like cricket: PCA finds the directions along which your players differ the most and lines its axes up with them. Just as a talent scout who first asks 'what single quality separates these cricketers most?' might land on overall match-impact — the axis with the widest spread — PC1 points along the direction of maximum variance. Just as the scout's next question must add fresh information rather than repeat the first, so he picks a quality unrelated to match-impact, PC2 captures the most remaining variance while sitting perpendicular to PC1. Just as each further quality he considers must be at right angles to all the previous ones — genuinely new, not a rehash, every later component captures the next-highest variance while staying orthogonal to those before it. Just as a scout can then describe most of what makes players differ using only his top two or three qualities, PCA lets you keep the leading components and summarise high-dimensional data with far fewer, non-overlapping axes.

Mathematically, PCA computes the eigendecomposition of the covariance matrix (or the singular value decomposition of the data matrix). The eigenvectors are the component directions; the eigenvalues measure how much variance each component explains. Scikit-learn's `PCA` uses SVD internally, which is numerically stable even for wide matrices. You do not need the linear algebra to use PCA effectively — but understanding that components are variance-maximising axes helps you interpret what they represent.

Explained Variance and the Scree Plot

After fitting PCA, `pca.explained_variance_ratio_` gives the fraction of total variance explained by each component. `pca.explained_variance_ratio_.cumsum()` gives the cumulative total. A scree plot (explained variance vs component index) helps you choose how many components to keep: look for the 'elbow' where adding more components gives diminishing returns. A common rule is to keep enough components to explain 90–95% of variance, though the right threshold depends on the application.

Analogy🏏Cricket
🏏 Think of it like cricket: after PCA ranks the qualities that separate players, explained_variance_ratio_ tells you what share of the whole squad's variation each quality accounts for. Just as a scout notes that match-impact explains, say, 60% of how players differ and the next quality another 20%, each component reports its fraction of total variance, and the cumsum tells you the running total captured so far. Just as the scout plots each quality's contribution and watches it tail off — the first few matter enormously, later ones barely move the needle, a scree plot shows variance against component index and reveals the elbow where extra components give diminishing returns. Just as a selector decides to keep enough qualities to explain most of what separates players and drop the rest, you keep enough components to reach a chosen variance target. Reading the scree curve this way tells you exactly how many dimensions to retain without discarding real signal or hoarding noise.
python
import numpy as np
import matplotlib.pyplot as plt
from sklearn.decomposition import PCA
from sklearn.preprocessing import StandardScaler
from sklearn.datasets import load_wine

# Load a real multi-dimensional dataset
data = load_wine()
X, y = data.data, data.target           # 178 samples, 13 features, 3 classes

# Scale first — PCA is variance-based, so scale matters
X_scaled = StandardScaler().fit_transform(X)

# Fit PCA to all components
pca_full = PCA()
pca_full.fit(X_scaled)

# Scree plot
evr = pca_full.explained_variance_ratio_
cum_evr = np.cumsum(evr)

fig, axes = plt.subplots(1, 2, figsize=(12, 4))
axes[0].bar(range(1, len(evr)+1), evr, alpha=0.7)
axes[0].set(xlabel='Component', ylabel='Explained Variance Ratio',
             title='Scree Plot')
axes[1].plot(range(1, len(cum_evr)+1), cum_evr, 'bo-')
axes[1].axhline(0.90, color='red', ls='--', label='90% threshold')
axes[1].set(xlabel='Number of Components', ylabel='Cumulative Explained Variance',
             title='Cumulative Variance')
axes[1].legend()
plt.tight_layout(); plt.show()

n_for_90 = np.argmax(cum_evr >= 0.90) + 1
print(f"Components to explain 90% variance: {n_for_90}")
print(f"Variance explained by first 2 PCs : {cum_evr[1]:.3f}")

2D Visualisation of Cluster Structure

The most common unsupervised use of PCA is projecting high-dimensional data to 2D for a scatter plot. Even if K-Means or DBSCAN labels are available, plotting the first two principal components coloured by cluster assignment lets you visually verify that the algorithm found meaningful structure. If the clusters overlap badly in PCA space, they may not be real — they could be artefacts of the algorithm's assumptions rather than genuine groupings in the data.

Analogy🏏Cricket
🏏 Think of it like cricket: PCA's most popular trick is squashing a player's dozen stats down to two axes so you can plot the whole squad on a single chart and see who groups with whom. Just as a coach sketches every player as a dot on a two-axis board and colours each dot by the role his system assigned — opener, finisher, spinner, projecting the first two principal components and colouring points by K-Means or DBSCAN label lets you eye-check the clustering. Just as clearly separated coloured pockets on the board reassure you the role groupings are real, well-separated clusters in PCA space confirm meaningful structure. But just as colours that smear into one another warn you the role split may be imaginary — an artefact of forcing groups where none exist, badly overlapping clusters in the projection hint they aren't genuine. This quick visual gut-check is what stops you trusting cluster labels that only look tidy in the algorithm's head.
python
import numpy as np
import matplotlib.pyplot as plt
from sklearn.decomposition import PCA
from sklearn.cluster import KMeans
from sklearn.preprocessing import StandardScaler
from sklearn.datasets import load_wine

data = load_wine()
X_scaled = StandardScaler().fit_transform(data.data)

# K-Means clustering (unsupervised — we don't use y)
km = KMeans(n_clusters=3, n_init=10, random_state=42)
cluster_labels = km.fit_predict(X_scaled)

# Project to 2D with PCA for visualisation
pca2d = PCA(n_components=2)
X_2d = pca2d.fit_transform(X_scaled)

fig, axes = plt.subplots(1, 2, figsize=(14, 5))
colours = ['#E63946', '#457B9D', '#2D6A4F']

# Left: K-Means clusters
for c in range(3):
    m = cluster_labels == c
    axes[0].scatter(X_2d[m, 0], X_2d[m, 1], c=colours[c],
                    label=f'Cluster {c}', s=50, alpha=0.8)
axes[0].set(xlabel=f'PC1 ({pca2d.explained_variance_ratio_[0]*100:.1f}%)',
             ylabel=f'PC2 ({pca2d.explained_variance_ratio_[1]*100:.1f}%)',
             title='K-Means Clusters in PCA Space')
axes[0].legend()

# Right: true wine variety (as reference)
for c, name in enumerate(data.target_names):
    m = data.target == c
    axes[1].scatter(X_2d[m, 0], X_2d[m, 1], c=colours[c], label=name, s=50, alpha=0.8)
axes[1].set(xlabel=f'PC1', ylabel=f'PC2', title='True Wine Varieties (Reference)')
axes[1].legend()

plt.tight_layout(); plt.show()
print(f"2 PCs explain {pca2d.explained_variance_ratio_.sum()*100:.1f}% of variance")

PCA for Compression — Reconstruct and Measure Loss

PCA compression works by projecting the data to a lower-dimensional space, then inverting the projection back to the original feature space. The reconstruction is an approximation — the gap between original and reconstructed values is the information lost by discarding the smaller components. This is measured by reconstruction error (mean squared difference). Compression is useful for storage reduction, denoising, and speeding up downstream algorithms. You choose the number of components by balancing reconstruction quality against the compression ratio.

Analogy🏏Cricket
🏏 Think of it like cricket: PCA compression is like summarising each player by only his few most telling qualities, then trying to reconstruct his full stat-line from that summary. Just as you'd project a cricketer onto his top attributes — say match-impact and consistency — throwing away the finer details, PCA projects data onto fewer components. Just as rebuilding the player's complete profile from that short summary gives a good likeness but never the exact original — the fine detail you dropped is simply gone, inverting the projection back to the original space yields an approximation, and the gap is the information lost by discarding the smaller components. Just as you'd gauge how faithful your shorthand is by measuring how far the reconstructed profile drifts from the true one, reconstruction error is the mean squared difference between original and rebuilt values. Just as carrying compact player summaries saves the scout's notebook space at a tolerable loss of detail, PCA shrinks storage while keeping error acceptably small.
python
import numpy as np
from sklearn.decomposition import PCA
from sklearn.preprocessing import StandardScaler
from sklearn.datasets import load_wine

data = load_wine()
X = StandardScaler().fit_transform(data.data)   # shape: (178, 13)

print(f"Original shape: {X.shape}")
print(f"{'Components':>12}  {'Explained Var':>14}  {'Reconst. MSE':>13}  {'Compression':>12}")
print("-" * 58)

for n_comp in [1, 2, 3, 5, 8, 13]:
    pca = PCA(n_components=n_comp)
    X_low  = pca.fit_transform(X)          # (178, n_comp)
    X_reco = pca.inverse_transform(X_low)  # (178, 13)
    mse    = np.mean((X - X_reco) ** 2)
    ratio  = X.shape[1] / n_comp
    var    = pca.explained_variance_ratio_.sum()
    print(f"{n_comp:>12}  {var*100:>13.1f}%  {mse:>13.4f}  {ratio:>10.1f}x")

n_components as a Variance Threshold

Instead of specifying an integer component count, you can pass a float between 0 and 1 to `PCA(n_components=0.95)`. Scikit-learn will automatically select the minimum number of components that explain at least 95% of variance. This is the most robust way to use PCA in production pipelines — the component count adapts to the dataset rather than being hardcoded.

Analogy🏏Cricket
🏏 Think of it like cricket: instead of ordering a scout to describe every player using exactly three qualities, you give him a target — 'capture at least 95% of what makes these cricketers differ, and use as few qualities as that takes.' Just as a shrewd scout then keeps adding qualities only until he's explained 95% of the squad's variation and stops, PCA(n_components=0.95) automatically selects the minimum components explaining that share of variance. Just as this adapts to the group — a uniform squad needs one or two qualities while a wildly varied one needs more, the component count adjusts to each dataset rather than being fixed. Just as hardcoding 'always use three qualities' would over-describe a simple squad and under-describe a complex one, a fixed integer count fits some data and fails other. Setting a variance threshold instead is the robust production move: the pipeline keeps exactly enough information every time, no matter what data flows through, without you hand-tuning the number.
python
from sklearn.decomposition import PCA
from sklearn.preprocessing import StandardScaler
from sklearn.datasets import load_wine
import numpy as np

X = StandardScaler().fit_transform(load_wine().data)

# Auto-select components for 95% variance retention
pca_95 = PCA(n_components=0.95)
X_reduced = pca_95.fit_transform(X)

print(f"Original features  : {X.shape[1]}")
print(f"Reduced components : {pca_95.n_components_}")
print(f"Variance retained  : {pca_95.explained_variance_ratio_.sum()*100:.1f}%")
print(f"Reduced shape      : {X_reduced.shape}")

Link to Course 3 — Supervised vs Unsupervised PCA

In Course 3 (Data Analysis & Feature Engineering), you used PCA inside a supervised pipeline to reduce collinear features before passing them to a regression or classification model. The algorithm was identical but the purpose was different: there you chose components that helped the downstream estimator generalise better, guided by cross-validation scores. Here in unsupervised mode, you choose components purely based on how much variance they retain — there is no target variable to validate against. The key lesson linking both uses: always scale before PCA, always inspect the scree plot, and always embed PCA inside a Pipeline so the same transformation applies consistently to training and future data.

Analogy🏏Cricket
🏏 Think of it like cricket: the same fitness drill serves two different goals depending on who's watching. Just as in Course 3 you ran PCA inside a supervised pipeline — trimming overlapping, collinear player stats before feeding a batter into a score-predicting model, you chose components to help a downstream estimator generalise, guided by cross-validation scores, exactly as a coach keeps only the fitness measures that improve match predictions. Just as here, in unsupervised mode, no scoreboard tells you which qualities matter, so you keep components purely to preserve the squad's overall spread and reveal its natural groupings, the purpose shifts to retaining variance and exposing structure rather than boosting a target metric. Just as the drill's mechanics are identical whether you're prepping for a specific match or simply studying the squad, the PCA algorithm is the same — only the selection criterion changes. Recognising that one tool wears two hats is what lets you apply PCA correctly in either supervised or unsupervised settings.

💡 PCA vs t-SNE vs UMAP: PCA is linear, fast, and invertible — ideal for compression, preprocessing, and when interpretability of components matters. t-SNE and UMAP are non-linear methods better at preserving local cluster structure for visualisation only — they cannot compress/reconstruct data and are much slower. For datasets above ~50 features, run PCA to ~50 components first, then apply t-SNE or UMAP on the PCA output for visualisation.

  • PCA finds orthogonal axes (principal components) of maximum variance — the first few components capture most of the data's information.
  • Always StandardScale before PCA; variance-based decomposition is dominated by high-magnitude features if unscaled.
  • The scree plot (explained variance vs component count) reveals the elbow where adding more components gives diminishing returns.
  • Use PCA 2D projections to visually verify cluster structure found by K-Means, DBSCAN, or agglomerative clustering.
  • Reconstruction via inverse_transform quantifies information loss — choose n_components to balance compression ratio and reconstruction error.
  • Pass a float (e.g. 0.95) to PCA(n_components) to auto-select the minimum components explaining that fraction of variance.
  • Supervised PCA (Course 3) chooses components to help a downstream model; unsupervised PCA chooses components by variance alone.
Lesson 28 of 35
0% complete