Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Кластеризация

🎯 Цель

После прочтения этой главы:

  • Поймёте, что такое unsupervised learning и clustering
  • Узнаете разницу между алгоритмами K-Means, DBSCAN, Hierarchical
  • Узнаете методы поиска оптимального числа кластеров
  • Сможете применить в реальных бизнес-проектах вроде customer segmentation

Что нужно изучить

  • K-Means — самый простой и распространённый
  • K-Means++ — хорошая initialization
  • MiniBatchKMeans — для больших datasets
  • DBSCAN — density-based, произвольная форма
  • Hierarchical Clustering — agglomerative, dendrogram
  • Gaussian Mixture Models (GMM) — soft clustering
  • Mean Shift, OPTICS — альтернативы
  • Выбор числа кластеров — Elbow method, Silhouette score
  • Визуализация — в 2D через PCA, t-SNE, UMAP

Библиотеки

pip install scikit-learn umap-learn yellowbrick
  • scikit-learn — основные алгоритмы
  • umap-learn — dimensionality reduction (быстрее и точнее t-SNE)
  • yellowbrick — ML-визуализации (Elbow, Silhouette)

Важные темы

Когда нужен Clustering?

  • Customer segmentation — группировка клиентов (для маркетинга)
  • Anomaly detection — какие точки не подходят ни в одну группу
  • Document grouping — поиск похожих текстов
  • Image compression — кластеризация цветов
  • Feature engineering — cluster ID как новый feature

Алгоритм K-Means

1. K ta tasodifiy markaz (centroid) tanlash
2. Har nuqtani eng yaqin centroidga assign qilish
3. Centroidlarni o'rta arifmetik bilan yangilash
4. Konvergentsiyaga qadar 2-3 qadamlarini takrorlash

Ограничения:

  • Нужно заранее знать K
  • Только сферические clusters
  • Чувствительность к outliers
  • Важно feature scaling

DBSCAN — альтернатива

В отличие от K-Means:

  • K не нужен (автоматически)
  • Cluster произвольной формы
  • Автоматически определяет outliers (noise label -1)
  • 2 параметра: eps (радиус) и min_samples
DBSCAN'da nuqta turlari:
- Core: eps radiusida >= min_samples ta nuqta
- Border: core'ga yaqin lekin o'zi core emas
- Noise: hech bir cluster'ga to'g'ri kelmaydi (outlier)

Поиск оптимального K

1. Elbow method:

Для каждого K считаем inertia (within-cluster sum of squares)
→ ищем точку «изгиба»

2. Silhouette score:

Score = (b - a) / max(a, b)
a = average distance to own cluster
b = average distance to nearest other cluster

Range: [-1, 1]
1 = ajoyib clustering
0 = overlapping clusters
< 0 = noto'g'ri assignment

Примеры кода

K-Means clustering

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

# Искусственные data
X, _ = make_blobs(n_samples=500, centers=4, n_features=2, random_state=42)

# Scale (ВАЖНО — для distance-based алгоритмов)
X_scaled = StandardScaler().fit_transform(X)

# K-Means
kmeans = KMeans(n_clusters=4, n_init=10, random_state=42)
labels = kmeans.fit_predict(X_scaled)

# Silhouette
score = silhouette_score(X_scaled, labels)
print(f"Silhouette Score: {score:.3f}")  # 0.8+ — хорошо

# Визуализация
fig, ax = plt.subplots(figsize=(8, 6))
ax.scatter(X[:, 0], X[:, 1], c=labels, cmap="viridis", s=30)
ax.scatter(*kmeans.cluster_centers_.T, c="red", s=200, marker="X", label="Centroids")
ax.legend()
plt.show()

Elbow method

from yellowbrick.cluster import KElbowVisualizer

model = KMeans(n_init=10, random_state=42)
visualizer = KElbowVisualizer(model, k=(2, 11), metric="distortion")
visualizer.fit(X_scaled)
visualizer.show()
# Автоматически определяет «elbow point»

Silhouette analysis

from sklearn.metrics import silhouette_score

scores = {}
for k in range(2, 11):
    km = KMeans(n_clusters=k, n_init=10, random_state=42)
    labels = km.fit_predict(X_scaled)
    scores[k] = silhouette_score(X_scaled, labels)

best_k = max(scores, key=scores.get)
print(f"Best k: {best_k} (silhouette = {scores[best_k]:.3f})")

DBSCAN

from sklearn.cluster import DBSCAN

dbscan = DBSCAN(eps=0.3, min_samples=10)
labels = dbscan.fit_predict(X_scaled)

n_clusters = len(set(labels)) - (1 if -1 in labels else 0)
n_noise = list(labels).count(-1)
print(f"Clusters: {n_clusters}, Noise points: {n_noise}")

Hierarchical Clustering + Dendrogram

from scipy.cluster.hierarchy import dendrogram, linkage, fcluster
import matplotlib.pyplot as plt

linkage_matrix = linkage(X_scaled, method="ward")

fig, ax = plt.subplots(figsize=(12, 5))
dendrogram(linkage_matrix, truncate_mode="lastp", p=20, leaf_font_size=10, ax=ax)
ax.set_title("Hierarchical Clustering Dendrogram")
plt.show()

# Cut tree по threshold
labels = fcluster(linkage_matrix, t=4, criterion="maxclust")

Customer Segmentation — реальный пример (RFM)

import pandas as pd
from sklearn.cluster import KMeans
from sklearn.preprocessing import StandardScaler

# Искусственные customer data
df = pd.DataFrame({
    "customer_id": range(1000),
    "recency_days": np.random.exponential(30, 1000),
    "frequency": np.random.poisson(5, 1000),
    "monetary": np.random.exponential(500, 1000),
})

# RFM scaling
X = df[["recency_days", "frequency", "monetary"]].copy()
X["recency_days"] = -X["recency_days"]  # less is better → invert
X_scaled = StandardScaler().fit_transform(X)

# Clustering
km = KMeans(n_clusters=4, n_init=10, random_state=42)
df["segment"] = km.fit_predict(X_scaled)

# Итоги сегментов
segment_summary = df.groupby("segment")[["recency_days", "frequency", "monetary"]].mean()
print(segment_summary)
# Бизнес-имена:
# Champions:    low recency, high freq, high monetary
# At Risk:      high recency, low freq, low monetary
# и т.д.

Интеграция с backend

Customer Segmentation API

from fastapi import FastAPI
from pydantic import BaseModel
import joblib
import numpy as np

app = FastAPI()
model_bundle = joblib.load("models/customer_segments.joblib")
# {"kmeans": kmeans, "scaler": scaler, "segment_names": [...]}

class CustomerRFM(BaseModel):
    recency_days: int
    frequency: int
    monetary: float

class SegmentResponse(BaseModel):
    segment_id: int
    segment_name: str
    marketing_action: str

SEGMENT_ACTIONS = {
    0: "Champions — VIP offer",
    1: "At Risk — win-back campaign",
    2: "New — onboarding email",
    3: "Loyal — referral program",
}

@app.post("/segment", response_model=SegmentResponse)
def get_segment(customer: CustomerRFM):
    X = np.array([[-customer.recency_days, customer.frequency, customer.monetary]])
    X_scaled = model_bundle["scaler"].transform(X)
    seg_id = int(model_bundle["kmeans"].predict(X_scaled)[0])
    return SegmentResponse(
        segment_id=seg_id,
        segment_name=model_bundle["segment_names"][seg_id],
        marketing_action=SEGMENT_ACTIONS[seg_id],
    )

Anomaly Detection (DBSCAN)

@app.post("/check-anomaly")
def detect_anomaly(transaction: TransactionData):
    X = np.array([[transaction.amount, transaction.time_of_day, ...]])
    X_scaled = scaler.transform(X)
    
    # DBSCAN re-fit на recent data + новая точка
    cluster = dbscan.fit_predict(np.vstack([recent_data, X_scaled]))[-1]
    
    is_anomaly = cluster == -1
    return {"is_anomaly": is_anomaly, "cluster": int(cluster)}

Ресурсы

🏋️ Упражнения

🟢 Easy

  1. Создайте 3 cluster через make_blobs, classify через K-Means и визуализируйте.
  2. Найдите оптимальный K методом Elbow (K=2..10).
  3. В DBSCAN измените eps (0.1, 0.3, 0.5, 1.0) и посмотрите результат.

🟡 Medium

  1. Загрузите Wholesale Customer dataset (UCI), найдите customer-сегменты через K-Means и интерпретируйте каждый сегмент с бизнес-точки зрения.
  2. Визуализируйте высокоразмерные данные в 2D через t-SNE / UMAP.
  3. Silhouette analysis: нарисуйте silhouette plot для разных k.

🔴 Hard

  1. Segmentation API: production-ready FastAPI-сервис — при поступлении customer RFM data возвращает real-time сегмент, модель retrain каждую неделю (Airflow или cron).
  2. Image color quantization: загрузите изображение и перерисуйте 16 доминантными цветами через K-Means (image compression).

Capstone

notebooks/month-02/03_clustering.ipynb:

  • Mall Customer Segmentation Kaggle dataset
  • EDA → feature selection (Age, Income, Spending Score)
  • Сравнение K-Means, DBSCAN, Hierarchical
  • Поиск оптимального K
  • Бизнес-имена для каждого cluster (Premium, Budget, Young Spenders и т.д.)
  • Написать маркетинговые рекомендации

✅ Чек-лист

  • Знаю разницу между Supervised и Unsupervised
  • Понимаю, как работает алгоритм K-Means
  • Умею искать оптимальный K через Elbow и Silhouette
  • Знаю, когда применить K-Means, а когда DBSCAN
  • Знаю, почему feature scaling важно для clustering
  • Могу применить clustering к реальному бизнес-проекту вроде customer segmentation

Переходим к Feature Engineering.