Skip to content

Singular Value Decomposition

The Singular Value Decomposition (SVD) is often called the fundamental theorem of linear algebra because it works for every matrix — square or rectangular, invertible or not. It factors any matrix into a rotation, a scaling, and another rotation: A=UΣVA = U\Sigma V^\top. This one decomposition powers recommender systems, topic modeling, the pseudo-inverse, image compression, and PCA.

A real-life example: Netflix-style recommendations

Take a big users × movies ratings table (mostly empty). Its SVD uncovers hidden “taste factors” — a right-singular vector might represent “sci-fi lover,” a left-singular vector “stereotypical sci-fi movie,” and the singular value how strong that factor is. Reconstructing the table from the top few factors fills in the blanks — predicting ratings for movies a user hasn’t seen. That’s collaborative filtering, and it’s SVD.

The decomposition

For any ARm×nA \in \mathbb{R}^{m\times n} of rank rr:

A=UΣV,A = U\,\Sigma\,V^\top,

where

  • URm×mU \in \mathbb{R}^{m\times m} is orthogonal; its columns ui\mathbf{u}_i are the left-singular vectors.
  • VRn×nV \in \mathbb{R}^{n\times n} is orthogonal; its columns vj\mathbf{v}_j are the right-singular vectors.
  • ΣRm×n\Sigma \in \mathbb{R}^{m\times n} is “diagonal” with the singular values σ1σ2σr>0\sigma_1 \ge \sigma_2 \ge \dots \ge \sigma_r > 0 on the diagonal and zeros elsewhere.

Because UU and VV are orthogonal (rotations) and Σ\Sigma is a pure scaling, the SVD says every linear map is a rotation, then an axis-aligned stretch, then another rotation.

The three stages, visualized

Apply A=UΣVA = U\Sigma V^\top to the unit circle in three steps. VV^\top rotates it (watch the colored markers turn), Σ\Sigma scales it into an axis-aligned ellipse, and UU rotates the ellipse into its final orientation:

sketch SVD: rotate → scale → rotate p5.js
The unit circle transformed by A = UΣVᵀ in three stages. V^T rotates, Σ stretches into an axis-aligned ellipse, U rotates the ellipse. The colored markers track how points move through each stage.

How it’s built

The SVD is constructed from two eigendecompositions:

  • The right-singular vectors VV are the eigenvectors of the symmetric matrix AAA^\top A.
  • The singular values are σi=λi\sigma_i = \sqrt{\lambda_i}, the square roots of the eigenvalues of AAA^\top A (which are 0\ge 0).
  • The left-singular vectors are ui=1σiAvi\mathbf{u}_i = \frac{1}{\sigma_i}A\mathbf{v}_i (equivalently, eigenvectors of AAAA^\top).

This gives the singular value equation Avi=σiuiA\mathbf{v}_i = \sigma_i\mathbf{u}_i — like the eigenvalue equation, but with different orthonormal bases on each side.

SVD vs. eigendecomposition

diagram Diagram mermaid

The key differences: the SVD always exists and applies to non-square matrices, and its factors are genuine rotations. For a symmetric positive-definite matrix, the two decompositions coincide.

NumPy

svd.py
import numpy as np
 
A = np.array([[1.0, 0.0, 1.0],
              [-2.0, 1.0, 0.0]])          # 2x3, not square
 
U, s, Vt = np.linalg.svd(A)               # s is the vector of singular values
print("singular values:", np.round(s, 4))
print("U orthogonal:", np.allclose(U @ U.T, np.eye(2)))
print("V orthogonal:", np.allclose(Vt @ Vt.T, np.eye(3)))
 
# rebuild A = U Σ Vᵀ  (Σ padded to 2x3)
Sigma = np.zeros((2, 3))
Sigma[:2, :2] = np.diag(s)
print("A = U Σ Vᵀ:", np.allclose(U @ Sigma @ Vt, A))
 
# right-singular vectors are eigenvectors of AᵀA; σ² are its eigenvalues
w = np.linalg.eigvalsh(A.T @ A)
print("σ² ≈ eigenvalues of AᵀA:", np.round(np.sort(w)[::-1][:2], 4), "vs", np.round(s**2, 4))
svd.py
import numpy as np
 
A = np.array([[1.0, 0.0, 1.0],
              [-2.0, 1.0, 0.0]])          # 2x3, not square
 
U, s, Vt = np.linalg.svd(A)               # s is the vector of singular values
print("singular values:", np.round(s, 4))
print("U orthogonal:", np.allclose(U @ U.T, np.eye(2)))
print("V orthogonal:", np.allclose(Vt @ Vt.T, np.eye(3)))
 
# rebuild A = U Σ Vᵀ  (Σ padded to 2x3)
Sigma = np.zeros((2, 3))
Sigma[:2, :2] = np.diag(s)
print("A = U Σ Vᵀ:", np.allclose(U @ Sigma @ Vt, A))
 
# right-singular vectors are eigenvectors of AᵀA; σ² are its eigenvalues
w = np.linalg.eigvalsh(A.T @ A)
print("σ² ≈ eigenvalues of AᵀA:", np.round(np.sort(w)[::-1][:2], 4), "vs", np.round(s**2, 4))
text
singular values: [2.4495 1.4142]
U orthogonal: True
V orthogonal: True
A = U Σ Vᵀ: True
σ² ≈ eigenvalues of AᵀA: [6. 2.] vs [6. 2.]
text
singular values: [2.4495 1.4142]
U orthogonal: True
V orthogonal: True
A = U Σ Vᵀ: True
σ² ≈ eigenvalues of AᵀA: [6. 2.] vs [6. 2.]

Why this matters for ML

  • Recommender systems (collaborative filtering) factor the ratings matrix via SVD to find latent taste factors and predict missing entries.
  • Latent Semantic Analysis / topic models apply SVD to term-document matrices to surface topics.
  • Pseudo-inverse & least squares, PCA, and whitening are all computed most stably through the SVD.

🧪 Try It Yourself

Exercise 1 – Decompose any matrix

Exercise 2 – Reconstruct A = U Σ Vᵀ

Exercise 3 – Singular values vs eigenvalues of AᵀA

Recap

  • The SVD A=UΣVA = U\Sigma V^\top factors any matrix into rotation × scaling × rotation, with orthogonal U,VU, V and non-negative singular values in Σ\Sigma.
  • It always exists (unlike eigendecomposition) and handles non-square matrices.
  • Built from the eigendecompositions of AAA^\top A and AAAA^\top; σi=λi\sigma_i = \sqrt{\lambda_i}.
  • Powers recommenders, LSA, the pseudo-inverse, PCA, and whitening.

Next: keep only the top singular values for the best low-rank fit — Matrix Approximation.

If this helped you, consider buying me a coffee ☕

Buy me a coffee

Was this page helpful?

Let us know how we did