Machine Learning · Insper · U5

Topic Modeling & BERTopic

Given thousands of documents, what are they about?

LDA, NMF and BERTopic, from the classical to the modern

A question that sounds simple

  • Nobody labels the documents, nobody lists the themes: unsupervised, the text-world sibling of clustering.
  • Uses: a year of reviews or support tickets, a news archive, social media, a scientific literature.

LDA

a probabilistic story of how words are written

NMF

factorizes the TF-IDF matrix

BERTopic

sentence embeddings + UMAP + HDBSCAN + a variant of TF-IDF

Two corpora: 11 hand-written sentences, and 2,155 real posts from four forums (the forum is hidden from the models, to check them).

The path of this lesson

  1. What is a topic?words that go together, or documents that go together
  2. LDALatent Dirichlet Allocation: a story of how words get written
  3. NMFnon-negative matrix factorization: a document as a sum of parts
  4. BERTopicembed, reduce, cluster, describe
  5. Compare and choosethe three side by side; the pitfalls
Each stage answers one question: what are we looking for in the documents? → what story could have written these words? → can a matrix factorization find the same topics? → what if a topic is a cluster of documents? → which model should I trust, and when?
What are we looking for in the documents?

What is a topic? Two answers

a distribution over words

"Sports" gives high probability to team, game, goal, almost none to oven. A document is a mixture: 80% sports, 20% space.

LDA, and NMF with non-negative weights

a cluster of documents

Each document belongs to one topic, or to none; the topic's words are computed afterwards, to describe the cluster.

BERTopic

The hand-made corpus, as counts

docteamgamegoalrocketlaunchmoonbreadbake
011100000
300011000
600000011
911011000
1000000110

11 sentences, 53 words kept, a vocabulary of 33 (English stop words removed).

Three themes: sports, space, cooking; the last two sentences mix them.

Predict. A topic model receives only this matrix, without the comments. Can it find the three themes?
U5.1 LDA · What story could have written these words?

LDA: a story of how the words got there

Latent Dirichlet Allocation (Blei, Ng & Jordan, 2003):

  1. each topic \(k\) is a distribution \(\varphi_k\) over the vocabulary;
  2. each document \(d\) has its own mixture \(\theta_d\), e.g. \((0.8, 0.2)\);
  3. for every word slot: draw a topic \(z\) from \(\theta_d\), then a word from \(\varphi_z\).
\[ p(w \mid d) = \sum_k \theta_{d,k}\, \varphi_{k,w} \]

Not a claim that people write this way. Word order plays no part: bag-of-words counts are enough.

The story by hand

Two topics as bar charts over six words and the document's word distribution, 0.8 times the first plus 0.2 times the second

A document 80% sports, 20% space:

\(p(\textit{team}) = 0.8 \times 0.40 + 0.2 \times 0.05 = 0.33\)

\(p(\textit{rocket}) = 0.8 \times 0.05 + 0.2 \times 0.40 = 0.12\)

Following the story, 4 of 12 slots drew the space topic, and they are exactly where moon, orbit, rocket, orbit appear.

The Dirichlet prior: how mixed is a document?

Predict. With \(\alpha = 0.1\), are documents pure (one topic) or evenly mixed?
Mixtures of 400 documents over three topics in a triangle: alpha 0.1 piles them on the corners, alpha 1 spreads them, alpha 10 crowds the center
\(\alpha\)largest share
0.10.89
10.62
100.42

In scikit-learn: doc_topic_prior and topic_word_prior, both \(1/k\) by default: few topics per document, few words per topic.

Simulator: write a document the LDA way

Predict. With \(\alpha = 0.1\), will the documents you draw come out in one color or in all three?

Fitting LDA: running the story backwards

  • Generate a corpus with the story itself (300 documents, 30 words each), so the true topics are known.
  • LDA recovers the true weights (0.35, 0.30, 0.25 on each topic's own words) within 0.01.
  • The estimated mixtures correlate 0.97 with the true ones.
The topics come out in an arbitrary order: topic "2" of one run can be topic "0" of another.

And on the 53 hand-written words?

  • Seed 0: bread fresh game oven · team goal game orbit · rocket launch bread delayed: the themes mixed.
  • Each document still goes confidently (0.86 to 0.88) to one topic.
  • Over 20 seeds, only 1 separates the nine single-theme sentences cleanly.
Nothing is wrong with the code: with 53 words the counts carry too little evidence. LDA needs many documents with enough words each.

LDA on 2,155 real posts

Four forums of 20 Newsgroups (graphics, hockey, space, religion); 5,725 words of 3+ letters in at least 5 posts and at most half of them.

jpeg don pts like think play period gif
god space people think just jesus time like
team game hockey season games nhl play year
image edu data graphics space available software program
Hockey comes out clean; the rest blur. Each post goes to its largest topic; agreement with the forums, adjusted Rand index (ARI): 0.456.
U5.2 NMF · Can a matrix factorization find the same topics?

NMF: \(X \approx WH\), with nothing negative

\[ X_{\,n \times V} \;\approx\; W_{\,n \times k}\; H_{\,k \times V}, \qquad W \ge 0,\; H \ge 0 \]

rows of \(H\)

the topics: a weight for every word

rows of \(W\)

how much of each topic a document contains

Non-negative matrix factorization (Lee & Seung, 1999): the same shape as PCA, plus the constraint that every entry is \(\ge 0\). Here \(X\) is TF-IDF.

NMF on the 11 sentences

Topics: launch rocket satellite orbit · bread oven bake fresh · team game goal won

Clean split, where LDA failed 19 times out of 20.

init='nndsvda' starts from an SVD, not a random point: one reason the result is stable.

sentencespacecookingsports
0 (sports)0.000.000.71
3 (space)0.620.000.00
9 team watched the rocket launch…0.290.000.45
10 astronauts ate fresh bread…0.100.410.00

Why non-negative? A comparison with SVD

Heat maps of the two 3 x 33 topic-word matrices: TruncatedSVD has 25 negative weights and contrasts themes; NMF has none and each component lights up one theme
SVD: 25 negative weights; a component reads "sports words minus space words". NMF can only add parts, so each part is a whole theme.

Simulator: NMF parts versus SVD directions

Predict. From random weights, press step: will the NMF rows end up as whole themes or as contrasts like the SVD's? Will its error reach the SVD's?

NMF on the posts

graphics thanks files image program file know windows
god jesus people believe christ faith bible christians
game team hockey players play games season nhl
space nasa launch shuttle moon orbit lunar earth

LDA

0.456
ARI with the forums

NMF

0.767
the four topics are the four forums

One run on one corpus: the lab finds a corpus where the order is reversed.

How many topics, and are they any good?

No labels to cross-validate against: the score must come from the documents.

perplexity

how surprised LDA is by held-out posts; lower is better; only for probabilistic models

coherence (NPMI)

do the top words co-occur in documents?

\[ \text{NPMI}(w_i, w_j) = \frac{\log \dfrac{P(w_i, w_j)}{P(w_i)\,P(w_j)}}{-\log P(w_i, w_j)} \in [-1, 1] \]

By hand: of 2,155 posts, 304 contain god, 159 jesus, 101 both; independent would be 1.04%, observed 4.69%: NPMI = 0.492.

Choosing \(k\)

Left: LDA's held-out perplexity rises steadily with k. Right: coherence; LDA peaks at k = 4, NMF climbs to k = 4 and stays on a plateau

At \(k = 4\): LDA coherence 0.224, diversity 0.85; NMF 0.369 and 1.00.

Perplexity only rises: read literally, it recommends \(k = 2\); and it does not track what people find interpretable.

Scan a range of \(k\), look for a knee in coherence, then read the topics. Four forums or twelve sub-themes is a choice of granularity.
U5.3 BERTopic · What if a topic is a cluster of documents?

Short documents: where word counts run out

ARI against the number of words kept per post: below about 40 words, both NMF and LDA are close to zero

First 20 words of each post: NMF 0.12, LDA 0.03.

Predict. "I want my money back" / "please process a refund": TF-IDF cosine?

Meaning as distance

TF-IDF cosine

0.00
no shared word

embedding cosine

0.60
a sentence embedding does not need shared words

On the 20-word posts, plain k-means on the embeddings reaches ARI 0.582, five times NMF's.

The idea behind BERTopic: first place the documents where meaning is distance, then look for groups.

BERTopic: four steps, each a lesson you know

Stage 1 — embed

Each post → 384 numbers with all-MiniLM-L6-v2 (small, English, fast on a CPU).

Predict. For each post, take its 10 nearest posts. What share comes from the same forum, with TF-IDF and with embeddings?

TF-IDF

83.2%

embeddings

94.2%

Stage 2 — reduce with UMAP

  • In 384 dimensions distances concentrate: density-based clustering suffers.
  • UMAP to 5 dimensions, not 2: the goal is to cluster, not to draw.
  • min_dist=0.0 packs similar points tightly, which a density clusterer wants.
Same-forum neighbors after UMAP: 95.4%. The neighborhoods survived. UMAP is stochastic: fix random_state.

Stage 3 — cluster with HDBSCAN

Predict. Nobody sets the number of clusters. How many will there be, and will every post get one?

clusters

24
from min_cluster_size=10 and the density

outliers (−1)

431
20% of the posts

pure

21 / 24
≥ 90% of one forum

Hockey (516) and religion (554) are one big cluster each; graphics and space break into many small ones (file formats, graphics cards, the Moon…).

Simulator: min_cluster_size, one value at a time

Predict. Raise min_cluster_size from 2 to 40: will the number of topics fall smoothly?

Stage 4 — describe each cluster with c-TF-IDF

Join the documents of a cluster into one pseudo-document; then a class-based TF-IDF:

\[ \text{c-TF-IDF}(t, c) = \frac{n_{t,c}}{\sum_{t'} n_{t',c}} \times \log\!\Big(1 + \frac{A}{f_t}\Big) \]

By hand, three clusters of the hand-made sentences: 16, 13 and 14 words, \(A = 14\).

team (3×, all sports)

\(\tfrac{3}{16} \times \log(1 + 14/3) = 0.325\)

game (2×)

\(\tfrac{2}{16} \times \log 8 = 0.260\)

BERTopic's own transformer gives exactly the same matrix.

The clusters of the posts, named

clusterpoststop words
−1431space jpeg launch image (the outliers)
1567god jesus people church
0520team game hockey play
1566image graphics package processing
955card mode vesa vga
2352moon lunar prize money

The class BERTopic chains the same four steps: same partition (ARI 1.0), same top words, only renumbered by size.

Stage 5 — tune the words, not the clusters

topic 2, named by…top words
default vectorizerimage and for of to it or the graphics with
stop words removedimage graphics package processing software data analysis …
KeyBERTInspiredgraphical graphics rtrace plots tools interactive plotting …
The words are computed after clustering: update_topics changes them and the post-to-topic assignments stay identical.
U5.4 Comparing the Models · Which model should I trust, and when?

LDA vs NMF vs BERTopic, measured

Same 2,155 posts, 24 topics for all three, two seeds each. Predict first: whose topics are purest?

modelseedtopicsoutlierscoherencediversityhomogeneity
LDA42240%0.2650.720.526
NMF42240%0.3910.920.646
BERTopic422420%0.2510.880.927
LDA43240%0.2760.700.574
NMF43240%0.4070.910.644
BERTopic431610%0.2950.820.662

Reading the table

  • Homogeneity: BERTopic 0.927, but on the 80% of posts it kept; with seed 43 it finds 16 broader topics and falls to 0.662.
  • Coherence and diversity favor NMF: NPMI rewards co-occurring words, which NMF reconstructs; BERTopic picks distinctive words.
  • Stability between seeds (ARI): LDA 0.164, NMF 0.736, BERTopic 0.324, with even the number of topics changing.
A coherence score measures one aspect of quality, not the truth.

The overall comparison

LDANMFBERTopic
a topic isa distribution over wordsa non-negative row of \(H\)a cluster, named by c-TF-IDF
number of topicsfixed in advancefixed in advancefound by HDBSCAN
short documentsweakweakstrong
outliersnonenoneexplicit (−1)
seed-dependencestrongweaker (SVD start)yes, even the number of topics
costcheap, CPUcheapest, CPUembedding model; a GPU helps

Pitfalls: stop words and outliers

stop words

Without a list, topics are named by the, of, to. A list in the wrong language does not help: topic 6 here is van, het, een, from posts in Dutch.

too many outliers

reduce_outliers reassigns all 431. Homogeneity on all posts: 0.822 (c-TF-IDF) or 0.882 (embeddings), down from 0.927.

Forcing the ambiguous posts into topics makes them less pure: a trade-off, not a free fix.

Pitfall: granularity is a cliff, not a dial

Predict. min_cluster_size from 10 to 15: a few topics fewer, or a lot?
min_cluster_sizetopicsoutliers
59628%
102420%
1550%
2530%

Scan a few values and read the topics; to merge topics without re-clustering, reduce_topics.

Pitfall: reproducibility

Add to the embeddings a noise of about one millionth (the size of CPU-vs-GPU differences), keep every seed:

noise, seed 024 topics, ARI with the original 0.908
noise, seed 124 topics, ARI 0.910
noise, seed 23 topics, ARI 0.514
Fixing seeds makes a run repeatable, not true. Report topics that survive seeds and small perturbations, stay away from the cliff, and save the fitted model. For Portuguese, use a multilingual model and a Portuguese stop-word list.

Summary

  1. A topic is a distribution over words (LDA, NMF) or a cluster of documents (BERTopic).
  2. LDA: a generative story; needs many documents with enough words.
  3. NMF: additive parts of the TF-IDF matrix; stable, cheap, coherent.
  4. Choose \(k\) with coherence and by reading the topics; perplexity misleads.
  5. BERTopic: embed → UMAP → HDBSCAN → c-TF-IDF; strong on short texts, explicit outliers, fragile to seeds and to min_cluster_size.
Lab · two to three minutes on a CPU

Topics in five forums, three ways

  • Five other forums of 20 Newsgroups: 2,613 posts, between 495 and 551 per forum.
  • Steps 2–3: LDA and NMF. Steps 4–7: BERTopic step by step, then in one call. Steps 8–10: inspect the topics, compare them with the forums, deal with the outliers.
  • Download the lab notebook and open it in Jupyter or Colab; in Colab run !pip install bertopic first.
  • Run the blocks in order, in one session; most of the time is step 4.