토픽 모델링(Topic Modeling) — LDA와 BERTopic

LDA는 문서(document)를 토픽(topic)의 혼합으로, 토픽을 단어 분포(word distribution)로 봅니다. BERTopic은 문서를 임베딩 공간(embedding space)에서 군집화(clustering)하고 각 군집(cluster)을 토픽으로 봅니다. 목표는 같지만 사용하는 기본 단위(primitive)가 다릅니다.

유형: Learn 언어: Python 선수 강의: Phase 5 · 02 (BoW + TF-IDF), Phase 5 · 03 (Word2Vec) 예상 시간: 약 45분

학습 목표

  • LDA(Latent Dirichlet Allocation; 잠재 디리클레 할당)의 생성 과정(generative story)을 설명합니다.
  • BERTopic의 임베딩, UMAP, HDBSCAN, 클래스 기반 TF-IDF(class-based TF-IDF) 파이프라인을 이해합니다.
  • 토픽 일관성(topic coherence)과 토픽 다양성(topic diversity)으로 토픽 모델을 평가합니다.
  • 코퍼스(corpus) 길이, 연산 자원(compute budget), 다중 토픽 요구사항에 따라 LDA와 BERTopic을 선택합니다.

문제

10,000건의 고객 지원 티켓(customer support ticket), 50,000건의 뉴스 기사, 200,000건의 트윗이 쌓여 있다고 가정해봅니다. 모든 문서를 직접 읽지 않고도 이 모음(collection)이 무엇에 관한 것인지 파악해야 합니다. 라벨링된 카테고리도 없고, 카테고리가 몇 개나 존재하는지도 모릅니다.

토픽 모델링은 지도(supervision) 없이 이 문제에 답합니다. 코퍼스를 입력하면 일관성 있는 토픽 몇 개와, 각 문서별로 그 토픽들에 대한 분포(distribution)를 돌려줍니다.

알고리즘 계열은 크게 두 가지가 지배적입니다. LDA(2003)는 각 문서를 잠재 토픽(latent topic)의 혼합으로, 각 토픽을 단어에 대한 분포로 모델링합니다. 추론(inference)은 베이즈(Bayesian) 방식으로 이루어집니다. LDA는 혼합 소속(mixed-membership) 토픽 할당과 단어 수준의 설명 가능한 확률 분포가 필요한 경우 여전히 실무 환경(production)에서 쓰입니다.

BERTopic(2020)은 BERT로 문서를 인코딩(encode)하고, UMAP으로 차원을 축소한 뒤, HDBSCAN으로 군집화하고, 클래스 기반 TF-IDF로 토픽 단어를 추출합니다. 짧은 텍스트, 소셜 미디어, 단어 중첩보다 의미적 유사도(semantic similarity)가 더 중요한 경우에 강점이 있습니다. 다만 문서 하나에 토픽 하나만 부여된다는 점은 긴 문서를 다룰 때 한계로 작용합니다.

이 강의는 두 방식 모두에 대한 직관을 키우고, 주어진 코퍼스에 어떤 것을 선택해야 하는지를 정리합니다.

사전 테스트

2문제 · 이 강의를 시작하기 전에 얼마나 알고 있는지 확인해보세요

1.LDA는 각 문서를 토픽(topic)의 혼합(mixture)으로 모델링합니다. 이 맥락에서 '혼합'이 구체적으로 의미하는 것은 무엇인가요?

2.BERTopic은 문서마다 토픽 하나만 할당하고, LDA는 모든 토픽에 대한 분포를 할당합니다. 이 단일 할당(single-assignment) 특성이 한계가 되는 경우는 언제인가요?

0/2 답변 완료

개념

LDA (probabilistic, mixed-membership) document "stocks rose after the fed cut rates" topic mixture {finance: 0.7, politics: 0.2, ...} topic_word matrix: finance -> { stocks: 0.04, rate: 0.03, ... } politics -> { fed: 0.05, vote: 0.04, ... } tech -> { chip: 0.04, ai: 0.03, ... } each row sums to 1 good for long docs, topic mixtures, limited compute. weak on short text. no semantics. interpretable probability distributions. BERTopic (neural, cluster-based) docs (N) BERT embed 384-dim UMAP 5-dim HDBSCAN cluster 0 1 2 3 class-based TF-IDF top words per cluster = topic representation one topic per document. short text friendly. semantic.

LDA의 생성 과정(generative story). 각 토픽은 단어에 대한 확률 분포입니다. 각 문서는 토픽들의 혼합입니다. 문서 안의 단어 하나를 생성할 때, 먼저 문서의 혼합 분포에서 토픽 하나를 뽑고, 그다음 그 토픽의 단어 분포에서 단어 하나를 뽑습니다. 추론은 이 과정을 거꾸로 수행합니다. 즉, 관측된 단어들이 주어졌을 때 문서별 토픽 분포와 토픽별 단어 분포를 추정합니다. 수학적으로는 붕괴 깁스 샘플링(collapsed Gibbs sampling)이나 변분 베이즈(variational Bayes) 방법으로 풉니다.

LDA의 핵심 출력은 다음과 같습니다.

  • doc_topic: (n_docs, n_topics) 형태의 행렬(matrix)이며, 각 행(row)의 합은 1입니다(문서의 토픽 혼합).
  • topic_word: (n_topics, vocab_size) 형태의 행렬이며, 각 행의 합은 1입니다(토픽의 단어 분포).

BERTopic 파이프라인.

  1. 문장 임베딩 모델(sentence transformer, 예: all-MiniLM-L6-v2)로 각 문서를 384차원 벡터로 인코딩합니다.
  2. UMAP으로 차원을 약 5차원으로 축소합니다. BERT 임베딩은 그대로 군집화에 쓰기에는 차원이 너무 높습니다.
  3. HDBSCAN으로 군집화합니다. 밀도 기반(density-based) 알고리즘이라 군집 크기가 가변적이며, 어디에도 속하지 못한 문서에는 "이상치(outlier)" 라벨이 붙습니다.
  4. 각 군집에 대해, 그 군집에 속한 문서들에 클래스 기반 TF-IDF를 적용해 대표 단어를 뽑습니다.

출력은 문서당 하나의 토픽입니다(이상치 문서에는 -1 라벨이 붙습니다). 선택적으로 HDBSCAN의 확률 벡터를 통해 소프트 멤버십(soft membership)도 얻을 수 있습니다.

직접 만들기

Step 1: scikit-learn으로 LDA

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

여기서 짚어볼 점은 다음과 같습니다. 불용어(stopword)를 제거하고, min_dfmax_df로 너무 드물거나 너무 흔한 용어를 걸러냅니다. LDA는 원시 빈도(raw count)를 입력으로 기대하기 때문에 TfidfVectorizer가 아니라 CountVectorizer를 사용합니다.

Step 2: BERTopic(실무용)

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

Topic != -1 조건으로 BERTopic의 이상치 버킷(즉, HDBSCAN이 어떤 군집에도 넣지 못한 문서)을 제외합니다. min_topic_size는 HDBSCAN의 최소 군집 크기를 조절합니다. BERTopic 라이브러리의 기본값은 10이며, 이 예시에서는 강의 규모에 맞춰 15로 명시했습니다. 10,000건이 넘는 코퍼스라면 50이나 100으로 올리는 편이 좋습니다.

Step 3: 평가

두 방법 모두 토픽 단어를 출력합니다. 문제는 그 단어들이 서로 의미적으로 잘 묶이는지(coherent)입니다.

  • 토픽 일관성(topic coherence; c_v). 슬라이딩 윈도우 문맥에서 상위 단어 쌍의 NPMI(normalized pointwise mutual information; 정규화된 점별 상호정보량)를 계산하고, 이를 토픽별 벡터로 모은 뒤 코사인 유사도(cosine similarity)로 비교합니다. 값이 클수록 좋습니다. gensim.models.CoherenceModel에서 coherence="c_v"로 사용합니다.
  • 토픽 다양성(topic diversity). 모든 토픽의 상위 단어 중 고유한(unique) 단어의 비율입니다. 값이 클수록 좋으며, 토픽들이 서로 덜 겹친다는 뜻입니다.
  • 정성적 검토(qualitative inspection). 각 토픽의 상위 단어를 사람이 직접 읽고, 그것이 실제로 어떤 개념을 가리키는지 이름 붙일 수 있는지 확인합니다. 사람의 판단이 마지막 방어선입니다.

무엇을 선택할까

상황선택
짧은 텍스트(트윗, 리뷰, 헤드라인)BERTopic
토픽이 혼합된 긴 문서LDA
GPU가 없거나 연산 자원이 부족LDA 또는 NMF
문서 수준 다중 토픽 분포가 필요LDA
LLM 통합으로 토픽 라벨링BERTopic(직접 지원)
자원이 제약된 엣지 배포(edge deployment)LDA
최대 수준의 의미적 일관성BERTopic

가장 큰 실무 변수는 문서 길이입니다. BERT 임베딩은 입력을 잘라내고(truncate), LDA의 단어 빈도 방식은 길이에 무관하게 동작합니다. 임베딩 모델의 문맥 길이를 넘는 문서라면 청크(chunk)로 자른 뒤 집계(aggregate)하거나, LDA를 사용해야 합니다.

사용하기

2026년 기준 스택은 다음과 같습니다.

  • BERTopic. 짧은 텍스트나 의미가 중요한 경우의 기본 선택입니다.
  • gensim.models.LdaModel. 실무에서 검증된 고전 LDA 구현입니다.
  • sklearn.decomposition.LatentDirichletAllocation. 실험용으로 간편한 LDA 구현입니다.
  • NMF(Non-negative Matrix Factorization; 비음수 행렬 분해). LDA의 빠른 대안이며, 짧은 텍스트에서는 품질이 비슷합니다.
  • Top2Vec. BERTopic과 유사한 설계입니다. 커뮤니티는 작지만 일부 벤치마크에서 좋은 성능을 보입니다.
  • FASTopic. 비교적 최신 기법으로, 매우 큰 코퍼스에서 BERTopic보다 빠릅니다.
  • LLM 기반 라벨링. 군집화 알고리즘을 돌린 뒤, 각 군집에 이름을 붙이도록 LLM에 프롬프트합니다.

산출물 만들기

다음 내용을 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.

연습문제

  1. 쉬움. 20 Newsgroups 데이터셋에 토픽 5개로 LDA를 학습시킵니다. 토픽별 상위 10개 단어를 출력하고, 사람이 직접 라벨을 붙여봅니다. 알고리즘이 실제 카테고리를 잘 찾아냈는지 비교해봅니다.
  2. 중간. 같은 20 Newsgroups 부분집합에 BERTopic을 학습시킵니다. 찾아낸 토픽 수, 상위 단어, 정성적 일관성을 LDA와 비교합니다. 어느 쪽이 실제 카테고리를 더 깔끔하게 드러내는지 정리합니다.
  3. 어려움. 사용 중인 코퍼스에서 LDA와 BERTopic 각각에 대해 c_v 일관성을 계산합니다. 각 방법을 5, 10, 20, 50개의 토픽으로 돌려본 뒤 토픽 수 대비 일관성 그래프를 그립니다. 어느 방법이 토픽 수 변화에 더 안정적인지 보고합니다.

핵심 용어

용어흔한 설명실제 의미
토픽(Topic)코퍼스가 다루는 주제단어에 대한 확률 분포(LDA) 또는 유사한 문서들의 군집(BERTopic)입니다.
혼합 소속(Mixed membership)문서가 여러 토픽에 속함LDA가 각 문서에 모든 토픽에 대한 분포를 할당하는 것을 가리킵니다.
UMAP(Uniform Manifold Approximation and Projection)차원 축소국소 구조를 보존하는 매니폴드(manifold) 학습 기법이며, BERTopic에서 사용됩니다.
HDBSCAN(Hierarchical Density-Based Spatial Clustering of Applications with Noise)밀도 기반 군집화가변 크기 군집을 찾고, 이상치에 "잡음(noise)" 라벨(-1)을 부여합니다.
c_v 일관성(c_v coherence)토픽 품질 지표상위 토픽 단어들 사이의 점별 상호정보량(pointwise mutual information)을 슬라이딩 윈도우 안에서 평균한 값입니다.

더 읽을거리

실습 코드

이 강의의 실습 코드 1개

main
Code

산출물

이 강의에서 생성된 프롬프트, 스킬, 코드 산출물 1개

topic-picker

Pick LDA or BERTopic for a corpus. Specify library, knobs, evaluation.

Skill

확인 문제

3문제 · 모두 맞추면 완료 표시가 가능합니다

1.BERTopic은 HDBSCAN 전에 UMAP을 사용합니다. 원시 BERT 임베딩(embedding)을 바로 군집화하지 않고 차원 축소(dimensionality reduction)를 거치는 이유는 무엇인가요?

2.같은 고객 지원 티켓 코퍼스에 LDA와 BERTopic을 각각 적용했습니다. LDA의 토픽 일관성(c_v coherence)이 더 높지만, BERTopic의 상위 단어를 읽어보면 더 의미 있어 보입니다. 이 불일치를 설명하는 것은 무엇인가요?

3.평균 12개 토큰의 트윗 100,000건으로 이루어진 코퍼스에 대해 LDA와 BERTopic 중 하나를 선택해야 하는데 GPU가 없습니다. 어떤 것이 더 나은 선택이고 그 이유는 무엇인가요?

0/3 답변 완료

추가 문제 풀기

AI가 강의 내용을 바탕으로 새로운 문제를 생성합니다