How many components keep the variance

Medium12 min12 hidden tests

A search team compresses product features with PCA before it builds an index, and the rule is to keep just enough components to explain a target share of the variance, such as 90 percent. Write components_for_variance(X, target) that returns the smallest number of principal components whose variances add up to at least target of the total.

Move the target

keep the fewest components that reach it
KeptDroppedRunning total

Shares, largest first: 0.45, 0.2, 0.2, 0.05, 0.05, 0.05. Running total: 0.45, 0.65, 0.85, 0.9, 0.95, 1. It first reaches 0.90 at component 4, so keep 4.

Keep 4 components.

Examples

Variance shares 0.45, 0.2, 0.2, 0.05, 0.05 and 0.05

components_for_variance(np.vstack([np.diag([3.0, 2.0, 2.0, 1.0, 1.0, 1.0]), -np.diag([3.0, 2.0, 2.0, 1.0, 1.0, 1.0])]), 0.9)

returns 4

One component already explains about 69 percent

components_for_variance([[2.0, 0.0], [0.0, 1.0], [4.0, 3.0], [6.0, 2.0], [3.0, 5.0]], 0.6)

returns 1

Requirements

  • X is a 2-D list or array of shape (n, d) with n >= 2, and target is a float with 0 < target <= 1.
  • Center each column first. The component variances are the eigenvalues of the covariance matrix, or equally the squared singular values of the centered data. Sort them from largest to smallest.
  • Return the smallest int m such that the m largest variances divided by the total reach target. Count a share as reaching it when it is at least target - 1e-9, so float rounding cannot miss an exact target such as 1.0.
  • If the total variance is 0 (every column is constant), return 0.
The idea behind it

Each principal component carries part of the data's variance, and the parts add up to the total variance of the centered data. The explained variance ratio of a component is its share of that total. Sorted from largest to smallest, the running sum of those ratios says how much of the spread the first m components keep. A common rule is to keep the smallest m that reaches a target such as 90 or 95 percent. It sets the size of a compressed feature vector, an index or a plot without guessing. The variances come from the eigenvalues of the covariance matrix. They also come from the singular values s of the centered data, as s^2 / (n - 1). The scaling cancels in the ratio. Floating-point sums can land a hair below an exact target, so code that compares against a target such as 1.0 needs a small tolerance.

pythonCtrl+Enter runs
import numpy as np

def components_for_variance(X, target):
"""Smallest number of principal components that explain target.

X: 2-D list or array, shape (n, d), n >= 2
target: float in (0, 1], the share of total variance to keep
Center the columns, sort the component variances from largest to
smallest, and return the smallest m whose cumulative share is at least
target - 1e-9. Returns 0 when the total variance is 0.
"""
raise NotImplementedError

Stuck? Reveal one rung at a time

Worked solution

Pro includes the solution and walkthrough for every problem, plus the hands-on labs. The first problem of each topic is free.