Machine Learning · Graph Theory
📅 July 2026 ⏱ ≈ 13 min read 🎯 Advanced · Last updated: 9 July 2026

Spectral clustering: how eigenvectors of the graph Laplacian reveal cluster structure

K-means fails the moment your clusters aren't round blobs — two interlocking crescents, concentric rings, or a spiral all defeat it. Spectral clustering sidesteps the problem entirely: it never looks at raw coordinates, only at a similarity graph, and it finds clusters by examining the eigenvectors of that graph's Laplacian matrix (a matrix derived from the graph's connections that encodes how smoothly values can vary across it).

TL;DR: Instead of measuring straight-line distance, spectral clustering builds a similarity graph between points, then studies the eigenvectors of that graph's Laplacian matrix. The second-smallest eigenvector (the Fiedler vector) reveals the graph's natural split; using the first k eigenvectors as coordinates and running k-means on them recovers non-convex clusters — crescents, rings, spirals — that ordinary k-means cannot.

From points to a similarity graph

Spectral clustering starts by throwing away Euclidean distance as the primary signal and building a similarity graph instead: a weighted graph where an edge weight wij measures how "close" points i and j are. The most common choice is a Gaussian (RBF) kernel restricted to a neighbourhood:

w_ij = exp(−‖x_i − x_j‖² / 2σ²)   if j ∈ kNN(i), else 0
σ controls locality; kNN keeps the graph sparse and local

The key idea: two points can be "close" in graph terms — connected through a chain of nearby neighbours — even if they're far apart in straight-line distance. That's exactly what lets spectral clustering trace a crescent or a spiral as a single connected region.

The graph Laplacian

Given the weighted adjacency matrix W and the diagonal degree matrix D (Dii = Σⱼ wij), the unnormalized graph Laplacian is:

L = D − W
Symmetric, positive semi-definite: xᵀLx = ½ Σᵢⱼ wᵢⱼ(xᵢ − xⱼ)² ≥ 0

That quadratic form is the whole story: xᵀLx is small exactly when strongly-connected points i, j are assigned similar values xᵢ, xⱼ. Minimizing it is a smoothness constraint over the graph — and its minimizers are the low eigenvectors of L. In practice the normalized Laplacian is preferred, since it corrects for wildly different node degrees:

L_sym = D^(−1/2) L D^(−1/2) = I − D^(−1/2) W D^(−1/2)
L_rw = D⁻¹ L = I − D⁻¹W   (random-walk normalized form)

The Fiedler vector and graph cuts

L is positive semi-definite, so all its eigenvalues are ≥ 0, and the smallest one is always 0 with eigenvector 1 (constant) — for a connected graph, exactly one zero eigenvalue. The second-smallest eigenvalue λ₂ and its eigenvector, the Fiedler vector, encode the graph's best "bisection": points with a positive entry in the Fiedler vector form one side of a low-weight cut, negative entries form the other.

EigenvalueMeaning
λ₁ = 0Whole graph is one component (if connected)
λ₂ (Fiedler)Algebraic connectivity — how easy the graph is to split in two
λ₂ ≈ 0Graph is nearly disconnected — two natural clusters
λ₂, …, λ_k smallk natural clusters (small eigengap after λ_k)

Normalized cut and the relaxation trick

Formally, we'd like to partition the graph into k groups minimizing the total edge weight cut between groups, normalized by group size so the optimizer can't just isolate a single outlier node (Ncut, Shi & Malik, 2000). Solving this exactly is NP-hard — it's a discrete combinatorial problem. The trick is to relax the discrete ±1 cluster-membership constraint into continuous real values, which turns Ncut minimization into:

minimize xᵀLx / xᵀDx   subject to xᵀD1 = 0
This is a generalized eigenvalue problem: Lx = λDx

The relaxed solution is exactly the eigenvectors of the generalized eigenproblem Lx = λDx (equivalently, the eigenvectors of L_rw). Rounding the continuous eigenvector solution back to discrete cluster labels — usually with plain k-means in the eigenvector space — recovers an approximate but usually excellent Ncut partition.

The algorithm in JavaScript

Putting it together: build the similarity graph, compute the first k eigenvectors of the normalized Laplacian, stack them as columns to get an n×k embedding, then run k-means on the rows of that embedding.

function spectralClustering(points, k, sigma = 1.0, kNN = 10) {
  const n = points.length;
  const W = buildKnnSimilarityGraph(points, kNN, sigma); // n×n sparse weights
  const D = W.map(row => row.reduce((a, b) => a + b, 0));

  // Symmetric normalized Laplacian: L_sym = I - D^-1/2 W D^-1/2
  const Lsym = identity(n).map((row, i) =>
    row.map((_, j) => (i === j ? 1 : 0) − W[i][j] / Math.sqrt(D[i] * D[j]))
  );

  // Smallest k eigenvectors (excluding the trivial constant one)
  const { eigenvectors } = symmetricEigenDecomposition(Lsym);
  const embedding = eigenvectors.slice(0, k); // k smallest, columns

  // Row-normalize (Ng-Jordan-Weiss trick) then cluster with k-means
  const rows = transposeAndNormalizeRows(embedding, n, k);
  return kMeans(rows, k);
}
Row normalization matters: Ng, Jordan & Weiss (2002) showed that normalizing each embedded point to unit length before k-means makes clusters much more compact in eigenvector space — points that "should" be together end up nearly identical rows, which is exactly what k-means needs.

Choosing k: the eigengap heuristic

Unlike k-means, spectral clustering gives you a principled way to pick k without a separate silhouette sweep: plot the sorted eigenvalues λ₁ ≤ λ₂ ≤ … and look for the largest jump (eigengap) — |λk+1 − λk|. A large gap after λ_k suggests k well-separated clusters, because k eigenvalues are clustered near zero and the rest jump away sharply.

Caveat: the eigengap heuristic can be ambiguous on noisy or hierarchically-structured data (clusters within clusters). It's a strong heuristic, not a proof — always sanity check the resulting partition visually when possible.

Where spectral clustering wins

Spectral clustering's real strength is that it makes almost no assumption about cluster shape — only about graph connectivity — which is precisely where centroid-based methods like k-means break down.

▶ Live Demo

🧩 Explore clustering live

Watch centroid-based clustering converge, then compare it against non-convex shapes where spectral methods win

Open simulation →

🔗 Related Simulations

🧩K-Means Clustering 🕸️Force-Directed Graph 🌐Neural Gas 🎲Random Graph