Неконтролируемое обучение — кластеризация

Кластеризация среднего сдвига — это неконтролируемый метод машинного обучения для группировки схожих точек данных. Алгоритм среднего сдвига работает, назначая каждую точку данных кластеру на основе плотности точек вокруг нее, а затем сдвигая каждую точку данных на среднее значение назначенного ей кластера. Этот метод кластеризации может быть полезен для выявления кластеров данных, которые нелегко разделить с помощью других методов.

Как это работает?

Алгоритм среднего сдвига работает, назначая каждую точку данных кластеру, а затем итеративно перемещая центроиды кластера («среднее значение» кластера) к среднему значению всех точек данных, назначенных этому кластеру, до тех пор, пока центроиды кластера больше не перестанут двигаться. Это приводит к кластерам, в которых все точки данных более или менее «смещены» к центроиду кластера.

Когда мы должны использовать среднее смещение?

Кластеризация среднего сдвига не делает никаких предположений о форме распределения данных. Это делает его очень гибким методом, который можно адаптировать к сложным нелинейным распределениям данных. Кроме того, кластеризация по среднему сдвигу не требует от пользователя указания количества искомых кластеров, что может быть полезно в ситуациях, когда количество кластеров заранее неизвестно.

Однако важно отметить, что кластеризация среднего сдвига не гарантирует, что она найдет глобальные оптимумы для данного набора данных. Другими словами, возможно, что могут быть другие кластеризации данных, которые лучше, чем та, которая найдена по среднему сдвигу. Однако во многих случаях кластеризация среднего сдвига позволяет найти хорошую кластеризацию данных, и по этой причине она часто используется на практике.

Попробуем на примере!

Мы будем использовать набор данных о качестве белого вина, который можно найти здесь. Вы можете загрузить его в свой блокнот Google Colab и начать с кода:

#Import libraries:
import pandas as pd
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt

#Load and read data frame:
df = pd.read_csv('/content/winequality-white.csv', delimiter=';')
df

У нас есть 4898 точек данных и 12 функций. Следующим шагом является проверка значений NAN и типов данных, чтобы при необходимости внести какие-либо исправления:

#Check NAN values in df:
count_nan = df.isnull().sum()
print('Number of NaN values present: \n' + str(count_nan))

#Check data types:
print(df.dtypes)

Теперь мы преобразуем и масштабируем наши данные:

from sklearn.preprocessing import StandardScaler

#Define X as numpy array:
X = np.array(df)

scaler = StandardScaler()
X = scaler.fit_transform(X)

И пришло время построить нашу модель:

from sklearn.cluster import MeanShift, estimate_bandwidth
from sklearn import metrics

# The following bandwidth can be automatically detected using
bandwidth = estimate_bandwidth(X, quantile=0.6, n_samples=100)

#Fit the model:
ms = MeanShift(bandwidth=bandwidth, cluster_all=True, max_iter=10000)
ms.fit(X)
labels = ms.labels_
cluster_centers = ms.cluster_centers_

labels_unique = np.unique(labels)
n_clusters_ = len(labels_unique)

print("number of estimated clusters : %d" % n_clusters_)

Вы можете использовать параметр пропускная способностьиквантиль, чтобы управлять количеством кластеров. Чем ниже квантильный параметр, тем больше количество кластеров. Теперь, когда у нас есть модель, мы можем сохранить результаты в новую переменную:

#Create new variable and new data-frame:
df_ms = np.array(ms.labels_)
df_ms = pd.DataFrame(df_ms, columns = ['ms'])

#Merge dataframes:
df = pd.concat([df, df_ms], axis=1, join='inner')

Последним шагом является построение графической визуализации нашей модели. Мы попробуем и 2D-, и 3D-визуализацию, но у нас есть кластер, который значительно больше, чем другие, поэтому это может привести к некоторой путанице:

import matplotlib.pyplot as plt
from itertools import cycle

plt.figure(1)
plt.clf()

colors = cycle("bgrcmykbgrcmykbgrcmykbgrcmyk")
for k, col in zip(range(n_clusters_), colors):
    my_members = labels == k
    cluster_center = cluster_centers[k]
    plt.plot(X[my_members, 0], X[my_members, 1], col + ".")
    plt.plot(
        cluster_center[0],
        cluster_center[1],
        "o",
        markerfacecolor=col,
        markeredgecolor="k",
        markersize=14,
    )
plt.title("Estimated number of clusters: %d" % n_clusters_)
plt.show()

Другой вариант 2D-визуализации:

plt.scatter(X[labels==0, 0], X[labels==0, 1], s=50, marker='o', color='purple', label = 'Cluster 1')
plt.scatter(X[labels==1, 0], X[labels==1, 1], s=50, marker='o', color='orange', label = 'Cluster 2')
plt.scatter(X[labels==2, 0], X[labels==2, 1], s=50, marker='o', color='lightblue', label = 'Cluster 3')
plt.scatter(X[labels==3, 0], X[labels==3, 1], s=50, marker='o', color='red', label = 'Cluster 4')
plt.scatter(X[labels==4, 0], X[labels==4, 1], s=50, marker='o', color='lightgreen', label = 'Cluster 5')
plt.scatter(X[labels==5, 0], X[labels==5, 1], s=50, marker='o', color='lightcoral', label = 'Cluster 6')
plt.scatter(X[labels==6, 0], X[labels==6, 1], s=50, marker='o', color='grey', label = 'Cluster 7')

plt.legend()  
plt.show()

И, наконец, мы можем попробовать 3D-визуализацию:

fig = plt.figure()
  
ax = fig.add_subplot(111, projection ='3d')

ax.scatter(X[labels==0, 0], X[labels==0, 1], s=50, marker='o', color='purple', label = 'Cluster 1')
ax.scatter(X[labels==1, 0], X[labels==1, 1], s=50, marker='o', color='orange', label = 'Cluster 2')
ax.scatter(X[labels==2, 0], X[labels==2, 1], s=50, marker='o', color='lightblue', label = 'Cluster 3')
ax.scatter(X[labels==3, 0], X[labels==3, 1], s=50, marker='o', color='red', label = 'Cluster 4')
ax.scatter(X[labels==4, 0], X[labels==4, 1], s=50, marker='o', color='lightgreen', label = 'Cluster 5')
ax.scatter(X[labels==5, 0], X[labels==5, 1], s=50, marker='o', color='lightcoral', label = 'Cluster 6')
ax.scatter(X[labels==6, 0], X[labels==6, 1], s=50, marker='o', color='grey', label = 'Cluster 7')

  
plt.show()

Спасибо за чтение! Дайте мне знать, если у вас есть предложения, которые можно добавить в этот урок, и не забудьте подписаться, чтобы получать уведомления о моих будущих публикациях.

Если: вам понравилась эта статья, не забудьте подписаться на меня и, таким образом, получать все обновления о новых публикациях.

Иначе Если: вы хотите больше узнать о Medium, вы можете подписаться на членство в Medium с помощью моя реферальная ссылка. Это не будет стоить вам больше, но заплатит мне за кофе.

Еще: Спасибо!