Part of Language AI Handbook
Explains how Singular Value Decomposition compresses sparse co-occurrence matrices into dense word embeddings through Latent Semantic Analysis.
Choose your expertise level to adjust how many terms are explained. Beginners see more tooltips, experts see fewer to maintain reading flow. Hover over underlined terms for instant definitions.
Article links
Make inline references clickable
Singular Value Decomposition
Co-occurrence matrices and PPMI weighting, as we explored in the previous chapters, give us a way to represent words as high-dimensional vectors where each dimension corresponds to a context word. A word like "bank" might live in a space with tens of thousands of dimensions. These representations capture real associations, but they come with a serious problem: they are enormous and sparse, with substantial noise. Most entries are zero, and the non-zero entries carry substantial statistical noise from the finite size of any real corpus. The question is whether we can do better, whether there is a principled way to compress these unwieldy representations into a compact, dense representation that retains useful information.
Singular Value Decomposition (SVD) is the answer. It is a linear algebra technique that takes a large, sparse matrix and compresses it into a compact set of dense vectors that capture the most important structure while discarding noise. When applied to word-context matrices, this compression produces what are known as Latent Semantic Analysis (LSA) embeddings, an early but remarkably effective form of word embeddings that predates neural approaches by decades. Understanding SVD deeply is worth the effort not just for historical reasons. The mathematical ideas behind SVD, optimal low-rank approximation, orthogonal bases, and the spectral decomposition of data, reappear throughout modern machine learning in forms as varied as principal component analysis, matrix factorization for recommender systems, and even the theoretical analysis of what neural language models are implicitly learning.
The intuition behind SVD is that language has hidden structure. If "dog" and "cat" both appear frequently near "pet," "feed," and "veterinarian," those words are telling us something similar about both animals. But the raw co-occurrence matrix does not know this: it just sees two different rows with different column patterns. SVD discovers these latent patterns by finding directions in the high-dimensional space along which the data varies most strongly. Each direction captures a coherent theme or topic, and projecting words onto the most important directions gives dense, low-dimensional vectors that encode meaning through shared statistical patterns. The dimensions produced by SVD are not labeled with human-interpretable names. They are abstract algebraic constructs, but they encode real semantic relationships that emerge directly from distributional statistics.
This chapter builds up SVD from first principles: why matrix factorization works, what the singular values mean geometrically, how truncation produces optimal embeddings, and how the full pipeline from raw text to cosine similarities operates in practice. We then examine the practical algorithms needed to make SVD feasible at vocabulary scale, and close with an honest assessment of where LSA succeeds and where later approaches were forced to go beyond it.
Mathematical Formulation
To understand SVD, it helps to start with a simpler case you may already know: eigendecomposition. For a square symmetric matrix , eigendecomposition gives us , where is an orthogonal matrix of eigenvectors and is diagonal with eigenvalues. This works beautifully when is square and symmetric, but our word-context matrix is rectangular: it has one row per word in the vocabulary and one column per context word, and those two sets need not have the same size.
SVD is the generalization of eigendecomposition to rectangular matrices. For any matrix of dimensions , SVD produces an exact decomposition:
where:
- is an orthogonal matrix whose columns are the left singular vectors
- is an diagonal matrix containing the singular values on the diagonal, where
- is the transpose of an orthogonal matrix whose columns are the right singular vectors
The singular values measure how much variance each corresponding direction explains. A large means the -th pair of left and right singular vectors captures a strong, consistent pattern in the data. A small corresponds to a weak pattern that may be statistical noise arising from the finite sample of text.
For a word-context matrix where rows represent vocabulary words and columns represent context words:
- The left singular vectors define a coordinate system in word space: each column of is a direction in the space of vocabulary words
- The right singular vectors define a coordinate system in context space: each column of is a direction in the space of context words
- The singular values tell you how important each coordinate axis is in explaining the data
The entire matrix can be reconstructed exactly from the full SVD. The SVD says: can be written as a sum of rank-1 matrices, each formed by the outer product of one left singular vector and one right singular vector, weighted by the corresponding singular value:
where is the -th column of and is the -th column of . Each term is a rank-1 matrix describing one coherent pattern: it says "the set of words characterized by tend to co-occur with the set of contexts characterized by , and this tendency has strength ." The full matrix is the superposition of all these patterns. The real power comes from the truncated version, where we keep only the largest-magnitude terms.
Why Orthogonality Matters
The orthogonality constraints on and are a technical constraint with direct consequences for the quality of the embeddings.
Orthogonality means the columns of form an orthonormal basis: , and similarly . In practical terms, this means each SVD dimension is completely uncorrelated with every other. In a raw co-occurrence matrix, the dimensions (context words) are highly correlated: "cat" and "kitten" often appear in the same contexts, so their corresponding dimensions carry redundant information. Any vector in the raw PPMI space is tangled up with this redundancy. SVD finds a new basis where this redundancy has been removed.
The first SVD dimension captures the single most important source of variation in the data. The second dimension captures the most important variation that remains after removing the first. The third captures what remains after removing the first two, and so on. This greedy structure, where each dimension is chosen to be maximally informative given the previous ones while remaining orthogonal to all of them, is exactly what makes the truncated SVD an optimal low-rank approximation. You cannot do better with the same number of dimensions, given the orthogonality constraint.
A useful geometric picture: the SVD is finding the principal axes of an ellipsoid. If you imagine the rows of as points in -dimensional space, they form some cloud with an elongated shape. The first left singular vector points along the longest axis of this ellipsoid, the direction of maximum spread. The second points along the next longest axis, perpendicular to the first. SVD is essentially fitting an ellipsoid to the data and reading off its axes.
Connection to Matrix Products
There is a clean algebraic relationship between SVD and the eigendecomposition of the symmetric matrices and . Multiplying out the SVD factorization:
Since is orthogonal, , so the middle terms collapse. This shows that the columns of are exactly the eigenvectors of the matrix , and the squared singular values are the corresponding eigenvalues. Similarly, the columns of are the eigenvectors of the matrix .
In NLP terms, is the word-by-word similarity matrix: entry is the dot product of the PPMI profiles of words and , measuring how similar their co-occurrence patterns are. The eigenvectors of this matrix are the directions that best explain word-to-word similarity. The left singular vectors of are precisely these eigenvectors, which is why SVD gives you meaningful word embeddings.
Truncated SVD for Dimensionality Reduction
The key insight of Latent Semantic Analysis is that most of the informative structure in a word-context matrix lives in the top few hundred singular values. The rest is statistical noise arising from the finite, imperfect sample of text. By keeping only the largest singular values and their corresponding vectors, we obtain a rank- approximation:
where:
- is the matrix formed from the first columns of (the most important left singular vectors)
- is the diagonal matrix containing the largest singular values
- is the matrix formed from the first rows of (the most important right singular vectors)
This approximation is the closest rank- matrix to under the Frobenius norm. The Frobenius norm of a matrix is the square root of the sum of all squared entries:
No other rank- matrix provides a better approximation under this metric. This result, known as the Eckart-Young-Mirsky theorem, gives the truncated SVD a rigorous optimality guarantee. You are not just compressing the data: you are computing the mathematically optimal compression at any given target rank . The approximation error is:
This says the squared error of the rank- approximation equals the sum of squared singular values that were dropped. If the singular values decay rapidly, the error from truncation is small even for modest .
The word embeddings in LSA are the rows of : each word gets a -dimensional vector. You can also use just (the rows of the left singular matrix without scaling by singular values), but is more common because it preserves the relative importance of each dimension. A dimension with a large singular value should contribute more to the distance between embeddings than a dimension with a small one.
The Eckart-Young Theorem in Detail
The Eckart-Young-Mirsky theorem is worth pausing on, because it explains why truncated SVD is so natural for NLP. Consider the noise model for a co-occurrence matrix: we believe the true signal is a low-rank structure (a few dominant semantic themes), overlaid with high-rank noise from sampling variability, rare co-occurrences, and corpus-specific quirks. The theorem says that the best way to recover the signal, in a least-squares sense, is to keep only the top singular vectors and values. There is no other rank- matrix that comes closer to the observed data. This means truncated SVD is simultaneously a compression algorithm and a denoising algorithm. It removes the noisy high-rank components and retains the structured low-rank signal.
This is precisely analogous to smoothing a noisy signal by keeping only its low-frequency Fourier components. In Fourier analysis, the important structure is in the low frequencies and noise is in the high frequencies. In SVD analysis of co-occurrence matrices, the important structure is in the top singular values and noise is in the bottom ones. The analogy is not just metaphorical: both operations minimize mean squared error under their respective optimality criteria.
The Low-Rank Structure of Language
Why does the approximation work so well for language? Because human vocabulary is not independent. A text about biology uses many words together: "cell," "protein," "DNA," "gene," "enzyme." A text about finance uses a different cluster: "equity," "bond," "interest," "dividend," "portfolio." These thematic co-occurrences create low-rank structure in the word-context matrix: the vast majority of variation can be explained by a relatively small number of underlying semantic dimensions.
Consider what "low rank" means concretely. A rank- matrix can be written as the sum of outer products. For language, this means the entire co-occurrence behavior of the vocabulary can be approximated as a superposition of independent patterns. Pattern 1 might capture "biology words co-occurring with biology contexts." Pattern 2 might capture "finance words co-occurring with finance contexts." Pattern 3 might capture "sports words co-occurring with sports contexts." The actual patterns are more abstract and intertwined than this, but the point is that a relatively small number of them suffices to explain most of the variance.
For a vocabulary of 100,000 words, the raw PPMI matrix has 10 billion entries. But if the true rank is 300, then it can be described by , which is just 60 million numbers: a compression ratio of 167:1. The fact that this compressed description is also semantically meaningful is not a coincidence: it is because meaningful semantic categories are precisely the kind of coherent, repeating patterns that SVD is designed to discover.
SVD discovers these latent patterns automatically, without any supervision. Dimension 1 might correspond roughly to "living things vs. inanimate objects." Dimension 2 might separate "technical vs. everyday language." Dimension 3 might track "formal vs. informal register." These dimensions are not cleanly interpretable in the way a topic model produces explicit word lists, but they capture real semantic structure measurable in downstream tasks.
Latent Semantic Analysis
LSA, introduced by Deerwester, Dumais, Furnas, Landauer, and Harshman in their landmark 1990 paper "Indexing by latent semantic analysis," applies truncated SVD to term-document or term-term co-occurrence matrices to obtain word representations. The paper proposed LSA primarily as a method for document retrieval, but its implications for semantic representation quickly became clear.
LSA is the application of truncated SVD to a term-document or term-context matrix to derive low-dimensional word representations. The resulting vectors encode semantic similarity based on shared distributional patterns across the corpus.
The name "latent semantic" captures the core idea: the dimensions discovered by SVD correspond to underlying (latent) semantic themes that are not visible in the raw counts. The original LSA paper demonstrated something remarkable: after SVD compression, words that never appear in the same document can still have high cosine similarity in the compressed space, if they tend to appear in documents covering similar topics. This is latent semantics: meaning inferred from indirect co-occurrence patterns, not direct co-occurrence.
For example, "physician" and "doctor" rarely appear in the same sentence. In a raw co-occurrence matrix, their co-occurrence count might be close to zero. But both frequently appear in texts about hospitals, patients, treatments, and medical care. SVD discovers that these words belong to the same semantic neighborhood by noticing that they appear with similar context words across the corpus. The shared context lifts them into the same neighborhood in the latent space, even though they were never direct co-occurrences.
The original LSA evaluation was striking. On synonym selection tests from the Test of English as a Foreign Language (TOEFL), an LSA system trained on a large text corpus achieved accuracy comparable to college-bound non-native English speakers, and substantially above chance. This was achieved without any explicit synonym dictionaries or semantic rules, purely from distributional patterns in raw text. It was early evidence that statistical structure in large corpora encodes something meaningful about semantic relationships.
Term-Document vs. Term-Term Matrices
LSA can be applied to either of two matrix types, and the choice matters for what kind of similarity the resulting embeddings capture.
Term-document matrices have rows for terms and columns for documents. Entry records how often term appears in document , typically with TF-IDF weighting to reduce the dominance of common words. SVD on this matrix discovers patterns of which terms tend to appear together in the same documents. Two words will be similar if they tend to appear in the same kinds of documents, even if they rarely appear in the same sentence. This makes term-document LSA natural for topical similarity: "automobile" and "vehicle" are similar because they both appear in transportation articles.
Term-term co-occurrence matrices (also called word-word matrices) have rows and columns both representing vocabulary words, with entries recording how often the row word appears within a context window of the column word. The window might be 2 words to the left and right, or 5 words, or an entire document. SVD on this matrix discovers patterns of which words appear in similar local contexts. Two words will be similar if they are interchangeable in sentences, not just in documents.
Both approaches produce useful word embeddings, but they capture different aspects of similarity. Term-document matrices tend to capture topical or associative similarity: "surgeon" and "hospital" are similar because they appear in medical documents. Term-term matrices capture paradigmatic or substitutional similarity: "surgeon" and "physician" are similar because they can substitute for each other in sentences ("the surgeon/physician examined the patient"). For most NLP applications, paradigmatic similarity is more useful, which is why term-term matrices have become the standard for distributional word embeddings.
The window size in term-term matrices also matters. Narrow windows (1-2 words) capture syntactic similarity: words that fill the same grammatical role. Wide windows (5-10 words or entire documents) blend into topical similarity. This is because nearby words are constrained by local syntax, while distant words are constrained by document topic. The transition from narrow to wide windows interpolates between syntactic and topical similarity, and the right choice depends on the downstream task.
The Distributional Hypothesis Revisited
LSA is grounded in the distributional hypothesis, which holds that words with similar meanings tend to appear in similar contexts. We discussed this hypothesis in the chapter on distributional semantics, and LSA operationalizes it with mathematical precision. The PPMI matrix measures how much each word-context pair co-occurs beyond chance. SVD then finds the directions in this space along which co-occurrence patterns are most coherent and persistent.
What makes LSA's formulation powerful is that it goes beyond pairwise co-occurrence. Two words can be similar in the LSA space even if their direct co-occurrence count is zero, as long as they share indirect neighbors. If "cat" often appears near "pet" and "food," and "dog" often appears near "pet" and "food," then SVD places them near each other because they project strongly onto the same first few left singular vectors. The singular vectors aggregate co-occurrence signals across the entire vocabulary, finding the directions that simultaneously explain many words at once.
Choosing Embedding Dimensions
The most important hyperparameter in LSA is , the number of singular values to retain. The tradeoff is fundamental: too few dimensions and the representation cannot capture enough nuance in the vocabulary; too many and you retain noise rather than signal. Getting right matters more than almost any other architectural choice in the LSA pipeline.
The Singular Value Decay Curve
The primary diagnostic for choosing is a plot of the singular values in decreasing order, called a scree plot (the term comes from geology: "scree" is the debris that accumulates at the base of a cliff). The scree plot for a typical NLP co-occurrence matrix shows:
- A rapid initial decline through the first handful of dimensions, representing the dominant semantic themes
- A knee or elbow where the rate of decline slows substantially
- A long, gradually declining or flat tail representing noise and idiosyncratic patterns
The optimal is often near the elbow. Values beyond the elbow add little signal and increasingly mix noise into the representations. For tasks where you want distinct separation of major topics, choosing at or before the elbow is conservative and effective. For tasks where finer distinctions matter, you may benefit from going beyond the elbow.
In practice, the scree plot provides a floor on (include all components up to the elbow) but does not give a sharp ceiling. The right answer is usually obtained by evaluating downstream task performance across a range of values, which leads to the empirical approach described below.
Empirical Guidance
Choosing by evaluating downstream task performance is the most reliable approach. Researchers have found consistent patterns across many experiments with NLP co-occurrence matrices:
- Small vocabularies and small corpora benefit from small (50-100), because there are fewer distinct semantic dimensions to capture and the matrix is not large enough to support reliable estimation of many components
- Large vocabularies with rich, diverse corpora can benefit from larger (300-500), especially when the target application requires distinguishing fine-grained semantic categories
- The original LSA paper found 100-300 dimensions worked well for document similarity and word analogy tasks
- Performance is often stable across a range of values, with a broad plateau rather than a sharp peak; a factor of 2 change in rarely produces dramatic differences
The key insight is that controls the bias-variance tradeoff. Small gives high bias (the embedding cannot distinguish closely related words or subtle semantic contrasts) but low variance (the representation is not affected by corpus-specific noise or sampling fluctuations). Large gives low bias but high variance (noise in the corpus leaks into the embedding dimensions). The optimal balances these two sources of error, and that balance point depends on the corpus size and the downstream task.
For practical recommendation: start with as a baseline, evaluate on your target task, and try and to understand the sensitivity. If your corpus is small (fewer than 1 million tokens), prefer smaller . If your corpus is large and your task requires fine-grained distinctions, larger is worth testing.
Explained Variance as a Guide
An alternative to the scree plot is to look at cumulative explained variance: what fraction of the total variance (sum of squared singular values) is captured by the first components? Common thresholds are 80-90% explained variance. In practice, the number of components needed to explain 80% of variance in a large NLP matrix can be surprisingly large, because language has many semantic dimensions. The cumulative variance curve often rises steeply at first and then flattens gradually, without a clean elbow. Using explained variance thresholds can push too high in large, diverse corpora.
Both the scree plot and cumulative variance are useful diagnostics, but neither should override direct measurement on your downstream task. The relationship between intrinsic dimensionality estimates and extrinsic task performance is not always predictable.
SVD Computational Complexity
Computing the full SVD of an matrix takes time. For a vocabulary of words, a word-word co-occurrence matrix is , making the full SVD in time. A vocabulary of 100,000 words would require on the order of operations: completely infeasible with any current hardware.
The memory requirement for storing the full dense co-occurrence matrix is entries. At 100,000 words and 4 bytes per float, that is already 40 gigabytes. Larger vocabularies (500,000 words, as in some production systems) would require 1 terabyte just to store the matrix in dense form. These numbers make clear that full SVD on large NLP matrices is not just slow: it is impossible without specialized techniques.
Several strategies address this, and understanding them clarifies why LSA became computationally practical:
Sparse matrix storage: Co-occurrence matrices are extremely sparse. Even with a window of 5 words, most word pairs never co-occur in any reasonable corpus. The fraction of nonzero entries in a PPMI matrix for a 100,000-word vocabulary on a billion-word corpus is typically well below 1%. Sparse formats like compressed sparse row (CSR) store only the nonzero entries, reducing memory by 100x or more compared to dense storage.
Truncated SVD via Lanczos iteration: When you only need the top singular vectors rather than all of them, specialized algorithms exploit the structure of the problem. The Lanczos algorithm builds a sequence of orthogonal vectors that progressively refine estimates of the top singular vectors. Starting from a random vector, it applies the matrix repeatedly and uses Gram-Schmidt orthogonalization to build a Krylov subspace, a subspace that converges rapidly to the dominant singular directions. The algorithm requires only matrix-vector products with and , which can be done efficiently for sparse matrices without ever constructing a dense representation. The computational cost is roughly , where nnz is the number of nonzero entries.
Vocabulary truncation: Only retaining the top most frequent words dramatically reduces the matrix size. Words that appear very rarely (fewer than 5-10 times in the corpus) contribute mostly noise to the SVD and can safely be excluded. Keeping the top 30,000-50,000 vocabulary items is common in practice, which reduces the matrix from to entries, a reduction of 4-16x relative to a 100,000-word vocabulary.
PPMI matrix factorization via co-occurrence streaming: Rather than forming the full dense PPMI matrix and then applying SVD, some implementations stream through the corpus to accumulate only the co-occurrences needed, building the sparse PPMI matrix incrementally without ever materializing it fully in memory.
Randomized SVD for Scale
Even with sparse algorithms, exact SVD becomes slow for matrices with millions of rows or columns. Modern production NLP systems may want to compute embeddings for vocabularies of 500,000 to 1 million words. Randomized SVD, introduced by Halko, Martinsson, and Tropp in their influential 2011 paper "Finding structure with randomness," provides a principled approximation that dramatically reduces computation while maintaining high accuracy.
Randomized SVD approximates the top- singular vectors of a matrix by first projecting it onto a random low-dimensional subspace, then applying standard SVD to the smaller projected matrix. The result is nearly as accurate as exact SVD but much faster to compute, especially when is small relative to the matrix dimensions.
The algorithm works in two stages that together are much cheaper than direct SVD.
Stage 1: Range finding. The goal of this stage is to find a small orthonormal matrix whose columns approximately span the range (column space) of , restricted to the dominant directions. Generate a random matrix of shape , where is a small oversampling parameter, typically 5 to 10. The oversampling provides insurance that the random projection does not miss any important directions. Form the sample matrix:
Compute an orthonormal basis for the column space of using QR decomposition. The key insight is that multiplying by a random matrix produces a "sketch" of the column space of . If has dominant singular directions with much larger singular values than the rest, then will be approximately a linear combination of those directions plus small random perturbations. QR decomposition extracts an orthonormal basis for this sketch.
Stage 2: SVD of the projected matrix. Form the smaller matrix:
has dimensions . Rather than being enormous, is small in its first dimension: only rows. Compute the exact SVD of :
Recover the approximate left singular vectors as .
The computational saving is substantial. The expensive operations in the randomized algorithm are the matrix-vector products in forming and , each costing for a sparse matrix. The full SVD of costs , which is small when . Compared to exact SVD at , the asymptotic cost is similar, but the constant factors are much smaller because the algorithm avoids the iterative Lanczos refinement. For very large matrices, the difference is an order of magnitude in wall time.
The theoretical guarantee is that the error of randomized SVD is, with high probability, only slightly larger than the error of the best rank- approximation. Specifically:
where the expectation is over the random choice of and is the -th singular value. When is even modestly large (say, ) and the singular values decay rapidly (as they do in NLP matrices), the bound is tight and the approximation is excellent.
An optional but often used power iteration step can further improve accuracy: instead of computing , compute for small (typically 1 or 2). Each power iteration squares the singular values, making the dominant ones even more prominent relative to the small ones and producing a better sketch of the dominant subspace. The cost is additional matrix-vector products.
Scikit-learn's TruncatedSVD uses randomized SVD internally for large matrices, making it the practical tool of choice for LSA at scale. The algorithm='randomized' option (the default) invokes this randomized approach.
Interpreting SVD Dimensions
One of the persistent challenges with SVD-based embeddings is that the resulting dimensions are not directly interpretable. Unlike topic models such as Latent Dirichlet Allocation, which produce explicit probability distributions over words for each topic, SVD dimensions are abstract linear combinations of all the original features. A dimension is defined by its loading vector: the left singular vector , which assigns a real-valued weight to every word in the vocabulary. Positive weights indicate words that are "on one side" of the dimension; negative weights indicate words on the other side.
Despite this abstractness, considerable structure is recoverable through careful inspection. For each SVD dimension, you can rank the vocabulary words by their loading in the corresponding left singular vector: the words with the highest positive loadings tell you what the dimension is "about" in the positive direction, and the words with the highest negative loadings tell you what it captures in the negative direction. A dimension might show "music, melody, harmony, song, rhythm" on one pole and "mathematics, equation, proof, theorem, algebra" on the other, suggesting it captures a technical-versus-aesthetic contrast. Another dimension might show "happy, joyful, delighted, cheerful" on one pole and "sad, gloomy, miserable, depressed" on the other, capturing an emotional valence axis.
The first dimension often captures something close to word frequency, because the most frequent words co-occur with almost everything and therefore dominate the first principal direction. This is a well-known artifact of SVD applied to count matrices. Removing or downweighting the first few dimensions can sometimes improve downstream task performance by exposing more detailed semantic structure that would otherwise be obscured by the frequency signal.
SVD dimensions are also sensitive to corpus domain. The same vocabulary represented with LSA on scientific articles will produce very different embeddings than LSA on news articles or literary fiction, because the co-occurrence statistics differ substantially across these domains. This domain sensitivity is both a limitation and a useful property. As a limitation, it means LSA embeddings do not transfer cleanly across domains: embeddings trained on medical texts may poorly represent the everyday senses of medical terms as they appear in general text. As a feature, it means embeddings can be specialized to a domain by choosing the training corpus carefully. A medical NLP system benefits from training its LSA on clinical notes, and a legal NLP system benefits from training on court documents.
Understanding which dimensions correspond to which semantic properties is a useful research exercise but not necessary for practical use. The embeddings can be used directly for cosine similarity computation, nearest-neighbor retrieval, and downstream task inputs without any interpretation of individual dimensions.
The Relationship Between Dimensions and Topics
It is tempting to equate SVD dimensions with "topics," but the relationship is more complex. SVD dimensions are not topics in the sense of coherent themes with interpretable word distributions. They are mathematical abstractions that together span the semantic space of the corpus. Any individual word is represented as a weighted combination of all dimensions simultaneously. A word like "python" might have a large loading on a "programming languages" dimension, a smaller loading on a "biology/animals" dimension, and moderate loadings on several other dimensions.
The critical difference from topic models is that SVD dimensions can have negative loadings. In topic models, every word has a non-negative probability for every topic. In SVD, words can be "opposite" to a dimension: a word with a strongly negative loading on a dimension contrasts with words that have strongly positive loadings. This signed structure allows SVD to represent opposing semantic categories in a way that standard topic models cannot.
Worked Example
Let us trace through a small LSA example to build concrete intuition. Consider a toy PPMI matrix for six words ("cat," "dog," "python," "java," "bank," "river") against four context words ("pet," "code," "money," "water"). A plausible set of PPMI values might look like this:
| pet | code | money | water | |
|---|---|---|---|---|
| cat | 2.1 | 0.0 | 0.0 | 0.0 |
| dog | 1.9 | 0.0 | 0.0 | 0.0 |
| python | 0.0 | 2.3 | 0.0 | 0.0 |
| java | 0.0 | 2.1 | 0.0 | 0.0 |
| bank | 0.0 | 0.0 | 1.5 | 0.8 |
| river | 0.0 | 0.0 | 0.0 | 2.2 |
This matrix has clear block structure. SVD decomposes it as . Let's trace through what happens in each component.
The first singular value will be the largest. The corresponding left singular vector will have large positive loadings for words with strong, concentrated co-occurrence patterns. Since "cat" and "dog" together account for most of the mass in the "pet" column, and "python" and "java" account for most of the mass in the "code" column, the first singular vector will roughly weight the animal and programming words equivalently (they both form strong clean blocks), while the first right singular vector will split between "pet" and "code."
The second singular vector captures the next most important contrast after removing the first component. With the dominant "frequent words co-occur a lot" effect removed, likely separates the animal cluster from the programming cluster, or the financial/geographic words from both.
After truncating to dimensions, each word becomes a 2D point given by the corresponding row of . The resulting geometry reflects the matrix structure:
- "Cat" and "dog" land near each other, because their PPMI profiles are nearly identical (both have high loading on "pet" and zero elsewhere).
- "Python" and "java" land near each other, for the same reason (both load heavily on "code").
- "Bank" lands in an intermediate region, because its PPMI profile is spread across "money" and "water" rather than concentrated in either animal or programming contexts.
- "River" lands near its dominant context "water," somewhat near "bank" but displaced toward the nature pole.
The 2D embedding has turned a 4-dimensional sparse representation into a 2-dimensional dense one. The key semantic groupings are preserved, and the intermediate position of "bank" correctly reflects its ambiguity across two contextual domains.
This toy example illustrates why SVD-based compression is often described as semantically meaningful by construction: the truncated dimensions keep the directions that explain most of the co-occurrence variance, and those directions correspond to the dominant thematic contrasts in the corpus.
Code Implementation
Let us implement LSA from scratch to see each step clearly, then compare with scikit-learn's TruncatedSVD for practical use.
First, we install and import all required libraries:
Building a PPMI Matrix
We start with a small corpus to build a word-context co-occurrence matrix, then apply PPMI weighting as covered in the previous chapter. The corpus spans two distinct domains (animals and programming) and includes "bank" as a deliberately ambiguous word that bridges finance and geography:
# Small corpus covering two domains: animals and programming
corpus = [
"cat pet animal feed",
"dog pet animal feed",
"kitten cat animal",
"puppy dog animal",
"python code software program",
"java code software program",
"compiler python software",
"algorithm java code",
"bank finance money",
"bank river water",
]
# Build vocabulary
words = sorted(set(w for doc in corpus for w in doc.split()))
word_to_idx = {w: i for i, w in enumerate(words)}
vocab_size = len(words)Vocabulary size: 19 Words: ['algorithm', 'animal', 'bank', 'cat', 'code', 'compiler', 'dog', 'feed', 'finance', 'java', 'kitten', 'money', 'pet', 'program', 'puppy', 'python', 'river', 'software', 'water']
# Build co-occurrence matrix (document-level context)
# Each document is treated as a context window: all words in the same
# document are considered context for each other.
cooc = np.zeros((vocab_size, vocab_size))
for doc in corpus:
doc_words = doc.split()
for i, w1 in enumerate(doc_words):
for w2 in doc_words:
if w1 != w2:
cooc[word_to_idx[w1], word_to_idx[w2]] += 1
# Apply PPMI weighting
total = cooc.sum()
row_sums = cooc.sum(axis=1, keepdims=True)
col_sums = cooc.sum(axis=0, keepdims=True)
# PMI = log2(P(w,c) / (P(w) * P(c)))
# Small epsilon avoids log(0) for zero co-occurrences
epsilon = 1e-12
pmi = np.log2(
(cooc / total + epsilon)
/ ((row_sums / total) * (col_sums / total) + epsilon)
)
# PPMI: keep only positive PMI values
ppmi = np.maximum(pmi, 0)PPMI matrix shape: (19, 19) Sparsity (fraction zero): 82.27%
Most entries are zero. This reflects the sparsity typical of real co-occurrence matrices. PPMI has converted raw counts into meaningful association scores, and now we apply SVD to compress these into dense embeddings.
Computing SVD
We use numpy's linalg.svd to compute the full decomposition, then examine the singular value spectrum. The full_matrices=False option returns the economy (thin) SVD, which computes only components rather than the full square matrices:
# Full (thin) SVD
U, s, Vt = np.linalg.svd(ppmi, full_matrices=False)
# Fraction of variance explained by each component
# Each singular value squared is proportional to the variance it explains
variance_explained = s**2 / (s**2).sum()
cumulative_variance = variance_explained.cumsum()Top singular values and their contribution to total variance: Component Sigma Variance Cumulative ------------------------------------------------ 1 9.327 22.8% 22.8% 2 7.406 14.4% 37.3% 3 7.369 14.3% 51.5% 4 4.935 6.4% 57.9% 5 4.392 5.1% 63.0% 6 4.392 5.1% 68.0% 7 4.392 5.1% 73.1% 8 4.137 4.5% 77.6%
The first few components capture most of the variance. The rapid drop-off in singular values tells us the PPMI matrix has measurable low-rank structure: only a few latent dimensions are needed to capture the essential patterns, and the remainder is noise.
Truncated Embeddings
We form the word embeddings by projecting onto the top singular vectors, scaling each coordinate by the corresponding singular value. The scaling is important: it ensures that the distance between embeddings in the truncated space reflects the contribution of each dimension to the original matrix:
# Truncated SVD: k=2 for visualization, k=4 for richer embeddings
k = 2
U_k = U[:, :k]
s_k = s[:k]
# Word embeddings: rows of U_k * Sigma_k
# Shape: (vocab_size, k)
# Each row is the k-dimensional embedding for one word.
word_embeddings_2d = U_k * s_k
# Also compute k=4 embeddings for similarity comparison
k4 = min(4, len(s))
word_embeddings_4d = U[:, :k4] * s[:k4]2D word embeddings (U_k * Sigma_k): Word Dim 1 Dim 2 ------------------------------------ algorithm +0.000 -0.000 animal +0.000 -3.693 bank -5.487 -0.000 cat +0.000 -2.882 code +0.000 -0.000 compiler +0.000 -0.000 dog +0.000 -2.882 feed +0.000 -2.710 finance -3.771 -0.000 java +0.000 -0.000 kitten +0.000 -2.227 money -3.771 -0.000 pet +0.000 -2.710 program +0.000 -0.000 puppy +0.000 -2.227 python +0.000 -0.000 river -3.771 -0.000 software +0.000 -0.000 water -3.771 -0.000
The embedding coordinates directly reflect the semantic structure. Words from the same domain cluster together in the 2D space, and the ambiguous word "bank" should occupy an intermediate position. This reflects its membership in both the finance and nature clusters.
Visualizing the Embedding Space
A 2D scatter plot lets us see the semantic geometry directly:

Singular Value Spectrum
Visualizing the singular value decay curve helps guide the choice of and reveals how much low-rank structure the corpus contains:


The left panel shows the characteristic "elbow" shape: a few large singular values followed by a rapid drop to a flat tail. The right panel shows that just a few components explain the majority of variance in this small matrix. In a real corpus with hundreds of thousands of words, the number of components needed to reach 80% explained variance would be much larger, but the qualitative shape of both curves would be similar.
Cosine Similarity in Embedding Space
One of the most important tests for embedding quality is whether semantically similar words have high cosine similarity. Cosine similarity measures the angle between two vectors, ranging from -1 (opposite directions) to +1 (same direction), with 0 indicating orthogonality. Unlike Euclidean distance, cosine similarity is invariant to vector magnitude, which makes it reliable when comparing words that vary in frequency:
def cosine_similarity(v1, v2):
"""Compute cosine similarity between two vectors."""
norm1 = np.linalg.norm(v1)
norm2 = np.linalg.norm(v2)
if norm1 == 0 or norm2 == 0:
return 0.0
return np.dot(v1, v2) / (norm1 * norm2)
# Compare pairs using 4D embeddings for richer signal
word_pairs = [
("cat", "dog"), # Should be similar (both animals)
("python", "java"), # Should be similar (both programming)
("cat", "python"), # Should differ (different domains)
("bank", "finance"), # Should be moderately similar (financial context)
("bank", "river"), # Should be moderately similar (water context)
]
similarities = {}
for w1, w2 in word_pairs:
if w1 in word_to_idx and w2 in word_to_idx:
v1 = word_embeddings_4d[word_to_idx[w1]]
v2 = word_embeddings_4d[word_to_idx[w2]]
similarities[(w1, w2)] = cosine_similarity(v1, v2)Cosine similarities (k=4 LSA embeddings): Word Pair Similarity ------------------------------------- cat vs dog +1.0000 python vs java +1.0000 cat vs python -0.0000 bank vs finance +0.5434 bank vs river +0.5434
The similarity scores validate that LSA has captured domain structure. Within-domain pairs ("cat vs dog" and "python vs java") score much higher than cross-domain pairs ("cat vs python"). The ambiguous word "bank" shows moderate similarity to both finance-related and nature-related words, correctly reflecting its distributional ambiguity. This is LSA working as intended: the compressed representations encode the distributional patterns of the training corpus.
Using scikit-learn's TruncatedSVD
For real-world use with large sparse matrices, scikit-learn's TruncatedSVD is far more efficient than full SVD. It uses randomized SVD internally, handles sparse inputs natively, and provides variance explained metrics directly:
from scipy.sparse import csr_matrix
from sklearn.decomposition import TruncatedSVD
# Convert PPMI to sparse format (essential for large vocabularies)
ppmi_sparse = csr_matrix(ppmi)
# TruncatedSVD uses randomized SVD internally for efficiency
k = 4
svd = TruncatedSVD(n_components=k, random_state=42)
embeddings_sklearn = svd.fit_transform(ppmi_sparse)Input matrix shape: (19, 19) Embedding matrix shape: (19, 4) Total variance explained: 49.8% Per-component variance: Component 1: 20.3% Component 2: 11.0% Component 3: 10.9% Component 4: 7.6%
Note that TruncatedSVD.fit_transform returns the matrix directly: the row embeddings already incorporate the singular value scaling. The output shape of (vocab_size, k) gives one -dimensional embedding per word, ready for downstream use.
Comparing k Values
How does the choice of affect embedding quality? We can compare similarity rankings across different truncation levels to understand the tradeoff between noise reduction and semantic resolution:
k_values = [1, 2, 4, 6]
similarity_by_k = {}
for k_val in k_values:
k_actual = min(k_val, len(s))
emb = U[:, :k_actual] * s[:k_actual]
sim_dict = {}
for w1, w2 in word_pairs:
if w1 in word_to_idx and w2 in word_to_idx:
v1 = emb[word_to_idx[w1]]
v2 = emb[word_to_idx[w2]]
sim_dict[(w1, w2)] = cosine_similarity(v1, v2)
similarity_by_k[k_val] = sim_dictCosine similarity across k values: Word Pair k= 1 k= 2 k= 4 k= 6 --------------------------------------------------------- cat vs dog +1.00 +1.00 +1.00 +1.00 python vs java +1.00 +0.96 +1.00 +1.00 cat vs python +1.00 +0.11 -0.00 -0.00 bank vs finance +1.00 +1.00 +0.54 +0.41 bank vs river +1.00 +1.00 +0.54 +0.40
This comparison shows how the similarity structure evolves as we include more dimensions. With , only the dominant pattern is captured, and the full semantic picture is compressed to a single axis. With , finer distinctions emerge, and word pairs that share secondary contexts begin to show differentiated similarities.
A heatmap makes this evolution easy to see across all word pairs and all values simultaneously:

Key Parameters
The key parameters for TruncatedSVD are:
- n_components: The number of singular vectors to compute, controlling the embedding dimensionality. This is the most important parameter, and the choice follows the guidance in the section on choosing above.
- algorithm: Either
'randomized'(default, fast for large matrices) or'arpack'(exact, better for small matrices or when high precision is needed). For most NLP applications with matrices larger than a few thousand words,'randomized'is strongly preferred. - n_iter: Number of power iteration steps for the randomized algorithm. More iterations improve approximation quality at the cost of computation time. The default of 4 is sufficient for most NLP matrices.
- random_state: Random seed for reproducibility when using the randomized algorithm. Always set this to ensure consistent results across runs.
Analyzing SVD Dimensions
To ground the abstract algebra in something concrete, let us look at how SVD dimensions correspond to semantic content in practice. The approach is to examine the top-loading words for each left singular vector: the words with the most positive and most negative loadings reveal what semantic contrast the dimension is capturing.
def top_words_for_dimension(U, s, words, dim_idx, n=5):
"""Return the top n positive and negative words for an SVD dimension."""
loadings = U[:, dim_idx] * s[dim_idx]
top_pos = np.argsort(loadings)[-n:][::-1]
top_neg = np.argsort(loadings)[:n]
return (
[(words[i], loadings[i]) for i in top_pos],
[(words[i], loadings[i]) for i in top_neg],
)Dimension 1 (sigma=9.327): Positive: software(+0.00), python(+0.00), compiler(+0.00), java(+0.00) Negative: bank(-5.49), water(-3.77), river(-3.77), finance(-3.77) Dimension 2 (sigma=7.406): Positive: python(-0.00), algorithm(-0.00), compiler(-0.00), bank(-0.00) Negative: animal(-3.69), dog(-2.88), cat(-2.88), pet(-2.71) Dimension 3 (sigma=7.369): Positive: animal(+0.00), dog(+0.00), cat(+0.00), feed(+0.00) Negative: code(-3.21), software(-3.21), java(-2.85), python(-2.85) Dimension 4 (sigma=4.935): Positive: water(+1.45), money(+1.45), finance(+1.45), river(+1.45) Negative: bank(-3.99), compiler(-0.00), python(-0.00), feed(-0.00)
This analysis shows which words pull most strongly in each direction. On a toy corpus the interpretations are simple, but on a large corpus the same technique reveals meaningful semantic structure: frequency effects in early dimensions, domain contrasts in middle dimensions, and register or style contrasts in later dimensions.
Visualizing the SVD Components as a Heatmap
Another way to understand the SVD is to visualize the loading matrix directly: plotting as a heatmap with words on the rows and dimensions on the columns shows which words load most strongly on which components.

Limitations and Impact
When introduced in 1990, LSA demonstrated that automatic, unsupervised learning could produce word representations capturing semantic similarity, without any hand-built lexicons, dictionaries, or rules. The system outperformed human performance on synonym selection tasks and enabled document retrieval that found relevant documents even when query terms did not appear in them verbatim. These results were remarkable, and they established distributional methods as a serious approach to computational semantics.
The impact extended well beyond information retrieval. LSA became a widely used tool in cognitive science: researchers used it to model how humans acquire vocabulary and how semantic memory is organized. Landauer and Dumais used LSA to argue that word co-occurrence alone, without any symbolic processing, could explain a substantial fraction of human semantic knowledge. This sparked a productive debate about the sufficiency of distributional information for capturing meaning, a debate that continues today in discussions of large language models.
Yet LSA has significant limitations that motivated the development of newer methods. The most fundamental is computational. SVD on large matrices is expensive, and even with randomized algorithms, the memory requirements for large vocabulary matrices are substantial. A production-scale vocabulary of 500,000 words produces a matrix with 250 billion potential entries. Even in sparse form with 0.1% fill, that is 250 million nonzeros at several gigabytes. The full pipeline from corpus to embeddings can take hours on modern hardware for large corpora.
More importantly, LSA operates on global co-occurrence statistics: each entry in the PPMI matrix summarizes co-occurrence across the entire corpus. This means all context is pooled together, losing positional information. The phrase "not good" co-occurs with "good" in a window, but so does "very good." LSA cannot distinguish which pattern is which because the same context word "good" gets counted in both. Negation, scope, and composition are invisible to the global count aggregation.
LSA embeddings also struggle with polysemy. The word "bank" receives a single embedding vector, regardless of whether it appears in a financial context or a geographical one. This single-vector limitation means that LSA conflates the financial sense and the riverbank sense into one mixed representation that may not be ideal for either downstream task. Word2Vec and later dense neural embeddings still share this limitation, but contextual models like ELMo and then BERT eventually solved it by producing different embeddings for each token occurrence depending on the surrounding context.
The reliance on linear algebra places a fundamental ceiling on what LSA can capture. Language meaning is not purely linear: the relationship between "not" and the words it negates requires understanding scope and semantic composition. The meaning of "kick the bucket" (idiomatically: to die) is not a linear combination of the meanings of "kick" and "bucket." Simple matrix factorization cannot capture these nonlinear relationships. Neural embedding methods, starting with Word2Vec in 2013, moved beyond these constraints by learning embeddings through prediction tasks. And transformer-based models moved even further by learning contextual, compositional representations through self-attention over the entire sequence.
Despite these limitations, LSA remains widely used today in specific applications: information retrieval, document similarity, topic exploration, and exploratory analysis of large text collections. Its theoretical guarantees (optimal rank- approximation by the Eckart-Young theorem), interpretable components, and deterministic behavior (with fixed random seed for randomized variants) make it a principled baseline against which newer methods are compared. Many practitioners find that LSA embeddings are surprisingly competitive with neural embeddings on tasks where global co-occurrence patterns are more informative than local context, particularly in domain-specific retrieval applications.
The Matrix Factorization Interpretation of Word2Vec
One of the most intellectually interesting aspects of LSA's legacy is its relationship to Word2Vec. In 2014, Levy and Goldberg proved that Word2Vec's skip-gram model with negative sampling is implicitly factorizing a shifted version of the PMI matrix. The neural network that Word2Vec trains is, in a precise mathematical sense, performing matrix factorization on a modified co-occurrence matrix. This result unified the statistical and neural approaches to distributional semantics, showing that the two superficially different frameworks are mathematically equivalent under certain conditions.
The implication is that the improvements of Word2Vec over LSA are not primarily due to neural networks per se, but rather due to differences in the objective (PMI with negative sampling vs. PPMI), the training procedure (stochastic gradient descent on pairs vs. batch SVD on the full matrix), and the weighting scheme (harmonic weighting of context positions vs. uniform window counts). These are meaningful differences, but they are not the difference between "neural" and "classical": they are differences in how the distributional statistics are collected and how the factorization is performed.
This insight directs attention toward what the actual engineering choices are in building good distributional embeddings, and it clarifies that the progress from LSA to Word2Vec to GloVe was incremental and cumulative, not a revolutionary break. The next chapter covers Word2Vec in detail, which builds directly on the distributional intuitions developed here while introducing the prediction-based training objective that proved empirically superior.
Sensitivity to Corpus Quality and Preprocessing
One practical aspect of LSA that practitioners learn quickly is its sensitivity to corpus quality. Unlike neural models, which can tolerate some noise through their implicit regularization mechanisms, SVD is quite sensitive to how the input matrix is constructed. Choices that matter significantly include:
Minimum frequency thresholds: Words that appear fewer than 5-10 times provide unreliable statistics. Including them adds noise to the low singular values and can degrade embedding quality for frequent words through the orthogonality constraint. A common rule of thumb is to exclude words appearing fewer than 5-10 times per million tokens.
Context window size: Narrower windows produce syntactically focused embeddings; wider windows produce topically focused embeddings. The right size depends on the task. Named entity recognition benefits from narrow windows; document similarity benefits from wide ones.
Subsampling: Discarding a fraction of occurrences of very frequent words (analogous to Word2Vec's subsampling) can improve embedding quality by reducing the dominance of the first SVD dimension, which often captures little more than frequency.
PPMI smoothing: Replacing the standard denominator in PPMI with a raised-power version of the context distribution (context probability raised to the power 0.75) reduces the bias toward rare contexts and improves embedding quality on word similarity benchmarks.
These choices interact with in ways that are hard to predict theoretically, making empirical tuning essential for production systems.
Summary
Singular Value Decomposition converts large, sparse co-occurrence matrices into compact, dense word embeddings by finding the most important linear dimensions of the data. The key ideas from this chapter are:
- SVD decomposes any matrix as , where the left singular vectors define word space, the right singular vectors define context space, and the singular values measure how much variance each direction captures
- Truncated SVD retains only the top components, giving the optimal rank- approximation by the Eckart-Young-Mirsky theorem: no other rank- matrix is closer to the original under the Frobenius norm
- LSA applies truncated SVD to word-context or term-document matrices to discover latent semantic dimensions, enabling words that never co-occur directly to have high similarity if they share distributional neighborhoods
- The singular value spectrum guides the choice of : retain components before the elbow in the scree plot, and validate with downstream task performance
- Exact SVD is but sparse matrix algorithms and randomized SVD bring this to practical levels; scikit-learn's
TruncatedSVDhandles large sparse matrices efficiently with the randomized algorithm - Randomized SVD achieves near-exact results by projecting to a random low-dimensional subspace first, then computing exact SVD of the smaller projected matrix; this reduces computation from to a much faster constant-factor improvement
- SVD dimensions are not directly interpretable but reflect real semantic structure; examining top-loading words for each dimension reveals the semantic contrasts it captures
- LSA captures global co-occurrence patterns but cannot handle polysemy, negation, or compositional meaning; these limitations motivated the transition to neural approaches
- Word2Vec implicitly performs matrix factorization on a shifted PMI matrix, unifying the neural and algebraic traditions and showing that the progress from LSA to Word2Vec was a matter of objective and training procedure rather than a categorical shift in methodology
Quiz
Ready to test your understanding? Take this quick quiz to reinforce what you've learned about Singular Value Decomposition and Latent Semantic Analysis.
Singular Value Decomposition and LSA
Reference
Citation details
Cite or share this article.
Continue with the full handbook
This chapter is part of Language AI Handbook. Use the handbook page to browse the complete table of contents and continue reading in sequence.
Explore Language AI HandbookStay up to date
Get articles, book updates, and news delivered to your inbox.
No spam, unsubscribe anytime.
Join the community
Sign in to remove popups, track your reading progress, and join the discussion.

Comments
1 comment
I am not sure the quizzes work ... after answering one question, the second one does not show.
Hi Roddy, Thank you for flagging the bug. I've pushed a fix, and it should now be working again.