Phase 05 - Lesson 15

Modelado de Tópicos — LDA y BERTopic

LDA: los documentos son mezclas de tópicos, los tópicos son distribuciones sobre palabras. BERTopic: los documentos se agrupan en el espacio de embeddings, los agrupamientos son tópicos. Mismo objetivo, primitivas diferentes.

Tipo: Aprender Lenguajes: Python Prerrequisitos: Fase 5 · 02 (BoW + TF-IDF), Fase 5 · 03 (Word2Vec) Tiempo: ~45 minutos

El Problema

Tienes 10.000 tickets de soporte al cliente, 50.000 artículos de noticias o 200.000 tweets. Necesitas saber de qué trata la colección sin leerla. No tienes categorías etiquetadas. Ni siquiera sabes cuántas categorías existen.

El modelado de tópicos responde a eso sin supervisión. Dale un corpus y recibe de vuelta un pequeño conjunto de tópicos coherentes y, para cada documento, una distribución sobre esos tópicos.

Dos familias algorítmicas dominan. LDA (2003) trata cada documento como una mezcla de tópicos latentes y cada tópico como una distribución sobre palabras. La inferencia es bayesiana. Todavía se usa en producción cuando necesitas asignaciones de tópicos con pertenencia mixta y distribuciones de probabilidad explicables a nivel de palabra.

BERTopic (2020) codifica documentos con BERT, reduce la dimensionalidad con UMAP, agrupa con HDBSCAN y extrae palabras de tópicos mediante TF-IDF basado en clases. Gana con texto corto, redes sociales y cualquier cosa donde la similitud semántica importe más que la superposición de palabras. Un documento recibe un solo tópico, lo que es una limitación para contenido de formato largo.

Esta lección construye intuición para ambos y señala cuál elegir para un corpus dado.

El Concepto

Modelo de mezcla de LDA vs agrupamiento de BERTopic

Historia generativa de LDA. Cada tópico es una distribución sobre palabras. Cada documento es una mezcla de tópicos. Para generar una palabra en un documento, muestrea un tópico de la mezcla del documento y luego muestrea una palabra de la distribución de ese tópico. La inferencia invierte esto: dadas las palabras observadas, infiere la distribución de tópicos por documento y la distribución de palabras por tópico. El muestreo de Gibbs colapsado o el Bayes variacional hacen la matemática.

Salida principal de LDA:

  • doc_topic: matriz (n_docs, n_topics), cada fila suma 1 (mezcla de tópicos del documento).
  • topic_word: matriz (n_topics, vocab_size), cada fila suma 1 (distribución de palabras del tópico).

Pipeline de BERTopic.

  1. Codifica cada documento con un sentence transformer (por ejemplo, all-MiniLM-L6-v2). Vectores de 384 dimensiones.
  2. Reduce la dimensionalidad con UMAP a ~5 dimensiones. Los embeddings de BERT tienen una dimensionalidad demasiado alta para el agrupamiento.
  3. Agrupa con HDBSCAN. Basado en densidad, produce agrupamientos de tamaño variable y una etiqueta de "outlier".
  4. Para cada agrupamiento, calcula el TF-IDF basado en clases sobre los documentos del agrupamiento para extraer las palabras principales.

La salida es un tópico por documento (más una etiqueta de outlier -1). Opcionalmente, una pertenencia suave mediante el vector de probabilidad de HDBSCAN.

Constrúyelo

Paso 1: LDA con 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)}")

Observa: stopwords eliminadas, min_df y max_df filtran términos raros y ubicuos, CountVectorizer (no TfidfVectorizer) porque LDA espera conteos brutos.

Paso 2: BERTopic (producción)

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]}")

El filtro sobre Topic != -1 descarta el cubo de outliers de BERTopic (documentos que HDBSCAN no pudo agrupar). El min_topic_size controla el tamaño mínimo de agrupamiento de HDBSCAN; el valor por defecto de la biblioteca BERTopic es 10. Este ejemplo lo establece explícitamente en 15 para la escala de la lección. Para corpus de más de 10.000 documentos, auméntalo a 50 o 100.

Paso 3: evaluación

Ambos métodos producen palabras de tópicos. La cuestión es si esas palabras son coherentes.

  • Coherencia de tópicos (c_v). Combina la NPMI (información mutua puntual normalizada) de pares de palabras principales sobre contextos de ventana deslizante, agrega las puntuaciones en vectores de tópicos y compara esos vectores mediante similitud del coseno. Cuanto más alta, mejor. Usa gensim.models.CoherenceModel con coherence="c_v".
  • Diversidad de tópicos. Fracción de palabras únicas entre las palabras principales de todos los tópicos. Cuanto más alta, mejor (los tópicos no se superponen).
  • Inspección cualitativa. Lee las palabras principales de cada tópico. ¿Nombran algo real? El juicio humano sigue siendo la última línea de defensa.

Cuándo elegir cuál

Situación Elige
Texto corto (tweets, reseñas, titulares) BERTopic
Documentos largos con mezclas de tópicos LDA
Sin GPU / cómputo limitado LDA o NMF
Necesidad de distribuciones multitópico a nivel de documento LDA
Integración con LLM para etiquetado de tópicos BERTopic (soporte directo)
Despliegue en edge con recursos restringidos LDA
Máxima coherencia semántica BERTopic

La mayor consideración práctica es la longitud del documento. Los embeddings de BERT truncan; los conteos de LDA funcionan con cualquier longitud. Para documentos más largos que el contexto del modelo de embeddings, o divide en fragmentos + agrega o usa LDA.

Úsalo

El stack de 2026:

  • BERTopic. Predeterminado para texto corto y cualquier cosa donde la semántica importe.
  • gensim.models.LdaModel. LDA clásico para producción, maduro, probado en batalla.
  • sklearn.decomposition.LatentDirichletAllocation. LDA fácil para experimentos.
  • NMF. Factorización de matrices no negativas. Alternativa rápida a LDA, calidad comparable en texto corto.
  • Top2Vec. Diseño similar a BERTopic. Comunidad más pequeña pero bueno en algunos benchmarks.
  • FASTopic. Más nuevo, más rápido que BERTopic en corpus muy grandes.
  • Etiquetado basado en LLM. Ejecuta cualquier agrupamiento y luego pídele a un modelo que nombre cada agrupamiento.

Entrégalo

Guarda 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.

Ejercicios

  1. Fácil. Ajusta LDA con 5 tópicos en el conjunto de datos 20 Newsgroups. Imprime las 10 palabras principales por tópico. Etiqueta cada tópico a mano. ¿El algoritmo encontró las categorías reales?
  2. Medio. Ajusta BERTopic en el mismo subconjunto de 20 Newsgroups. Compara el número de tópicos encontrados, las palabras principales y la coherencia cualitativa frente a LDA. ¿Cuál revela las categorías reales de forma más limpia?
  3. Difícil. Calcula la coherencia c_v tanto para LDA como para BERTopic en tu corpus. Ejecuta cada uno con 5, 10, 20 y 50 tópicos. Grafica la coherencia vs el número de tópicos. Informa qué método es más estable a lo largo de los números de tópicos.

Términos Clave

Término Lo que la gente dice Lo que realmente significa
Tópico Algo de lo que trata el corpus Una distribución de probabilidad sobre palabras (LDA) o un agrupamiento de documentos similares (BERTopic).
Pertenencia mixta Un documento abarca varios tópicos LDA asigna a cada documento una distribución sobre todos los tópicos.
UMAP Reducción de dimensionalidad Aprendizaje de variedad (manifold) que preserva la estructura local; usado en BERTopic.
HDBSCAN Agrupamiento por densidad Encuentra agrupamientos de tamaño variable; produce etiqueta de "ruido" (-1) para outliers.
Coherencia c_v Métrica de calidad de tópicos Información mutua puntual promedio de las palabras principales del tópico dentro de ventanas deslizantes.

Lectura Adicional

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