Занятие 9
Лабораторная 9¶
import numpy as np
import matplotlib.pyplot as plt
from sklearn.datasets import make_blobs
from scipy.cluster.hierarchy import dendrogram, linkage
from sklearn.datasets import make_circles
from sklearn.cluster import AgglomerativeClustering
from sklearn.cluster import KMeans
from sklearn.cluster import DBSCAN
from sklearn.metrics import silhouette_score
1.1 Постановка задачи кластеризации¶
Дано:
$X$ - пространство объектов
$X^l$ - обучающая выборка
$\rho: X * X -> [0;\infty)$ - функция расстояния между объектами
Найти:
$Y$ - множество кластеров
$a : X -> Y$ - алгоритм кластеризации
При этом кластеры должны иметь следующии свойства:
- объекты одного кластера должны быть похожи
- объекты разных кластеров должны отличаться
Задача кластеризация — это задача обучения без учителя. В данной задаче у нас нет обучающей выборки и нет ответов(классов).
1.2 Проблема задачи кластеризации¶
Рассмотрим простой пример. У нас есть выборка из 300 экземпляров. Сколько здесь кластеров? Мы легко можем увидеть, что здесь присутствует 4 кластера.
# Генерация случайных данных
X, _ = make_blobs(n_samples=300, centers=4, cluster_std=0.30, random_state=0)
# Визуализация результатов
plt.scatter(X[:, 0], X[:, 1])
plt.show()
Рассмотрим более сложный пример. Сколько здесь кластеров? Возможно здесь 2, 3, 5 кластеров, а может быть ещё больше?.
# Генерация случайных данных
X, _ = make_blobs(n_samples=300, centers=5, cluster_std=1.0, random_state=0)
# Визуализация результатов
plt.scatter(X[:, 0], X[:, 1])
plt.show()
Рассмотрим ещё один пример. Сколько здесь кластеров? Здесь вообще есть кластеры?
# Генерация случайных данных
X, _ = make_blobs(n_samples=300, centers=6, cluster_std=2, random_state=0)
# Визуализация результатов
plt.scatter(X[:, 0], X[:, 1])
plt.show()
Данные примеры показывают одну из проблем задачи классификации - решение задачи кластеризации неоднозначно. Это связано с рядом причин:
- Количество кластеров неизвестно.
- Результат кластеризации сильно зависит от выбранной метрики.
- Нет единого критерия оценки качества кластеризации.
- Существует большое разнообразие методов кластеризации, не все из которых имеют строгое теоретическое обоснование.
1.3 Цели задачи кластеризации¶
Упрошение данных: Кластеризация может помочь разбить данные на несколько кластеров, что позволит работать с каждым кластером по отдельности.
Анализ аномалий: Кластеризация может помочь выявить аномальные или необычные объекты в данных путем выделения кластеров, содержащих малое количество объектов.
Сжатие данных: Кластеризация может использоваться для уменьшения размерности данных путем замены экземпляров кластеров на их центры.
Построение иерархии: С помощью кластеризации можно построить иерархию данных.
Существует несколько методов решения задачи кластеризации:
- K-средних (K-means): Этот метод разбивает данные на заранее заданное количество кластеров (K) и минимизирует среднее расстояние между объектами и их центрами в каждом кластере.
- Иерархическая кластеризация: Этот метод строит иерархию кластеров, начиная с того, что каждый объект начинает как отдельный кластер, и затем объединяет их постепенно в более крупные кластеры.
- DBSCAN: Этот метод основан на плотности данных и способен обнаруживать кластеры произвольной формы.
2.1 Метод K-средних¶
Процесс работы метода K-средних можно описать следующим образом:
Инициализация центров: Сначала выбираются K случайных объектов из набора данных в качестве центра каждого кластера. Это означает, что мы предполагаем наличие K кластеров.
Присвоение объектов к ближайшим центрам: Каждый объект назначается к одному из K кластеров на основе ближайшего расстояния до центра кластера.
Пересчет центров: Для каждого кластера вычисляется новый центр.
Повторение шагов 2 и 3: Шаги 2 и 3 повторяются до тех пор пока центры кластеров не перестанут изменяться или будут меняться незначительно.
Конец: По завершении работы алгоритма каждый объект назначен к одному из K кластеров.
Рассмотрим пример работы данного алгоритма.
# Наши данные
X, _ = make_blobs(n_samples=300, centers=3, cluster_std=1.0, random_state=0)
# Инициализация центров случайным образом
k = 3
np.random.seed(0)
centroids = X[np.random.choice(X.shape[0], k, replace=False)]
# Алгоритм
max_iterations = 10
for _ in range(max_iterations):
# Шаг 1: Присвоение объектов к ближайшим центроидам
distances = np.sqrt(((X - centroids[:, np.newaxis])**2).sum(axis=2))
labels = np.argmin(distances, axis=0)
# Визуализация текущих кластеров
plt.figure()
plt.scatter(X[:, 0], X[:, 1], c=labels, cmap='plasma', s=50, alpha=0.5)
plt.scatter(centroids[:, 0], centroids[:, 1], c='black', s=200, alpha=0.5)
plt.title('Итерация {}'.format(_))
plt.show()
# Шаг 3: Пересчет центров
new_centroids = np.array([X[labels == i].mean(axis=0) for i in range(k)])
centroids = new_centroids
# Шаг 5
plt.figure()
plt.scatter(X[:, 0], X[:, 1], c=labels, cmap='plasma', s=50, alpha=0.5)
plt.scatter(centroids[:, 0], centroids[:, 1], c='black', s=200, alpha=0.5, label='центры')
plt.legend()
plt.title('Финальные результаты')
plt.show()
Мы можем наблюдать, что с каждой новой итерацией центры меняются всё меньше и меньше, и в какой - то момент перестают меняться. В данный момент может возникнуть два вопроса:
- Как выбрать начальные центры?
- Какую метрику использовать?
Ответы:
- Центры нужно выбирать случайным образом из объектов выборки, однако нужно стараться сделать так, чтобы расстояние между случайными объектами(начальными центрами) было большим.
- K-Means работает с Евклидовой метрикой.
2.2 метод K-средних в scikit-learn¶
Конечно же данный метод реализован в scikit-learn.
# Наши данные
X, _ = make_blobs(n_samples=300, centers=3, cluster_std=1.0, random_state=0)
# Применение метода K-средних
kmeans = KMeans(n_clusters=3, random_state=42)
kmeans.fit(X)
y_kmeans = kmeans.predict(X)
# Визуализация результатов
plt.scatter(X[:, 0], X[:, 1], c=y_kmeans, s=50, cmap='viridis')
centers = kmeans.cluster_centers_
plt.scatter(centers[:, 0], centers[:, 1], c='black', s=200, alpha=0.5)
plt.show()
Некоторые из гиперпараметров:
- n_clusters: количество кластеров
- init: метод инициализации начальных центров кластеров (например, "k-means++" или "random").
- n_init: количество запусков алгоритма с разными начальными центрами (по умолчанию 10).
- max_iter: максимальное количество итераций алгоритма в одном запуске (по умолчанию 300).
- tol: критерий остановки - минимальное изменение суммы квадратов в выбранных центрах, при котором алгоритм продолжает итерации.
3.1 Иерархическая кластеризация¶
Иерархическая кластеризация - это метод кластерного анализа, который строит иерархию кластеров. Есть два основных подхода к иерархической кластеризации:
агломеративный (снизу вверх)
дивизивный (сверху вниз)
Иерархическая кластеризация работает следующим образом:
- Создаём столько кластеров, сколько у нас объектов в выборке
- Повторяем итеративно слияние двух ближайших кластеров, пока не выполнится критерий останова.
Тут может возникнуть 2 вопроса:
- Как мы определяем расстояние между двумя кластерами?
- Что является критерием останова?
Ответы:
- Определяем как среднее расстояние между объектами кластеров, минимальное расстояние или максимальное.
- Критерием останова может быть: число кластеров или более сложные эвристики.
3.2 Иерархическая кластеризация в scikit-learn¶
Конечно же данный метод реализован в scikit-learn.
# Генерация синтетических данных
X, _ = make_blobs(n_samples=30, centers=3, cluster_std=0.4, random_state=0)
# Применение иерархической кластеризации
agg_clustering = AgglomerativeClustering(n_clusters=3)
assignment = agg_clustering.fit_predict(X)
# Визуализация результатов
plt.scatter(X[:, 0], X[:, 1], c=assignment, s=50, cmap='viridis')
plt.show()
Кроме того в контексте иерархической кластеризации у нас есть возможность построить Дендрограмму.
Дендрограмма - это диаграмма в виде дерева, которая используется для визуализации иерархической кластеризации. Каждый узел в дендрограмме представляет собой кластер данных или объединение кластеров. Расстояние между точками данных или кластерами соответствует положению узлов на дендрограмме.
На дендрограмме ось Y представляет расстояние или схожесть между кластерами или кластеризуемыми точками данных, а ось X обозначает отдельные точки данных или кластеры.
Дендрограмма позволяет визуализировать процесс иерархической кластеризации и представить информацию об объединении кластеров на различных уровнях иерархии. Участки дендрограммы, где ветви или кластеры соединяются или разделяются, показывают моменты объединения или деления кластеров.
# Генерация синтетических данных
X, _ = make_blobs(n_samples=30, centers=3, cluster_std=0.4, random_state=0)
# Построение матрицы объединения
linked = linkage(X, 'single')
# Визуализация дендрограммы
plt.figure(figsize=(10, 7))
dendrogram(linked,
orientation='top',
distance_sort='descending',
show_leaf_counts=True)
plt.show()
На дендрограмме выше можем наблюдать как начальные кластеры(30 штук) постепенно соединяются в кластеры побольше до тех пор пока не будет образовано 3 кластера.
4.1 DBSCAN (Density-based spatial clustering of applications with noise)¶
DBSCAN (Density-Based Spatial Clustering of Applications with Noise) - метод кластеризации, который может обнаруживать кластеры произвольной формы. Он может обрабатывать шум и не требует заранее заданного числа кластеров.
Все объекты(точки) можно разделить на три типа:
- корневые - точки в окрестности которых есть как минимум некоторое число $N$ точек.
- граничные - точки в окрестности корневой
- шумовые - не корневые и не граничные точки
- Корневые точки, имеющие общую окрестность, соединяются ребрами.
- Таким образом получается граф, в котором выделяются компоненты связности.
- Граничная точка относится к кластеру, в котором содержится наиболее близкая корневая точка для данной граничной точки.
- Шумовые точки отбрасываются.
4.2 DBSCAN в scikit-learn¶
# Генерация синтетических данных
X, _ = make_blobs(n_samples=300, centers=3, cluster_std=0.6, random_state=0)
# Применение DBSCAN
dbscan = DBSCAN()
clusters = dbscan.fit_predict(X)
# Визуализация результатов
plt.scatter(X[:, 0], X[:, 1], c=clusters, cmap='plasma')
plt.show()
Можно наблюдать, что наш алгоритм выделил три кластера и шумовые точки(выделенные синим).
Некоторые из гиперпараметров:
- eps: радиус окрестности вокруг каждой точки.
- min_samples: минимальное количество точек, которые должны находиться в радиусе eps, чтобы точка считалась корневой.
5. Оценка качества кластеризации¶
Существует несколько оценок качества кластеризации:
Среднее внутрикластерное растояние - сумма расстояний между точками из одного и того же кластера делится на количество пар точек, принадлежащих к одному кластеру.
Среднее межкластерное расстояние - среднее расстояние между кластерами.
Очевидно, что чем ниже значение 1, тем лучше. Чем выше значение 2 тем также лучше.
- Оценка силуэта является метрикой, используемой для оценки качества кластеризации. Эта метрика предоставляет меру того, насколько каждый объект хорошо согласуется с своим собственным кластером по сравнению с другими кластерами. Silhouette score вычисляется для каждого объекта, и затем вычисляется среднее значение по всем объектам, чтобы получить общую оценку качества кластеризации.
Значение silhouette score находится в диапазоне от -1 до 1. Высокое значение silhouette score указывает на то, что объекты хорошо согласованы с их собственными кластерами и плохо согласованы с соседними кластерами. Значение близкое к 1 указывает на четкое разделение кластеров, в то время как значение близкое к -1 указывает на перекрытие кластеризации.
Формула для вычисления silhouette score для каждого объекта i выглядит следующим образом:
$s(i) = \frac{b(i) - a(i)}{\max{\{a(i), b(i)\}}}$
- $a(i)$ - среднее расстояние от объекта i до всех остальных точек в том же кластере
- $b(i)$ - минимальное среднее расстояние от объекта i до всех точек в любом другом кластере
# Генерируем синтетические данные
X, _ = make_blobs(n_samples=300, centers=4, cluster_std=0.60, random_state=0)
# Проводим кластеризацию
kmeans = KMeans(n_clusters=4, random_state=10)
labels = kmeans.fit_predict(X)
# Вычисляем silhouette score
silhouette_avg = silhouette_score(X, labels)
print("Silhouette Score:", silhouette_avg)
Задача 1(2,5 балла)¶
- Для заданных данных произведите кластеризацию с помощью Kmeans на 1,2 ... 12 кластеров.
- Постройте график зависимости оценки силуэта от числа кластеров.
- Найдите набор гиперпараметров n_clusters, tol, init при котором достигается максимум оценки силуэта.
# Генерируем синтетические данные
X, _ = make_blobs(n_samples=1000, centers=6, cluster_std=0.80, random_state=0)
Задача 2(2,5 балла)¶
- Для заданных данных произведите кластеризацию с помощью иерархической кластеризация на 1,2 ... 12 кластеров.
- Постройте график зависимости оценки силуэта от числа кластеров.
# Генерируем синтетические данные
X, _ = make_blobs(n_samples=1000, centers=6, cluster_std=0.80, random_state=0)
Задача 3(2,5 балла)¶
- Для заданных данных произведите кластеризацию с помощью DBSCAN.
- Найдите набор гиперпараметров eps, min_samples при котором достигается максимум оценки силуэта.
# Генерируем синтетические данные
X, _ = make_blobs(n_samples=1000, centers=6, cluster_std=0.80, random_state=0)
Задача 4(2,5 балла)¶
Что лучше работает на данном датасете? Алгоритм Kmeans или DBSCAN?
import numpy as np
import matplotlib.pyplot as plt
from sklearn.datasets import make_moons
# Генерируем синтетические данные с двумя полумесяцами
X, _ = make_circles(n_samples=400, factor=0.5, noise=0.05, random_state=42)
# Визуализируем данные
plt.figure(figsize=(8, 6))
plt.scatter(X[:, 0], X[:, 1], c='black', marker='o', edgecolors='k')
plt.title('Синтетический набор данных')
plt.xlabel('Признак 1')
plt.ylabel('Признак 2')
plt.show()