Как подобрать модель кластеризации и оценить её качество?

«Как подобрать модель кластеризации и оценить её качество?» — вопрос из категории Классическое ML, который задают на 26% собеседований Data Scientist / ML Инженер. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Подбор модели кластеризации — итеративный процесс, который включает выбор алгоритма, определение оптимального числа кластеров и оценку результата.

1. Выбор алгоритма: Зависит от структуры данных и задачи.

  • K-Means / K-Medoids: Для сферических кластеров примерно одинакового размера. Чувствителен к выбросам.
  • DBSCAN: Для кластеров произвольной формы и обнаружения шума (выбросов). Не требует задания числа кластеров.
  • Agglomerative Clustering (иерархическая): Для построения дендрограммы и анализа иерархии кластеров.
  • Gaussian Mixture Models (GMM): Для кластеров, имеющих форму эллипсоидов (мягкая кластеризация с вероятностями принадлежности).

2. Определение числа кластеров (для K-Means):

  • Метод локтя (Elbow Method): Ищем "изгиб" на графике зависимости инерции (within-cluster sum of squares) от числа кластеров.
  • Силуэтный анализ (Silhouette Analysis): Выбираем число кластеров, максимизирующее средний силуэтный коэффициент (от -1 до 1).

3. Оценка качества кластеризации:

Внутренние метрики (нет истинных меток):

  • Silhouette Score: Оценивает, насколько объект похож на свой кластер по сравнению с другими кластерами. Ближе к 1 — лучше.
  • Индекс Дэвиса-Боулдина (DBI): Оценивает среднее сходство между кластерами. Ближе к 0 — лучше.
  • Индекс Калински-Харабаса (CHI): Отношение межкластерной дисперсии к внутрикластерной. Выше — лучше.

Внешние метрики (есть истинные метки):

  • Adjusted Rand Index (ARI): Измеряет сходство двух кластеризаций с поправкой на случайность. От -1 до 1.
  • Normalized Mutual Information (NMI): Измеряет взаимную информацию между кластеризациями, нормализованную по энтропии. От 0 до 1.

Практический пример с K-Means и силуэтным анализом:

import numpy as np
import matplotlib.pyplot as plt
from sklearn.cluster import KMeans
from sklearn.datasets import make_blobs
from sklearn.metrics import silhouette_score, davies_bouldin_score

# Генерация синтетических данных
X, y_true = make_blobs(n_samples=300, centers=4, cluster_std=0.6, random_state=42)

# Подбор числа кластеров методом локтя и силуэта
inertia = []
silhouette_scores = []
K_range = range(2, 11)

for k in K_range:
    kmeans = KMeans(n_clusters=k, random_state=42, n_init='auto').fit(X)
    inertia.append(kmeans.inertia_)
    silhouette_scores.append(silhouette_score(X, kmeans.labels_))

# Визуализация
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(12, 4))
ax1.plot(K_range, inertia, 'bo-')
ax1.set_title('Метод локтя')
ax1.set_xlabel('Число кластеров')
ax1.set_ylabel('Инерция')

ax2.plot(K_range, silhouette_scores, 'ro-')
ax2.set_title('Силуэтный анализ')
ax2.set_xlabel('Число кластеров')
ax2.set_ylabel('Силуэтный коэффициент')
plt.show()

# Обучение финальной модели с выбранным k=4
best_k = 4
final_model = KMeans(n_clusters=best_k, random_state=42, n_init='auto').fit(X)
labels = final_model.labels_

# Оценка
print(f"Silhouette Score: {silhouette_score(X, labels):.3f}")
print(f"Davies-Bouldin Index: {davies_bouldin_score(X, labels):.3f}")