Phase 05 - Lesson 15

Modelagem de Tópicos — LDA e BERTopic

LDA: documentos são misturas de tópicos, tópicos são distribuições sobre palavras. BERTopic: documentos se agrupam no espaço de embeddings, os agrupamentos são tópicos. Mesmo objetivo, primitivas diferentes.

Tipo: Aprender Linguagens: Python Pré-requisitos: Fase 5 · 02 (BoW + TF-IDF), Fase 5 · 03 (Word2Vec) Tempo: ~45 minutos

O Problema

Você tem 10.000 tickets de suporte ao cliente, 50.000 artigos de notícias ou 200.000 tweets. Você precisa saber sobre o que a coleção trata sem lê-la. Você não tem categorias rotuladas. Você nem sabe quantas categorias existem.

A modelagem de tópicos responde a isso sem supervisão. Dê a ela um corpus e receba de volta um pequeno conjunto de tópicos coerentes e, para cada documento, uma distribuição sobre esses tópicos.

Duas famílias algorítmicas dominam. O LDA (2003) trata cada documento como uma mistura de tópicos latentes e cada tópico como uma distribuição sobre palavras. A inferência é bayesiana. Ele ainda é usado em produção quando você precisa de atribuições de tópicos com pertencimento misto e distribuições de probabilidade explicáveis no nível das palavras.

O BERTopic (2020) codifica documentos com BERT, reduz a dimensionalidade com UMAP, agrupa com HDBSCAN e extrai palavras de tópicos via TF-IDF baseado em classes. Ele se sai melhor com texto curto, redes sociais e qualquer coisa em que a similaridade semântica importe mais do que a sobreposição de palavras. Um documento recebe um único tópico, o que é uma limitação para conteúdo de formato longo.

Esta lição constrói intuição para ambos e indica qual escolher para um dado corpus.

O Conceito

Modelo de mistura do LDA vs agrupamento do BERTopic

História generativa do LDA. Cada tópico é uma distribuição sobre palavras. Cada documento é uma mistura de tópicos. Para gerar uma palavra em um documento, amostre um tópico da mistura do documento e, em seguida, amostre uma palavra da distribuição desse tópico. A inferência inverte isso: dadas as palavras observadas, infira a distribuição de tópicos por documento e a distribuição de palavras por tópico. A amostragem de Gibbs colapsada ou o Bayes variacional fazem a matemática.

Saída principal do LDA:

  • doc_topic: matriz (n_docs, n_topics), cada linha soma 1 (mistura de tópicos do documento).
  • topic_word: matriz (n_topics, vocab_size), cada linha soma 1 (distribuição de palavras do tópico).

Pipeline do BERTopic.

  1. Codifique cada documento com um sentence transformer (por exemplo, all-MiniLM-L6-v2). Vetores de 384 dimensões.
  2. Reduza a dimensionalidade com UMAP para ~5 dimensões. Os embeddings do BERT têm dimensionalidade alta demais para agrupamento.
  3. Agrupe com HDBSCAN. Baseado em densidade, produz agrupamentos de tamanho variável e um rótulo de "outlier".
  4. Para cada agrupamento, calcule o TF-IDF baseado em classes sobre os documentos do agrupamento para extrair as principais palavras.

A saída é um tópico por documento (mais um rótulo de outlier -1). Opcionalmente, um pertencimento suave via o vetor de probabilidade do HDBSCAN.

Construa

Passo 1: LDA com scikit-learn

from sklearn.feature_extraction.text import CountVectorizer
from sklearn.decomposition import LatentDirichletAllocation
import numpy as np


def fit_lda(documents, n_topics=5, max_features=1000):
    cv = CountVectorizer(
        max_features=max_features,
        stop_words="english",
        min_df=2,
        max_df=0.9,
    )
    X = cv.fit_transform(documents)
    lda = LatentDirichletAllocation(
        n_components=n_topics,
        random_state=42,
        max_iter=50,
        learning_method="online",
    )
    doc_topic = lda.fit_transform(X)
    feature_names = cv.get_feature_names_out()
    return lda, cv, doc_topic, feature_names


def print_top_words(lda, feature_names, n_top=10):
    for idx, topic in enumerate(lda.components_):
        top_idx = np.argsort(-topic)[:n_top]
        words = [feature_names[i] for i in top_idx]
        print(f"topic {idx}: {' '.join(words)}")

Observe: stopwords removidas, min_df e max_df filtram termos raros e onipresentes, CountVectorizer (não TfidfVectorizer) porque o LDA espera contagens brutas.

Passo 2: BERTopic (produção)

from bertopic import BERTopic

topic_model = BERTopic(
    embedding_model="sentence-transformers/all-MiniLM-L6-v2",
    min_topic_size=15,
    verbose=True,
)

topics, probs = topic_model.fit_transform(documents)
info = topic_model.get_topic_info()
print(info.head(20))
valid_topics = info[info["Topic"] != -1]["Topic"].tolist()
for topic_id in valid_topics[:5]:
    print(f"topic {topic_id}: {topic_model.get_topic(topic_id)[:10]}")

O filtro em Topic != -1 descarta o balde de outliers do BERTopic (documentos que o HDBSCAN não conseguiu agrupar). O min_topic_size controla o tamanho mínimo de agrupamento do HDBSCAN; o padrão da biblioteca BERTopic é 10. Este exemplo o define explicitamente como 15 para a escala da lição. Para corpora com mais de 10.000 documentos, aumente para 50 ou 100.

Passo 3: avaliação

Ambos os métodos produzem palavras de tópicos. A questão é se essas palavras são coerentes.

  • Coerência de tópicos (c_v). Combina a NPMI (informação mútua pontual normalizada) de pares de palavras principais sobre contextos de janela deslizante, agrega as pontuações em vetores de tópicos e compara esses vetores via similaridade de cosseno. Quanto maior, melhor. Use gensim.models.CoherenceModel com coherence="c_v".
  • Diversidade de tópicos. Fração de palavras únicas entre as principais palavras de todos os tópicos. Quanto maior, melhor (os tópicos não se sobrepõem).
  • Inspeção qualitativa. Leia as principais palavras de cada tópico. Elas nomeiam algo real? O julgamento humano ainda é a última linha de defesa.

Quando escolher qual

Situação Escolha
Texto curto (tweets, avaliações, manchetes) BERTopic
Documentos longos com misturas de tópicos LDA
Sem GPU / poder computacional limitado LDA ou NMF
Necessidade de distribuições multitópico no nível do documento LDA
Integração com LLM para rotulagem de tópicos BERTopic (suporte direto)
Implantação em edge com recursos restritos LDA
Coerência semântica máxima BERTopic

A maior consideração prática é o comprimento do documento. Os embeddings do BERT truncam; as contagens do LDA funcionam com qualquer comprimento. Para documentos maiores que o contexto do modelo de embeddings, ou divida em pedaços + agregue ou use LDA.

Use

A stack de 2026:

  • BERTopic. Padrão para texto curto e qualquer coisa em que a semântica importe.
  • gensim.models.LdaModel. LDA clássico para produção, maduro, testado em batalha.
  • sklearn.decomposition.LatentDirichletAllocation. LDA fácil para experimentos.
  • NMF. Fatoração de matriz não negativa. Alternativa rápida ao LDA, qualidade comparável em texto curto.
  • Top2Vec. Design semelhante ao BERTopic. Comunidade menor, mas bom em alguns benchmarks.
  • FASTopic. Mais novo, mais rápido que o BERTopic em corpora muito grandes.
  • Rotulagem baseada em LLM. Execute qualquer agrupamento e depois peça a um modelo para nomear cada agrupamento.

Entregue

Salve como outputs/skill-topic-picker.md:

---
name: topic-picker
description: Pick LDA or BERTopic for a corpus. Specify library, knobs, evaluation.
version: 1.0.0
phase: 5
lesson: 15
tags: [nlp, topic-modeling]
---

Given a corpus description (document count, avg length, domain, language, compute budget), output:

1. Algorithm. LDA / NMF / BERTopic / Top2Vec / FASTopic. One-sentence reason.
2. Configuration. Number of topics: `recommended = max(5, round(sqrt(n_docs)))`, clamped to 200 for corpora under 40,000 docs; permit >200 only when the corpus is genuinely large (>40k) and note the increased compute cost. `min_df` / `max_df` filters and embedding model for neural approaches also belong here.
3. Evaluation. Topic coherence (c_v) via `gensim.models.CoherenceModel`, topic diversity, and a 20-sample human read.
4. Failure mode to probe. For LDA, "junk topics" absorbing stopwords and frequent terms. For BERTopic, the -1 outlier cluster swallowing ambiguous documents.

Refuse BERTopic on documents longer than the embedding model's context window without a chunking strategy. Refuse LDA on very short text (tweets, reviews under 10 tokens) as coherence collapses. Flag any n_topics choice below 5 as likely wrong; flag >200 on corpora under 40k docs as likely over-splitting.

Exercícios

  1. Fácil. Ajuste o LDA com 5 tópicos no conjunto de dados 20 Newsgroups. Imprima as 10 principais palavras por tópico. Rotule cada tópico manualmente. O algoritmo encontrou as categorias reais?
  2. Médio. Ajuste o BERTopic no mesmo subconjunto de 20 Newsgroups. Compare o número de tópicos encontrados, as principais palavras e a coerência qualitativa em relação ao LDA. Qual revela as categorias reais de forma mais limpa?
  3. Difícil. Calcule a coerência c_v tanto para o LDA quanto para o BERTopic no seu corpus. Execute cada um com 5, 10, 20 e 50 tópicos. Trace a coerência vs o número de tópicos. Relate qual método é mais estável entre os números de tópicos.

Termos-Chave

Termo O que as pessoas dizem O que realmente significa
Tópico Algo sobre o que o corpus trata Uma distribuição de probabilidade sobre palavras (LDA) ou um agrupamento de documentos semelhantes (BERTopic).
Pertencimento misto Um documento abrange vários tópicos O LDA atribui a cada documento uma distribuição sobre todos os tópicos.
UMAP Redução de dimensionalidade Aprendizado de variedade (manifold) que preserva a estrutura local; usado no BERTopic.
HDBSCAN Agrupamento por densidade Encontra agrupamentos de tamanho variável; produz rótulo de "ruído" (-1) para outliers.
Coerência c_v Métrica de qualidade de tópicos Informação mútua pontual média das principais palavras do tópico dentro de janelas deslizantes.

Leitura Complementar

0 lifetime access. Curriculum based on AI Engineering from Scratch by Rohit Ghumare (MIT, used under attribution).