На этом занятии мы открываем принципиально новый раздел машинного обучения — обучение без учителя (Unsupervised Learning). До сих пор в задачах регрессии и классификации мы всегда имели размеченную обучающую выборку с известным вектором ответов \(y\). Но как извлекать скрытые закономерности, если разметки нет, а ручной труд экспертов невозможен или слишком дорог? Мы подробно изучим базовую задачу этого направления — кластеризацию данных, разберем по шагам популярный метод k-средних (K-Means), поймем логику перемещения центроидов, разберемся в инициализации k-means++ и научимся объективно подбирать оптимальное число кластеров с помощью метода локтя (Elbow Method).
Кластеризация (кластерный анализ) — это задача автоматического разделения множества неразмеченных объектов на группы (кластеры) на основе их признакового описания.
Фундаментальный математический принцип кластеризации строится на двух правилах:
Мысленный эксперимент (Кластеризация как шаг к классификации): Представьте, что вы ботаник Эдгар Андерсон, собравший 150 цветков ириса и измеривший их параметры, но никаких классов еще не существует. Вместо субъективного деления «на глаз» специалист по анализу данных запускает кластеризацию по 4 признакам. Алгоритм делит данные на 3 плотные группы. После этого достаточно взять всего по одному типовому цветку из каждой группы, определить их биологический вид у эксперта и мгновенно присвоить осмысленные метки (Setosa, Versicolor, Virginica) всем сотням объектов сразу.
Основные сферы применения кластеризации в бизнесе и Data Science:
В библиотеке scikit-learn реализовано множество алгоритмов кластеризации, но фундаментальными считаются два противоположных подхода: K-Means (основан на центроидах и сферических расстояниях) и DBSCAN (основан на плотности точек в пространстве). На этом уроке мы фокусируемся на K-Means.
Главная особенность метода K-Means заключается в том, что количество кластеров \(k\) должно быть строго задано до запуска алгоритма.
Каждый кластер описывается своим центром масс — центроидом. Обучение модели заключается в итеративном поиске таких координат центроидов, при которых суммарное квадратичное отклонение объектов от центров своих кластеров будет минимальным.



max_iter.Геометрические допущения K-Means: Алгоритм делит пространство строго сферическими (гиперсферическими) границами одинакового размера (диаграммы Вороного). Если реальные кластеры имеют вытянутую форму, сложную топологию (полумесяцы, кольца) или разную плотность, K-Means разделит их некорректно. Кроме того, K-Means крайне чувствителен к выбросам, так как расчет среднего арифметического сильно смещает центроид в сторону экстремальной точки.

Поскольку стартовые центроиды выбираются случайно, неудачный выбор может затянуть оптимизацию или привести алгоритм в субоптимальный локальный минимум. Scikit-Learn решает эту проблему двумя механизмами:
По умолчанию модель обучается n_init=10 раз с разных случайных стартовых позиций. Из 10 полученных вариантов выбирается разбиение с наименьшей итоговой ошибкой (инерцией). На гигантских массивах данных значение n_init иногда уменьшают ради ускорения вычислений.
Вместо полностью случайного выбора Scikit-Learn по умолчанию использует стратегию init='k-means++':
Такой подход заставляет центроиды гарантированно стартовать в максимально удаленных друг от друга областях признакового пространства, что резко повышает скорость сходимости и устойчивость разбиения.
Проведем кластеризацию датасета Ирисов Фишера по двум признакам (длине и ширине лепестка), принципиально не передавая модели метки классов \(y\):
import matplotlib.pyplot as plt
from sklearn.datasets import load_iris
from sklearn.cluster import KMeans
# 1. Загрузка данных (берем только матрицу признаков X)
iris = load_iris()
X = iris.data[:, 2:] # Длина и ширина лепестка (petal length, petal width)
# 2. Инициализация и обучение K-Means на 3 кластера
kmeans = KMeans(n_clusters=3, init='k-means++', n_init=10, random_state=42)
kmeans.fit(X)
# 3. Получение меток кластеров для обучающих точек
labels = kmeans.labels_
# 4. Координаты найденных центроидов
centroids = kmeans.cluster_centers_
print("Координаты центроидов:\n", centroids)
# 5. Визуализация кластеров и их центров
plt.figure(figsize=(10, 6))
plt.scatter(X[:, 0], X[:, 1], c=labels, cmap='viridis', s=50, alpha=0.8, label='Объекты кластеров')
plt.scatter(centroids[:, 0], centroids[:, 1], c='red', marker='X', s=200, label='Центроиды')
plt.title('Кластеризация Ирисов с помощью K-Means (k=3)')
plt.xlabel('Длина лепестка (см)')
plt.ylabel('Ширина лепестка (см)')
plt.legend()
plt.grid(True)
plt.show()
# 6. Предсказание кластера для нового объекта
new_flower = [[5.0, 1.8]]
predicted_cluster = kmeans.predict(new_flower)
print(f"Новый цветок отнесен к кластеру: {predicted_cluster[0]}")
Обученная модель хранит в оперативной памяти исключительно координаты центроидов (атрибут cluster_centers_). При вызове метода predict() для нового объекта алгоритм просто находит ближайший к нему центроид.
В большинстве прикладных задач количество кластеров \(k\) заранее неизвестно. Если выбрать слишком мало кластеров — данные объединятся в разнородную кашу; если слишком много — кластеры распадутся на бессмысленные мелкие осколки (при \(k = N\) каждая точка станет своим кластером с нулевой ошибкой).
Для оценки компактности кластеров используется метрика инерции (Within-Cluster Sum of Squares, WCSS) — сумма квадратов расстояний от каждой точки до центроида своего кластера:
$$ \text{Inertia} = \sum_{j=1}^{k} \sum_{x_i \in S_j} \|x_i – c_j\|^2 $$
В Scikit-Learn значение инерции доступно через атрибут kmeans.inertia_.
# Расчет инерции для k от 1 до 10
inertias = []
k_range = range(1, 11)
for k in k_range:
model = KMeans(n_clusters=k, init='k-means++', n_init=10, random_state=42)
model.fit(X)
inertias.append(model.inertia_)
# Построение графика метода локтя
plt.figure(figsize=(10, 6))
plt.plot(k_range, inertias, 'bo-', linewidth=2, markersize=8)
plt.title('Подбор оптимального k методом локтя (Elbow Method)')
plt.xlabel('Количество кластеров (k)')
plt.ylabel('Инерция (Inertia / WCSS)')
plt.xticks(k_range)
plt.grid(True)
plt.show()

На датасете Ирисов график демонстрирует отчетливый изгиб в районе \(k = 2\) и \(k = 3\), подтверждая объективное разделение выборки на плотные группы без использования внешних подсказок учителя.
n_init: серия независимых перезапусков с отбором лучшего решения.k-means++: вероятностное разнесение стартовых центроидов в пространстве.sklearn.cluster.KMeans на датасете Iris без целевых меток.cluster_centers_.predict().n_clusters.