Навчання моделі кластеризації даних — задача, з якою стикаються при сегментації клієнтів або аналізі текстів. Алгоритми 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 тижні консультацій.
Отримайте консультацію по вашому проекту — ми підберемо оптимальний алгоритм та налаштуємо пайплайн під ваші дані. Замовте навчання моделі кластеризації з гарантією якості.
Детальніше про кластерний аналіз.







