Topic Modeling
Topic modeling is the task of assigning each document to one or several topics, usually without supervision.
An Archive Nobody Has Labeled
Imagine a newsroom archive with tens of thousands of articles and no one has ever tagged them. A reader who wants every article about the economy, or every article about a local election, has no easy way to find them. Text data like this is everywhere: customer reviews, support tickets, research abstracts, and social media posts. Most of it arrives as raw sentences with no category attached.
Topic modeling is a technique often applied to text for exactly this situation. Instead of asking a person to read everything and label it, the technique tries to discover what the documents are about. This article starts with a short pipeline that runs end to end, then explains each step and shows where the results can go wrong.
Documents, Topics, and Supervision
Topic modeling is the task of assigning each document to one or several topics, usually without supervision.
The phrase one or several topics is the key to the definition. The task does not force every document into a single bin. A document may touch more than one subject, and the method's job is to say which subjects are present. The phrase usually without supervision signals that the topics are not handed to the method in advance. They have to be found from the documents themselves.
News data might be grouped into topics such as politics, sports, and finance. A newspaper editor would recognize these as the sections of the paper. Topic modeling aims to produce this kind of grouping from the text of the articles, rather than from a list of section names someone wrote down beforehand.
The method used most often for this task is Latent Dirichlet Allocation, usually abbreviated LDA. LDA discovers hidden topics in a body of text. The word hidden matters: nobody labels the topics in advance. The model proposes them from patterns of word use across documents, and the person running it has to read the output and decide what each topic means.
Running the Pipeline First
The lesson begins with running code rather than definitions. The pipeline takes a collection of text documents and returns two outputs: a per-document summary of which topics each document leans toward, and a per-topic summary of which words define each topic. Read the code once now, then follow each stage in the sections that come after it.
- CountVectorizer turns raw text into the numeric document-word table X
fit_transformfits the LDA model to X and returns the document-level output in one step- components_ holds the topic-word importance table produced by the fit
- argsort and the reversed column slice put the most important word positions first in each row
Follow the diagram from left to right. Each stage depends on the one before it. Documents become a count table, the count table is fitted to produce a document-level output and a topic-word table, and the topic-word table is sorted into readable lists. A problem at any early stage shows up later as a strange topic, so the chain is worth keeping in mind whenever results look wrong.
Turning Text into a Count Table
LDA does not read raw sentences. It needs a numeric table in which each row is a document and each column is a vocabulary word, and each cell holds how often that word appears in that document. scikit-learn's CountVectorizer builds this table. In the pipeline above, the vectorizer is created with two settings, and the call to fit_transform learns the vocabulary from the training texts and converts them into the table stored in X.
max_featurescaps the vocabulary size so the table stays manageablemax_dfdrops words that occur in a large share of documentsfit_transformlearns the vocabulary and builds X in one call
The two settings shape what the model is allowed to see. A cap on vocabulary size keeps the table manageable. Dropping words that appear in a large share of documents removes terms that show up almost everywhere and therefore say little about any particular subject. The values 1000 and 0.95 used here are illustrative choices, not fixed rules. X is the only thing LDA receives, so any choice made at this stage carries straight through to the topics.
Hyperparameters Chosen Before Fitting
Each keyword argument in the LDA call is a hyperparameter, meaning a setting chosen by the person before fitting rather than something the model learns from the data. The table below summarizes the settings used in the lesson pipeline and what each one changes.
| Setting | Value in the pipeline | What it controls |
|---|---|---|
| n_components | 10 | How many topics the model produces; every topic changes when this changes |
| learning_method | batch | The fitting method; the source notes batch is slower but usually gives better results than the faster online default |
| max_iter | 25 | How many passes the model makes over the data |
| random_state | a fixed value | The random starting point, so rerunning the code reproduces the same result |
Hyperparameters in the lesson's LDA call
The call to fit_transform does two jobs at once. It fits the model to X and returns the document-level output stored in document_topics. Doing both in one step avoids the second pass that would be needed if you fitted first and transformed afterward.
How the Model Stores Its Topics
Before you look at topic words, it helps to know how the fitted model stores its topics. The model keeps a table called components_, which records how important each word is for each topic. Each cell answers a single question: how important is this word to this topic? A large value means the word carries a lot of weight in that topic, and a small value means it hardly matters.
What do you think happens?
Before reading further, predict the shape of components_ when the model has 10 topics and a vocabulary of many words.
Reveal answer
(n_topics, n_words), so for 10 topics it has 10 rows, one per topic, and one column per vocabulary word.
Each row is a topic and each column is a word in the vocabulary built by CountVectorizer. The cell at a given row and column is the importance of that word to that topic.
The components_ table has the same role as the components in the matrix decomposition methods covered earlier in the course, so if you remember those, you already know the layout. The next diagram shows how a row of this table maps to a topic and how its values feed the ranked word list.
The rows are the topics. The columns are the words. Reading a topic means reading one row, and reading a word's role across topics means reading one column.
Ranking the Words in Each Topic
A row of numbers is hard to read, so the next step converts each row into a list of its strongest words. The approach is to sort each topic's word weights and then map the sorted positions back to vocabulary names. The critical detail is that np.argsort returns positions, not values. For a row, it answers the question: which word positions, in order from smallest weight to largest, make up this row?
sorting = np.argsort(lda.components_, axis=1)[:, ::-1]
for topic_idx, row in enumerate(sorting):
top_words = [feature_names[i] for i in row[:10]]
print(topic_idx, top_words)- 1
np.argsortwith axis=1 sorts each row of components_ and returns the word positions in ascending order of weight - 2[:, ::-1] reverses the columns, so the first entry of each row points to the most important word
- 3The loop goes through each topic row and maps its first ten positions to readable words through
feature_names - 4The topic index is printed only as a label; topic numbers carry no ranking
Ranking one topic row by hand
A toy model has a vocabulary of four words in this order: goal, vote, budget, team. One topic's row of components_ holds the weights 0.1, 2.5, 0.4, 1.7. Produce the ranked word list for that topic.
- 1Pair each weight with its position
Position 0 is goal with weight 0.1, position 1 is vote with 2.5, position 2 is budget with 0.4, and position 3 is team with 1.7.
- 2Sort the positions by ascending weight
Ordering from smallest to largest weight gives the positions 0, 2, 3, 1.
- 3Reverse the order
Applying the reversed column slice gives 1, 3, 2, 0, so the first entry points at the largest weight.
- 4Map positions to words
Positions 1, 3, 2, 0 map to vote, team, budget, goal through the feature names.
The ranked list for this topic is vote, team, budget, goal. These numbers and words are illustrative and generated for teaching, not taken from a real fitted model.
Choosing the Number of Topics
The number of topics is the most consequential hyperparameter in this pipeline. Ten topics are few enough that a reader can inspect every one of them. A hundred topics give a more fine-grained picture, but reading all 100 would be overwhelming, so the source inspects a hand-picked subset of them by index.
- Only
n_componentschanges relative to the 10-topic model - The selected indices are a judgment call made for illustration
- Each selected row is ranked with the same argsort idea used earlier
Notice that the selected topic numbers are not a sequence and carry no inherent meaning. They were picked because they look interesting and representative. A reader who picks differently will see a different slice of the model.
One Topic or Several per Document
The source describes two cases that both fall under topic modeling. In the first, each document is assigned a single topic. The source calls this the task of clustering the documents, which connects to the clustering ideas covered earlier in the course. In the second, each document can have more than one topic, and the source connects this case to the decomposition methods covered earlier.
When a document is allowed several topics, it helps to picture the document as a bundle of topics rather than a single label. The source explains that the coefficients of the components in a document's representation indicate how strongly the document relates to each topic. A stronger coefficient means a stronger connection.
Notice what this does not claim. It does not say the article belongs to exactly one bin. Each topic receives its own degree of relatedness. This is the practical meaning of a document having multiple topics, and it is what separates this case from clustering.
Topics as Components, Documents as Coefficients
The multi-topic case is linked to decomposition methods. In a decomposition method, the data is expressed in terms of a set of components. In topic modeling, each component the method learns corresponds to one topic. The representation of any single document then records how much of each component it contains, and those amounts are its coefficients.
Latent Dirichlet Allocation is the decomposition method people most often mean when they talk about topic modeling. In these terms, LDA is one specific way of learning the components, and each component is read as a topic. The source does not give the internal mathematics here, so the important takeaway is the shape of the result: topics as components, and documents as coefficients over those components.
Where Topic Results Diverge
When the topic words look wrong, the fault usually sits at one identifiable stage. Each mistake below names the stage where the divergence starts, which is the question a debugger needs answered first.
Common mistake Treating topic numbers as a ranking
What it looks likeAssuming Topic 0 matters more than Topic 9 because it comes first.
Why it failsA topic has no built-in rank, and the numbering is arbitrary.
Do this insteadRank the words within each topic, and compare topics by reading their words rather than by index.
Common mistake Reading components_ values as a sorted list
What it looks likeTaking the first column of a row and assuming it holds the strongest word.
Why it failsnp.argsortreturns positions, not values, and the raw row is in vocabulary order.Do this insteadApply argsort, reverse the columns with [:, ::-1], and then map the positions through the feature names.
Common mistake Expecting one topic to stay the same when the count changes
What it looks likeComparing Topic 3 from a 10-topic fit with Topic 3 from a 100-topic fit as if they describe the same subject.
Why it failsChanging the number of topics changes all of them.
Do this insteadTreat each fit as its own model and read its topics fresh.
Common mistake Forgetting that X sets the ceiling on what the model can see
Why it failsLDA only receives X, so vocabulary cuts and frequency cuts made when building it shape every topic.
Do this insteadCheck the vectorizer settings and the shape of X before blaming the model.
Common mistake Assuming the model names its own topics
Why it failsThe topics are proposed from patterns of word use, and a person has to read the output and decide what each topic means.
Do this insteadRead the top words of each topic and write down a label yourself.
When a topic looks strange, check the stages in the same order the data flows. Begin with the vocabulary and the shape of X, confirm the shape of components_ against the number of topics you set, then check the sorting and the feature names. Most divergences are found at the earliest stage that disagrees with your expectation.
Debugging a Strange Topic
A colleague fits LDA with 10 topics and reports that Topic 0 looks like a mix of unrelated words. Using the chain of stages, list in order the checks you would run to find where the divergence begins, and say what each check would reveal.
Hints
- Start with the vocabulary and the shape of X
- Next confirm that components_ has one row per topic you set
- Then check the argsort and reversed-column step, followed by the feature names
Putting the Pipeline Together
- 1Topic modeling assigns each document to one or several topics, usually without supervision, so the topics must be found from the documents themselves.
- 2LDA needs a document-word table X from CountVectorizer; its components_ table holds one row per topic and one column per word, and argsort with a reversed slice turns each row into a ranked word list.
- 3The number of topics and the learning method are hyperparameters; changing the number of topics changes every topic, and topics have no built-in rank.
- 4Document clustering assigns one topic per document, while decomposition-based topic modeling gives each document coefficients over several topic components.
- 5When results look wrong, check the stages in data-flow order, starting with X, then components_, then the sorting and feature names.
Key Takeaways
- Topic modeling assigns each document to one or several topics, usually without supervision, so the topics are discovered from the text rather than supplied in advance.
- LDA reads a numeric document-word table built by CountVectorizer and stores its topics in components_, which has shape (
n_topics,n_words). - Ranking a topic means applying argsort, reversing the columns, and mapping the positions through the feature names; topics have no built-in order.
- Clustering assigns each document to one topic, while decomposition-based topic modeling represents each document as coefficients over several topic components.
- Hyperparameters such as the number of topics and the learning method change the topics, so diagnose problems by checking the earliest stage that disagrees with expectation.