3.5.2.5. Topic Modelling#

Topic modelling là một nhánh trong Xử lý Ngôn ngữ Tự nhiên (NLP) nhằm tìm ra các chủ đề tiềm ẩn (latent topics) trong một tập văn bản lớn, đại diện cho 1 loại unsupervised learning trong NLP

Ý tưởng cốt lõi là: các văn bản thường có thể được mô tả bằng một số lượng hạn chế các chủ đề chính, và mỗi văn bản phản ánh các chủ đề đó với các trọng số (mức độ) khác nhau. Mục tiêu của topic modelling là tự động “phân loại” những văn bản này vào các chủ đề hoặc xác định được các chủ đề chính trong một tập dữ liệu lớn mà không cần gán nhãn trước.


Khi nào nên sử dụng topic modelling?

  • Khám phá dữ liệu (Exploratory Analysis): Khi bạn có một lượng văn bản lớn mà chưa biết rõ nội dung chính hay các nhóm chủ đề tiềm ẩn, topic modelling giúp bạn hình dung bức tranh tổng quan.

  • Phân nhóm tài liệu: Khi bạn muốn phân nhóm các văn bản theo chủ đề để tiện cho quá trình quản lý, tìm kiếm, hoặc truy xuất thông tin.

    • VOC labeling

    • Social Listening

  • Trích xuất từ khóa / insight: Khi bạn muốn tóm tắt hoặc tìm các “từ khóa” nổi bật trong từng nhóm chủ đề nhằm phục vụ cho việc phân tích hoặc báo cáo.

  • Tiền xử lý cho các bài toán khác: Thông tin về chủ đề có thể được sử dụng làm đặc trưng (features) cho các bài toán máy học khác, ví dụ: phân loại văn bản, khuyến nghị nội dung, hoặc phân tích cảm xúc.


Các phương pháp phổ biến trong topic modelling

  • Latent Dirichlet Allocation (LDA):

    Đây là phương pháp được sử dụng rất rộng rãi. Ý tưởng chính: giả định mỗi tài liệu (document) là tổ hợp của các chủ đề, và mỗi chủ đề là một phân phối xác suất trên các từ vựng. Thông qua quá trình huấn luyện, LDA ước lượng xem mỗi tài liệu chứa những chủ đề nào và mỗi chủ đề chứa những từ nào với trọng số bao nhiêu.

  • Latent Semantic Analysis (LSA) / Latent Semantic Indexing (LSI):

    Dựa trên kỹ thuật phân rã ma trận (thường là SVD). Mỗi tài liệu được biểu diễn dưới dạng vector “bag-of-words” (hoặc TF-IDF), sau đó giảm chiều để tìm “khoảng không gian ngữ nghĩa” ẩn. LSA/LSI cũng có thể được sử dụng để tìm các chủ đề tiềm ẩn, tuy nhiên thường không ràng buộc các chủ đề và từ theo kiểu phân phối xác suất như LDA.

  • Non-negative Matrix Factorization (NMF):

    Tương tự ý tưởng phân rã ma trận nhưng thêm ràng buộc “không âm” (non-negative). Vì vậy, các chủ đề NMF thường có diễn giải tương đối rõ ràng hơn (mỗi chủ đề là sự kết hợp cộng tuyến tính của các từ, không cho phép giá trị âm).

  • Neural Topic Modelling (chủ đề dựa trên mạng nơ-ron):

    Ví dụ: Neural Variational Document Model (NVDM) hay những mô hình deep learning khác. Chúng sử dụng mạng nơ-ron để học phân phối chủ đề ẩn trong tài liệu. Có tiềm năng thể hiện tốt với các dữ liệu lớn, phức tạp.

  • BERT-based Topic Modelling:

    Áp dụng các mô hình ngôn ngữ dựa trên Transformer như BERT để tạo embedding cho câu/từ. Sau đó, tiến hành clustering hoặc áp dụng các thuật toán phân nhóm khác lên embedding này để suy ra chủ đề.


Cách xác định số lượng chủ đề (number of topics)

Việc chọn số lượng chủ đề phù hợp rất quan trọng, vì số lượng chủ đề quá ít hoặc quá nhiều đều có thể làm giảm chất lượng phân tích. Một số phương pháp phổ biến để ước lượng “tối ưu”:

  • Dựa trên kinh nghiệm / domain knowledge

    • Nếu bạn đã biết trước lĩnh vực nội dung hoặc mang tính chuyên ngành, bạn có thể ước lượng số lượng chủ đề hợp lý dựa vào kinh nghiệm.

  • Dùng metric đánh giá (Perplexity, Coherence, Silhouette Score, v.v.)

    • Coherence score (C_v, UMass, v.v.) phổ biến trong đánh giá LDA. Ý tưởng: tính mức độ liên quan giữa các từ cùng chủ đề, hoặc giữa từ trong chủ đề với các tài liệu.

    • Perplexity thường được sử dụng cho các mô hình xác suất (vd. LDA), mặc dù nó không phải lúc nào cũng tương quan tốt với chất lượng “giải thích” của chủ đề.

    • Elbow method áp dụng cho một số kỹ thuật như NMF, spectral clustering, K-means (trong trường hợp clustering embedding).

    • Grid search (hoặc iterative search) với các mô hình topic modelling

  • Huấn luyện nhiều mô hình với số lượng chủ đề khác nhau (k = 5, 10, 15, 20, …) và quan sát sự thay đổi của các chỉ số đánh giá (coherence, perplexity, …).

    • Chọn k có chỉ số đánh giá tốt nhất hoặc đạt điểm cân bằng giữa giải thích được và tính gọn nhẹ.

    • Trong thực tế, kết hợp cả đánh giá định lượng và định tính (xem xét sự “giải thích được” của chủ đề) là cách tối ưu.

3.5.2.5.1. Kết hợp mô hình truyền thống và transformer#

1. Vì sao phương pháp truyền thống (LDA, NMF…) vẫn còn giá trị?

  • Nhẹ, dễ triển khai: LDA, NMF triển khai tương đối gọn (thư viện Gensim, sklearn, …), không đòi hỏi hạ tầng GPU hay cấu hình quá cao.

  • Tính giải thích (interpretability) rõ ràng:

    • Mỗi chủ đề là một phân phối xác suất của từ; dễ quan sát “top words” và gán nhãn.

    • Các tổ chức, doanh nghiệp trong lĩnh vực cần khả năng giải thích (compliance, pháp lý…) có thể ưu tiên LDA/NMF.

  • Phù hợp dữ liệu vừa và nhỏ: Khi dữ liệu không quá lớn, hoặc chủ đề không quá phức tạp, LDA/NMF vẫn đem lại kết quả chấp nhận được, nhanh và ổn định.

  • Đánh giá/ so sánh dễ dàng: Có sẵn các chỉ số như perplexity, coherence (C_v, UMass, …) và bộ công cụ phân tích.


2. Lợi ích và hạn chế của tiếp cận transformer-based

Lợi ích

  • Hiểu ngữ cảnh tốt hơn: Các mô hình (BERT, PhoBERT, GPT, …) bắt được mối quan hệ ngữ nghĩa sâu hơn so với bag-of-words truyền thống.

  • Hiệu quả với ngôn ngữ phức tạp / nhiều ngôn ngữ: Đặc biệt khi văn bản dài, từ vựng phong phú, hoặc nhiều biến thể.

  • Chất lượng chủ đề thường tốt hơn (cụm từ, ngữ nghĩa phức tạp) nếu được huấn luyện/ fine-tune phù hợp.

Hạn chế

  • Chi phí tính toán cao: Cần GPU, tài nguyên lớn hơn so với LDA/NMF.

  • Khó giải thích: Transformer-based embedding đôi khi khó “truy ngược” được vì sao model nhóm văn bản đó vào một cụm; phải trích xuất top words thủ công thông qua các thống kê tần suất kết hợp (chứ không phải xác suất hiển thị rõ như LDA).

  • Phụ thuộc mô hình nền: Chọn sai mô hình embedding, hoặc model chưa fine-tune cho domain → kết quả chưa tối ưu.


3. Best Practice thực tế hiện nay

  • Chọn phương pháp theo “bài toán” và “tài nguyên”:

    • Nếu dữ liệu nhỏ hoặc vừa phải, yêu cầu giải thích cao, và tài nguyên hạn chế → LDA / NMF vẫn là lựa chọn hiệu quả.

    • Nếu dữ liệu lớn, mang tính đa dạng và cần nắm bắt ngữ nghĩa sâu, bạn sẵn sàng đầu tư hạ tầng → hướng transformer-based (BERTopic, Top2Vec, v.v.).

  • Kết hợp cả hai:

    • Dùng embedding transformer để rút gọn chiều, sau đó chạy LDA trên vector (thay vì chạy LDA trên bag-of-words). Tuy không phổ biến bằng “transformer + clustering”, nhưng cũng là một hướng.

  • Bảo đảm pipeline “chuẩn”:

    • Tiền xử lý: Với tiếng Việt, tách từ (Underthesea, PyVi…); với tiếng Anh, spaCy/NLTK. Lọc stopwords phù hợp.

    • Sinh embedding (nếu dùng transformer) hoặc TF-IDF (nếu LDA/NMF).

    • Giảm chiều (UMAP/PCA) → Phân cụm (K-means, HDBSCAN…).

    • Trích xuất top words để đặt tên chủ đề, đánh giá coherence.

    • Kiểm tra thủ công trên các văn bản đại diện.

  • Chú trọng đánh giá định tính (qualitative):

    Dù dùng LDA hay BERT, vẫn nên xem xét thủ công một số văn bản trong cụm; vì chỉ số (coherence, silhouette…) cũng có thể chưa phản ánh hết.

  • Cân nhắc domain adaptation / fine-tuning (nếu dùng mô hình embedding):

    • Đối với những ngữ cảnh chuyên ngành (y tế, tài chính, …), pretrained “chung” của BERT có thể không tối ưu.

    • Có thể fine-tune nhẹ (MLM, TSDAE, …) hoặc chọn mô hình domain-specific (BioBERT, FinBERT, PhoBERT news,…).

3.5.2.5.2. Chuẩn bị và tiền xử lý dữ liệu#

1. Dọn dẹp, chuẩn hóa (cleaning, normalization):

  • Loại bỏ ký tự đặc biệt, link, HTML tag, …

  • Xử lý chính tả, chuyển về chữ thường (nếu phù hợp).

  • Tùy theo ngôn ngữ (tiếng Anh, tiếng Việt, …) sử dụng tokenizer phù hợp. Ví dụ:

    • Tiếng Anh: spaCy, NLTK, …

    • Tiếng Việt: Underthesea, PyVi, RDRsegmenter… (để tách từ).

2. (Nếu cần) Tách câu hoặc chia nhỏ văn bản lớn:

  • Một bài báo quá dài có thể chia thành từng đoạn hoặc từng câu để embedding hiệu quả. Sau đó, có thể nhóm các đoạn/câu đó theo một cơ chế trung bình để đại diện toàn văn bản (hoặc áp dụng tiếp cận topic modelling trực tiếp trên từng đoạn/câu, rồi gộp lại).

3. Loại bỏ stopwords/ từ ít thông tin:

  • Tùy ngôn ngữ, cần một danh sách stopwords chất lượng.

  • Tuy nhiên, với tiếp cận embedding transformer, đôi khi những từ này không tác động tiêu cực nhiều như mô hình bag-of-words, nhưng vẫn nên cân nhắc lọc bớt “noise”.

import pandas as pd
df = pd.read_csv(r"data\105 - news-articles.csv")
df.head()
id title content
0 25626 One Weight-Loss Approach Fits All? No, Not Eve... Dr. Frank Sacks, a professor of nutrition at H...
1 19551 South Carolina Stuns Baylor to Reach the Round... South Carolina’s win over Duke was not only ...
2 25221 U.S. Presidential Race, Apple, Gene Wilder: Yo... (Want to get this briefing by email? Here’s th...
3 18026 His Predecessor Gone, Gambia’s New President F... BANJUL, Gambia — A week after he was inaugu...
4 21063 ‘Harry Potter and the Cursed Child’ Goes From ... The biggest book of the summer isn’t a blockbu...

Preprocessing

import nltk
from nltk.corpus import stopwords
from nltk.tokenize import word_tokenize
import string
from nltk.stem import WordNetLemmatizer

# Gộp title + content nếu muốn (ở đây ví dụ gộp chung để phân tích toàn văn bản)
df["text"] = df["title"].astype(str) + " " + df["content"].astype(str)

# Tải stopwords nếu chưa có
nltk.download("stopwords")
nltk.download("punkt")

stop_words = set(stopwords.words("english"))
lmtz = WordNetLemmatizer()


def preprocess_text(text):
    # Chuyển về chữ thường
    text = text.lower()
    # Tokenize
    tokens = word_tokenize(text)
    # Loại bỏ dấu câu, từ rỗng và ký tự không cần thiết + lemmatize
    tokens = [
        lmtz.lemmatize(t)
        for t in tokens
        if t not in stop_words and t not in string.punctuation
    ]
    return tokens


# Áp dụng cho toàn bộ dữ liệu
df["tokens"] = df["text"].apply(preprocess_text)

3.5.2.5.3. Sinh embedding từ mô hình Transformer#

2.1. Chọn mô hình gốc (pretrained model)

  • Tiếng Anh: BERT-base, RoBERTa-base, Sentence-BERT (SBERT), v.v.

  • Tiếng Việt: PhoBERT, xlm-roberta-base (đa ngôn ngữ), hoặc các mô hình vibert4news,…

Lưu ý:

  • Với dữ liệu chuyên ngành, nếu có domain-specific model (VD: mô hình cho y khoa, pháp luật, tài chính), bạn nên sử dụng để embedding phản ánh ngữ nghĩa chính xác hơn.

  • Có thể cân nhắc fine-tune nhẹ mô hình trên dữ liệu gốc (unsupervised domain adaptation) để cải thiện độ phù hợp.

2.2. Chiến lược lấy embedding

  • Sentence embedding:

    • Ví dụ dùng Sentence-BERT (SBERT) – mô hình được huấn luyện đặc biệt để sinh embedding câu, cho kết quả tốt hơn so với BERT “raw”.

    • Nếu mô hình không được tối ưu cho sentence embedding, có thể dùng pooling (mean pooling, CLS token) từ layer cuối/ trung gian của BERT.

  • Document embedding:

    • Nếu mỗi “bài” rất dài, có thể chia thành nhiều đoạn/câu, rồi lấy trung bình (average pooling), hoặc dùng mô hình hierarchical.

from sentence_transformers import SentenceTransformer

# Chọn 1 mô hình sentence-BERT cho tiếng Anh
model_name = "all-MiniLM-L6-v2"
model_sbert = SentenceTransformer(model_name)

# Chuyển mỗi văn bản (đã preprocessing) thành chuỗi để embedding
docs = df["text"].tolist()

# Sinh embeddings (mỗi doc -> vector 384 chiều cho 'all-MiniLM-L6-v2')
embeddings = model_sbert.encode(docs, show_progress_bar=True)
# (Tuỳ chọn) Giảm chiều để clustering tốt hơn: Dùng UMAP để giảm từ 384 chiều → 10, 15… (tuỳ ý).
import umap

reducer = umap.UMAP(n_neighbors=40, n_components=10, random_state=42)
reduced_embeddings = reducer.fit_transform(embeddings)

3.5.2.5.4. Phân cụm#

# K-means (cần biết trước số cụm):

from sklearn.cluster import KMeans

k = 5  # giả định muốn 5 cụm
kmeans = KMeans(n_clusters=k, random_state=42)
kmeans.fit(reduced_embeddings)
cluster_labels = kmeans.labels_
# HDBSCAN (tự động xác định số cụm dựa trên mật độ):

import hdbscan

clusterer = hdbscan.HDBSCAN(min_cluster_size=10, gen_min_span_tree=True)
cluster_labels = clusterer.fit_predict(reduced_embeddings)
# Gán mỗi document vào cụm / chủ đề
df["cluster"] = cluster_labels
print(df[["id", "title", "cluster"]].head())
      id                                              title  cluster
0  25626  One Weight-Loss Approach Fits All? No, Not Eve...        0
1  19551  South Carolina Stuns Baylor to Reach the Round...        4
2  25221  U.S. Presidential Race, Apple, Gene Wilder: Yo...        2
3  18026  His Predecessor Gone, Gambia’s New President F...        1
4  21063  ‘Harry Potter and the Cursed Child’ Goes From ...        3

3.5.2.5.5. Trích xuất từ khoá đại diện cho từng cụm#

  • Cách nhanh: Đếm tần suất từ (hoặc TF-IDF) trong mỗi cụm.

  • Hoặc: Sử dụng BERTopic – nó tự động thực hiện bước này.

# Trích xuất từ khoá đại diện cho từng cụm
from collections import Counter, defaultdict

cluster_texts = defaultdict(list)

for cluster_id, text_tokens in zip(df["cluster"], df["tokens"]):
    cluster_texts[cluster_id].extend(text_tokens)

for c in sorted(cluster_texts.keys()):
    word_freq = Counter(cluster_texts[c])
    top_words = [w for w, _ in word_freq.most_common(10)]
    print(f"Cụm {c}: {top_words}")
Cụm 0: ['’', '“', '”', 'said', 'mr.', '—', 'would', 'dr.', 'one', 'company']
Cụm 1: ['’', '“', '”', 'said', 'mr.', 'state', '—', 'year', 'united', 'one']
Cụm 2: ['’', 'mr.', '“', '”', 'trump', 'said', '—', 'president', 'new', 'would']
Cụm 3: ['’', '“', '”', 'mr.', 'said', '—', 'new', 'time', 'show', 'song']
Cụm 4: ['’', '“', '”', 'said', 'new', 'mr.', 'ms.', '—', 'would', 'time']
  • Nếu c == -1 (HDBSCAN): là outlier.

  • Từ list top_words, bạn có thể đặt nhãn (ví dụ “Embeddings & BERT” / “LDA topic modeling”, …).