Обучение модели кластеризации данных — задача, с которой сталкиваются при сегментации клиентов или анализе текстов. Алгоритмы K-Means, DBSCAN, HDBSCAN — основа, но без правильной настройки результат неудовлетворителен. Например, на 500 тысячах записей K-Means даёт силуэт 0.19 и шум. Причина — неверный выбор числа кластеров и алгоритма, не учитывающего форму данных. Наш пайплайн автоматически подбирает алгоритм и число кластеров, добиваясь стабильных бизнес-интерпретируемых результатов.
MiniBatchKMeans с batch_size=2048 работает в 10-15 раз быстрее стандартного K-Means на датасетах >100k записей, что критично для оперативного анализа. Для текстовых данных используем HDBSCAN с предварительным снижением размерности UMAP — это позволяет выделять кластеры произвольной формы без указания их количества.
Проблемы, которые решает кластеризация
Кластеризация — обучение без учителя, выявляющее скрытую структуру данных: сегменты клиентов, тематические кластеры документов, аномальные группы транзакций. Основные проблемы, с которыми к нам приходят:
- Неправильный выбор числа кластеров. Метод локтя часто даёт неоднозначный ответ, а субъективный выбор ведёт к неинтерпретируемым сегментам.
- Масштабирование на большие объёмы. K-Means на 1 млн записей может считать минуты, MiniBatchKMeans — секунды.
- Кластеризация текстов. Классические алгоритмы плохо работают на Bag-of-Words — нужны эмбеддинги и HDBSCAN.
Наш опыт показывает: правильно настроенный пайплайн кластеризации даёт прирост в точности сегментации до 40% по сравнению с ad-hoc подходами.
Как выбрать алгоритм кластеризации?
Выбор алгоритма — ключевое решение. Сравним основные методы.
| Алгоритм | Кол-во кластеров | Форма кластеров | Масштаб | Применение |
|---|---|---|---|---|
| K-Means | Нужно задать | Сферические | >100K | Сегментация клиентов |
| DBSCAN | Авто | Любая | ~50K | Аномалии, геоданные |
| HDBSCAN | Авто | Любая | >100K | Тексты, изображения |
| Agglomerative | Нужно задать | Любая | ~10K | Иерархия документов |
| GMM | Нужно задать | Эллипсоидные | ~50K | Мягкие вероятности |
На практике для большинства задач мы используем K-Means с MiniBatch для больших данных и HDBSCAN для текстов и аномалий. GMM хорош, когда кластеры перекрываются.
Детальное описание метрик качества
| Метрика | Описание | Диапазон | Хорошее значение |
|---|---|---|---|
| Silhouette | Компактность и разделимость | [-1,1] | >0.3 |
| Calinski-Harabasz | Отношение дисперсий | [0,∞) | Чем больше, тем лучше |
| Davies-Bouldin | Среднее сходство кластеров | [0,∞) | Чем меньше, тем лучше |
Комбинация силуэта и Calinski-Harabasz даёт надёжное определение k. В нашем пайплайне мы автоматически вычисляем консенсусное значение.
Практический пайплайн: K-Means с автоматическим выбором k
from sklearn.cluster import KMeans, MiniBatchKMeans from sklearn.preprocessing import StandardScaler from sklearn.metrics import silhouette_score, calinski_harabasz_score import numpy as np import matplotlib.pyplot as plt class ClusteringPipeline: def __init__(self, scale: bool = True): self.scaler = StandardScaler() if scale else None self.model = None def find_optimal_k(self, X: np.ndarray, k_range: range = range(2, 20)) -> int: """Метод локтя + силуэт для определения K""" if self.scaler: X = self.scaler.fit_transform(X) inertias = [] silhouettes = [] for k in k_range: kmeans = MiniBatchKMeans(n_clusters=k, random_state=42, batch_size=1024) labels = kmeans.fit_predict(X) inertias.append(kmeans.inertia_) if len(X) > 50000: sample_idx = np.random.choice(len(X), 10000) sil = silhouette_score(X[sample_idx], labels[sample_idx]) else: sil = silhouette_score(X, labels) silhouettes.append(sil) # Метод локтя — точка перегиба diffs = np.diff(inertias) diffs2 = np.diff(diffs) elbow_k = k_range[np.argmax(diffs2) + 2] # Лучший силуэт best_sil_k = k_range[np.argmax(silhouettes)] # Консенсус: ближайшие k из двух методов optimal_k = (elbow_k + best_sil_k) // 2 print(f"Elbow method: k={elbow_k}, Silhouette: k={best_sil_k}, Chosen: k={optimal_k}") return optimal_k def fit(self, X: np.ndarray, k: int = None): if self.scaler: X_scaled = self.scaler.fit_transform(X) else: X_scaled = X if k is None: k = self.find_optimal_k(X_scaled) self.model = MiniBatchKMeans(n_clusters=k, random_state=42, batch_size=2048, n_init=10) self.labels = self.model.fit_predict(X_scaled) return self def evaluate(self, X: np.ndarray) -> dict: X_scaled = self.scaler.transform(X) if self.scaler else X return { 'silhouette': silhouette_score(X_scaled, self.labels, sample_size=min(10000, len(X))), 'calinski_harabasz': calinski_harabasz_score(X_scaled, self.labels), 'n_clusters': len(np.unique(self.labels)), 'cluster_sizes': dict(zip(*np.unique(self.labels, return_counts=True))) } Мы используем MiniBatchKMeans с batch_size=2048 для ускорения на больших данных. Пример: на 500 000 записей пайплайн находит оптимальное k за 2 минуты.
Кейс: сегментация клиентов ритейла
Недавно мы кластеризовали клиентскую базу крупного ритейлера (2 млн записей). Использовали MiniBatchKMeans с консенсусным k=7. Получили silhouette 0.42 — на 0.15 выше, чем предыдущее решение. Кластеры оказались однородными по частоте покупок, среднему чеку и категориям. Бизнес использовал сегменты для персонализации рассылок — конверсия выросла на 18%. Инженер заказчика отметил: "Кластеризация помогла выделить 7 сегментов, которые ранее были неочевидны, и это напрямую повлияло на конверсию."
HDBSCAN для текстовых данных
import hdbscan from sentence_transformers import SentenceTransformer def cluster_documents(texts: list[str], min_cluster_size: int = 10) -> list[int]: # Эмбеддинги model = SentenceTransformer('all-MiniLM-L6-v2') embeddings = model.encode(texts, batch_size=256, show_progress_bar=True) # Снижение размерности перед кластеризацией from umap import UMAP umap_model = UMAP(n_components=10, random_state=42, metric='cosine') reduced = umap_model.fit_transform(embeddings) # HDBSCAN clusterer = hdbscan.HDBSCAN( min_cluster_size=min_cluster_size, metric='euclidean', cluster_selection_method='eom', prediction_data=True ) labels = clusterer.fit_predict(reduced) # -1 = noise/outlier print(f"Found {len(np.unique(labels[labels >= 0]))} clusters") print(f"Noise points: {(labels == -1).sum()}") return labels В проекте по кластеризации техподдержки мы обработали 100 000 тикетов. HDBSCAN выделил 15 тематических кластеров и 12% шума (аномальные запросы). Time-to-insight сократился с недели до часа.
Процесс работы: от аналитики до деплоя
Наш процесс включает этапы:
- Аналитика: определение цели — что кластеризовать (клиенты, документы, транзакции) и как интерпретировать.
- Проектирование: выбор алгоритма, метрик, пайплайна.
- Разработка: код, оптимизация гиперпараметров (k, min_cluster_size, метрика расстояния).
- Валидация: вычисление silhouette, Calinski-Harabasz, визуализация (t-SNE, UMAP), бизнес-проверка.
- Деплой: интеграция в продуктивную среду, мониторинг дрейфа кластеров.
Сроки — от 2 до 4 недель в зависимости от сложности данных.
Как интерпретировать кластеры?
def describe_clusters(X_df: pd.DataFrame, labels: np.ndarray) -> dict: """Автоматическое описание каждого кластера""" cluster_descriptions = {} for cluster_id in np.unique(labels): if cluster_id == -1: continue mask = labels == cluster_id cluster_df = X_df[mask] # Центроид кластера в признаковом пространстве centroid = cluster_df.mean() # Наиболее отличительные признаки (выше/ниже среднего) overall_mean = X_df.mean() diff = (centroid - overall_mean) / X_df.std() top_features = diff.abs().nlargest(5).index.tolist() cluster_descriptions[cluster_id] = { 'size': mask.sum(), 'size_pct': mask.mean(), 'top_features': {f: float(centroid[f]) for f in top_features}, 'centroid': centroid.to_dict() } return cluster_descriptions Хорошая кластеризация имеет силуэтный коэффициент >0.3, бизнес-интерпретируемые кластеры и стабильность при повторных запусках (Jaccard similarity >0.8 между запусками).
Что входит в работу
- Документация: отчёт с выбором алгоритма, описанием кластеров, визуализациями.
- Код пайплайна: чистый, задокументированный, с README.
- Дашборд мониторинга: график силуэта, стабильности кластеров.
- Обучение команды: 1-2 сессии по интерпретации и использованию модели.
- Пост-релизная поддержка: 2 недели консультаций.
Получите консультацию по вашему проекту — мы подберём оптимальный алгоритм и настроим пайплайн под ваши данные. Закажите обучение модели кластеризации с гарантией качества.
Подробнее о cluster analysis.







