The Fourier Matrix#
Week 13 closed with unitary matrices — complex analogues of orthogonal matrices that preserve length via . This week opens with the most important unitary family in signal processing and numerical linear algebra: the Fourier matrix.
Fix an integer and let
be a primitive -th root of unity (so and for ). The Fourier matrix has entries
(using -based indexing). Explicitly, row and column hold the power :
Multiplying a vector by produces the discrete Fourier transform (DFT):
Each frequency bin is the inner product of against a pure complex exponential of frequency . The inverse transform recovers from by conjugation (up to scaling): .
Unitary (up to scaling). The columns of are the discrete complex exponentials
These columns are orthogonal with respect to the complex inner product: when and otherwise. Equivalently,
Scaling by produces a truly unitary matrix with . So itself is unitary up to that standard factor — the complex cousin of an orthogonal change of basis.
Circulant connection. A circulant matrix is constant on every wrap-around diagonal: each row is a right cyclic shift of the row above. Remarkably, every circulant matrix is diagonalized by the same Fourier matrix . The columns of are simultaneous eigenvectors of the entire circulant family. That is why convolutions (which become multiplications after a DFT) and many shift-invariant filters are natural in the Fourier basis.
Tiny example. For , , so
For , and the second column is . Direct matrix–vector multiplication costs arithmetic — fine for , painful for . The next section is about doing the same product much faster.
The Fast Fourier Transform#
A naive product walks every entry of and every component of , which is work. The FFTFast Fourier Transform (Fast Fourier Transform) is a family of algorithms that compute the same DFT in operations when is a power of two (and with similar near-linear cost for highly composite ).
The key is a divide-and-conquer factorization of . Split the input into even and odd indices:
Each of those half-length vectors has a DFT of size . The Cooley–Tukey identity says the full DFT can be assembled from the two half-size DFTs with only extra multiplications by “twiddle factors” :
for (indices of the half-size transforms taken modulo ). In matrix language, factors into a product involving a permutation (even/odd reordering), a block-diagonal matrix with two copies of , and a sparse diagonal of twiddles glued by an “butterfly” step.
Complexity. Let be the cost of an -point FFT. The recurrence is
Unrolling gives — each of levels costs work across the whole tree. Compared with the direct matrix product, that is the difference between “impossible at audio or image scale” and “routine in real time.”
You do not need a full derivation of every butterfly diagram to use the idea: the Fourier matrix is structured; the structure is recursive even/odd splitting; recursion plus combine steps yields . Libraries such as numpy.fft.fft implement carefully optimized variants of this idea (and more general factorizations when is not a power of two).
Principal Component Analysis#
Shift from frequency bases to data geometry. PCAPrincipal Component Analysis (Principal Component Analysis) finds orthonormal directions in feature space along which a dataset varies the most. It is the statistical reading of the SVD from Week 13.
Setup. Collect observations of features into a data matrix , with rows as observations and columns as features. (Images, sensor readings, word counts — any tabular cloud of points works.)
Center the data. Subtract the sample mean of each column so the cloud sits at the origin:
Without centering, the first “component” often just points toward the mean rather than along the spread of the data.
SVD of the centered matrix. Compute
with orthogonal ( or thin), diagonal singular values , and orthogonal (). The principal components are the columns of — the right singular vectors — ordered by decreasing singular value. Column is the direction of greatest variance; is the next, orthogonal to ; and so on.
Why “maximum variance”? For a unit vector , the sample variance of the projected (centered) data is
The matrix is symmetric positive semidefinite. By the spectral theorem (Week 12) and the SVD link , its leading eigenvector is and the maximum of over is . Each subsequent principal component solves the same problem in the orthogonal complement of the previous ones.
Scores. The coordinates of the data in the principal-component basis are the rows of . Keeping only the first columns of projects every observation onto a -dimensional subspace spanned by the top principal components.
Variance and Dimensionality Reduction#
Singular values quantify how much structure each principal component captures. Because
(with ), the fraction of variance explained by principal component is
The cumulative fraction for the first components is . If that number is , the top directions retain 95% of the total (centered) energy of the data.
Low-rank approximation. Truncating the SVD to the top singular values produces
the best rank- approximation of in both Frobenius and spectral norms (Eckart–Young, previewed in Week 13). PCA as dimensionality reduction is exactly this truncation: store the matrix and the scores , and reconstruct approximately when needed.
Practice sketch. Suppose centered 2-D data has singular values and . Then
Ninety percent of the variance lies along PC1. Projecting onto that single axis compresses each point from two numbers to one while losing only 10% of the energy — often an excellent trade for visualization or noise filtering.
In high dimensions the same arithmetic applies: many datasets are approximately low-rank after centering, so a handful of principal components replace hundreds of raw features. The browser lab below runs PCA via np.linalg.svd on a synthetic correlated cloud and prints the explained-variance ratios.
Course Recap#
Fourteen weeks, one throughline: factorizations that turn hard linear problems into easy ones.
- Elimination () — Weeks 2–4. Gaussian elimination factors (with pivots and permutations when needed) so that becomes two triangular solves. The algebra of row operations becomes a product of elementary matrices.
- Orthogonalization () — Weeks 7–8. Gram–Schmidt and Householder build with orthonormal columns in . Least squares stabilizes into solving instead of forming the often-ill-conditioned normal equations alone.
- Eigendecomposition — Weeks 9–12. (and when is symmetric) explains powers , differential systems, quadratic forms, and positive definiteness. Dynamics become independent modes along eigenvectors.
- The SVD — Week 13. works for every matrix, square or not. It unifies and generalizes the spectral picture: singular values replace eigenvalues when symmetry or squareness is missing.
- This week. The Fourier matrix is a structured unitary (up to scale) change of basis that diagonalizes every circulant operator; the FFT makes that change cheap. PCA reads the SVD of centered data as variance-maximizing coordinates — the same and you already know, reinterpreted for statistics and compression.
If you remember only one sentence from the course: choose the right factorization, and the geometry of the problem becomes visible. for systems, for least squares, eigenvalues for dynamics, SVD for almost everything else — including the Fourier and PCA tools that close the loop into applications.
Knowledge check#
The FFT computes the discrete Fourier transform of n points in what time complexity, compared to the O(n²) direct approach?
Browser lab#
Run an FFT on a synthetic signal, then PCA on synthetic 2D data via the SVD.
import numpy as np
import matplotlib.pyplot as plt
# Part 1: FFT
t = np.linspace(0, 1, 256, endpoint=False)
signal = np.sin(2 * np.pi * 5 * t) + 0.5 * np.sin(2 * np.pi * 20 * t)
spectrum = np.fft.fft(signal)
freqs = np.fft.fftfreq(len(t), d=t[1] - t[0])
# Part 2: PCA via SVD
rng = np.random.default_rng(0)
mean = [0, 0]
cov = [[3, 1.5], [1.5, 1]]
data = rng.multivariate_normal(mean, cov, size=200)
data_centered = data - data.mean(axis=0)
U, S, Vt = np.linalg.svd(data_centered, full_matrices=False)
explained_variance_ratio = (S ** 2) / np.sum(S ** 2)
print("explained variance ratio =", explained_variance_ratio)
fig, axes = plt.subplots(1, 2, figsize=(11, 4.5))
axes[0].plot(freqs[freqs >= 0], np.abs(spectrum[freqs >= 0]))
axes[0].set_title("FFT magnitude spectrum")
axes[0].set_xlabel("frequency (Hz)")
axes[1].scatter(data_centered[:, 0], data_centered[:, 1], alpha=0.4, s=10)
for i in range(2):
v = Vt[i] * S[i] / np.sqrt(len(data))
axes[1].plot([0, v[0]], [0, v[1]], linewidth=2,
label=f"PC{i+1} ({explained_variance_ratio[i]*100:.1f}%)")
axes[1].set_aspect("equal")
axes[1].legend()
axes[1].set_title("Principal components")
plt.tight_layout()
plt.show()
Part 1 builds a sum of 5 Hz and 20 Hz sines and plots the magnitude of np.fft.fft against non-negative frequencies — expect clear peaks at those two bins. Part 2 draws a correlated Gaussian cloud, centers it, runs np.linalg.svd, and overlays the principal directions scaled by singular values. The printed explained_variance_ratio should sum to and put most of the mass on PC1, matching the elongated shape of the scatter.
Quiz#
In PCA, the principal components are the columns of ___ in the SVD of the (centered) data matrix.