使用LLM嵌入和HDBSCAN對非結構化文本進行聚類
本文介紹瞭如何結合大語言模型嵌入和HDBSCAN密度聚類算法,構建文本聚類管道,自動發現未標註文本數據中的主題。包括使用預訓練模型生成嵌入、UMAP降維、HDBSCAN聚類及可視化。
在當前的生成式AI熱潮中,人們往往關注聊天界面和提示詞,但大語言模型(LLM)的應用遠不止於此。其最強大的能力之一是將原始、雜亂的非結構化文本轉化為語義豐富的數學表示——嵌入。隨後,這些文本表示可用於各種機器學習任務,聚類便是其中之一。
特別是,嵌入可以與HDBSCAN等高級密度聚類技術結合,從而發現文本集合中的隱藏主題、模式或類別,無需預先標註。本文將從零開始構建一個基於文本的聚類管道,使用免費數據集和開源嵌入模型,並藉助Python庫實現。
逐步實現
首先,安裝必要的Python庫:sentence-transformers用於加載預訓練LLM生成嵌入,umap-learn用於降維。此外,還需要scikit-learn和pandas。
!pip install sentence-transformers umap-learn接着,獲取數據。使用fetch_20newsgroups函數加載新聞組數據集,並篩選出三個類別(sci.space、sci.med、rec.autos)的150個樣本。注意,儘管數據集包含標籤,但我們將其忽略,以模擬真實聚類場景。
import pandas as pd
from sklearn.datasets import fetch_20newsgroups
categories = ['sci.space', 'sci.med', 'rec.autos']
newsgroups = fetch_20newsgroups(subset='train', categories=categories, remove=('headers', 'footers', 'quotes'))
df = pd.DataFrame({'text': newsgroups.data, 'true_label': newsgroups.target})
df = df[df['text'].str.strip().str.len() > 100].sample(150, random_state=42).reset_index(drop=True)
print(f"Loaded {len(df)} text documents.")然後,使用all-MiniLM-L6-v2模型生成嵌入。這是一個輕量級但高效的模型。
from sentence_transformers import SentenceTransformer
model = SentenceTransformer('all-MiniLM-L6-v2')
embeddings = model.encode(df['text'].tolist(), show_progress_bar=True)
print(f"Embedding matrix shape: {embeddings.shape}")嵌入維度較高,需要降維。採用UMAP將維度降至5,同時保留足夠的信息。
import umap
reducer = umap.UMAP(n_neighbors=15, n_components=5, min_dist=0.0, random_state=42)
reduced_embeddings = reducer.fit_transform(embeddings)
print(f"Reduced matrix shape: {reduced_embeddings.shape}")降維後,應用HDBSCAN聚類。設置最小簇大小為8,最小樣本數為3。
from sklearn.cluster import HDBSCAN
clusterer = HDBSCAN(min_cluster_size=8, min_samples=3, store_centers='centroid')
df['cluster'] = clusterer.fit_predict(reduced_embeddings)
cluster_counts = df['cluster'].value_counts()
print("Cluster Distribution:")
print(cluster_counts)結果發現兩個簇,分別對應不同主題。通過檢查樣本文本,可知簇0主要涉及空間和醫學話題,簇1主要涉及汽車話題。
為了進一步可視化,可以繪製各維度組合的散點圖。
import matplotlib.pyplot as plt
import seaborn as sns
import itertools
reduced_df = pd.DataFrame(reduced_embeddings, columns=[f'UMAP_D{i+1}' for i in range(reduced_embeddings.shape[1])])
reduced_df['cluster'] = df['cluster']
dim_pairs = list(itertools.combinations(reduced_df.columns[:-1], 2))
num_plots = len(dim_pairs)
num_cols = 3
num_rows = (num_plots + num_cols - 1) // num_cols
plt.figure(figsize=(num_cols * 5, num_rows * 4))
for i, (dim1, dim2) in enumerate(dim_pairs):
plt.subplot(num_rows, num_cols, i + 1)
sns.scatterplot(x=dim1, y=dim2, hue='cluster', data=reduced_df, palette='viridis', s=70, alpha=0.7)
plt.title(f'{dim1} vs {dim2}')
plt.grid(True, linestyle='--', alpha=0.6)
plt.tight_layout()
plt.show()總結
通過將LLM嵌入與HDBSCAN結合,我們可以有效捕捉文本的語義信息,自動確定聚類數量,並識別噪聲點。這種方法適用於多種無監督文本分析任務。