跳转至

473_文本聚类方法


一句话说明

文本聚类是在没有标签的情况下,自动把相似文本归为一组的无监督学习方法,常用于话题发现、文档整理、用户意图分析。


核心知识点

  • 表示方式:TF-IDF稀疏向量 或 BERT/Sentence-BERT语义密集向量
  • 聚类算法:K-Means(指定簇数)、DBSCAN(自动发现噪声)、层次聚类
  • 降维可视化:PCA / t-SNE / UMAP 将高维向量压缩到2D便于观察
  • 评估指标
  • 有标签:ARI(调整兰德指数)、NMI
  • 无标签:轮廓系数(Silhouette Score)、Davies-Bouldin Index

经典方法对比

方法特点需指定K噪声处理
K-Means快速、球形簇假设不支持
DBSCAN任意形状、自动噪声支持
层次聚类可视树状图可后验选不支持
BERTopic语义主题建模自动支持
GMM软聚类(概率)

代码示例

# 基于 Sentence-BERT + K-Means 的文本语义聚类

from sentence_transformers import SentenceTransformer
from sklearn.cluster import KMeans, DBSCAN
from sklearn.metrics import silhouette_score
from sklearn.decomposition import PCA
import numpy as np
import matplotlib.pyplot as plt

# ---- 1. 文本数据 ----
texts = [
    "深度学习在图像识别中的应用",
    "卷积神经网络识别猫和狗",
    "自然语言处理的最新进展",
    "BERT模型在文本分类中的效果",
    "股票市场今日大跌",
    "央行调整利率政策",
    "足球世界杯冠军赛回顾",
    "篮球NBA季后赛精彩片段",
]

# ---- 2. 用 Sentence-BERT 生成语义向量 ----
# Sentence-BERT专为句子级别语义相似度设计,比直接用BERT的[CLS]好
model = SentenceTransformer('paraphrase-multilingual-MiniLM-L12-v2')
embeddings = model.encode(texts, show_progress_bar=True)
# embeddings.shape: (8, 384)  每条文本一个384维向量
print(f"向量形状: {embeddings.shape}")

# ---- 3. K-Means 聚类 ----
n_clusters = 3  # 先假设有3个话题
kmeans = KMeans(n_clusters=n_clusters, random_state=42, n_init=10)
labels = kmeans.fit_predict(embeddings)  # 每个文本的簇标签

for text, label in zip(texts, labels):
    print(f"[簇{label}] {text}")

# ---- 4. 用轮廓系数选最优K ----
silhouette_scores = []
k_range = range(2, 6)  # 尝试K=2到5
for k in k_range:
    km = KMeans(n_clusters=k, random_state=42, n_init=10)
    lbs = km.fit_predict(embeddings)
    score = silhouette_score(embeddings, lbs)  # 越接近1越好
    silhouette_scores.append(score)
    print(f"K={k}: Silhouette={score:.4f}")

best_k = k_range[np.argmax(silhouette_scores)]
print(f"最优K: {best_k}")

# ---- 5. 降维可视化(PCA到2D)----
pca = PCA(n_components=2)
embeddings_2d = pca.fit_transform(embeddings)  # (8, 2)

plt.figure(figsize=(8, 6))
colors = ['red', 'blue', 'green', 'orange', 'purple']
for i, (x, y) in enumerate(embeddings_2d):
    plt.scatter(x, y, c=colors[labels[i]], s=100)
    plt.annotate(texts[i][:10], (x, y), fontsize=8)
plt.title('文本聚类可视化(PCA降维)')
plt.savefig('text_cluster.png', dpi=100)

# ---- 6. BERTopic 主题建模(推荐!)----
# pip install bertopic
# from bertopic import BERTopic
# topic_model = BERTopic(language="multilingual", min_topic_size=2)
# topics, probs = topic_model.fit_transform(texts)
# topic_model.get_topic_info()  # 查看每个主题的关键词

# ---- 7. DBSCAN(无需指定K,自动发现噪声)----
dbscan = DBSCAN(eps=0.5, min_samples=2, metric='cosine')
db_labels = dbscan.fit_predict(embeddings)
# -1 表示噪声点(不属于任何簇)
print("DBSCAN簇标签:", db_labels)

面试常问点

  1. K-Means的缺点是什么?
  2. 需预先指定K;对初始化敏感;只适合球形、等大小簇

  3. Sentence-BERT相比BERT直接编码好在哪?

  4. 专门针对句子相似度优化(对比学习训练),语义表示更准确

  5. 如何确定最优聚类数K?

  6. 肘部法则(Elbow):SSE随K减少,找"弯折"点
  7. 轮廓系数:K=1时无意义,找最大轮廓系数对应的K

  8. 文本聚类在实际业务中的应用?

  9. 用户评论自动分组、客服工单意图分类、新闻话题发现

速查表

任务方案
快速原型TF-IDF + K-Means
语义聚类Sentence-BERT + K-Means
自动话题数BERTopic
有噪声数据DBSCAN
可视化UMAP降维 + matplotlib