Вступление

В этом посте мы рассмотрим несколько случаев, когда алгоритм KMC не работает должным образом или может давать неинтуитивные результаты. В частности, мы рассмотрим следующие сценарии:

  1. Наше предположение о количестве (реальных) кластеров неверно.
  2. Пространство функций очень размерно.
  3. Грозди бывают странной или неправильной формы.

Все эти условия могут привести к проблемам с K-средними, так что давайте посмотрим.

Неправильное количество кластеров

Чтобы упростить задачу, давайте определим вспомогательную функцию compare, которая создаст и решит для нас проблему кластеризации, а затем сравнит результаты.

from sklearn import datasets
from sklearn.cluster import KMeans
from sklearn.datasets import make_blobs, make_circles, make_moons
from mpl_toolkits.mplot3d import Axes3D

import numpy as np
import pandas as pd
import itertools


def compare(N_features, C_centers, K_clusters, dims=[0, 1],*args):
    data, targets = make_blobs(
      n_samples=n_samples if 'n_samples' in args else 400,
      n_features=N_features,
      centers=C_centers,
      cluster_std=cluster_std if 'cluster_std' in args else 0.5,
      shuffle=True,
      random_state=random_state if 'random_state' in args else 0)

    FEATS = ['x' + str(x) for x in range(N_features)]
    X = pd.DataFrame(data, columns=FEATS)
    X['cluster'] = \
		KMeans(n_clusters=K_clusters, random_state=0).fit_predict(X)

    fig, axs = plt.subplots(1, 2, figsize=(12, 4))
    axs[0].scatter(data[:, dims[0]], data[:, dims[1]],
        c='white', marker='o', edgecolor='black', s=20)
    axs[0].set_xlabel('x{} [a.u.]'.format(dims[0]))
    axs[0].set_ylabel('x{} [a.u.]'.format(dims[1]))
    axs[0].set_title('Original dataset')
    axs[1].set_xlabel('x{} [a.u.]'.format(dims[0]))
    axs[1].set_ylabel('x{} [a.u.]'.format(dims[1]))
    axs[1].set_title('Applying clustering')

    colors = itertools.cycle(['r', 'g', 'b', 'm', 'c', 'y'])
    for k in range(K_clusters):
        x = X[X['cluster'] == k][FEATS].to_numpy()
        axs[1].scatter(
		x[:, dims[0]], 
		x[:, dims[1]], 
		color=next(colors),
		edgecolor='k', 
		alpha=0.5
	)
    plt.show()

Слишком мало кластеров

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

Слишком много кластеров

В отличие от последней ситуации, попытка обернуть данные в слишком много кластеров создает искусственные границы внутри реальных кластеров данных.

Данные с высокими (er) габаритами

Набор данных не обязательно должен быть таким высоким по размерам, прежде чем мы начнем замечать проблемы. Хотя визуализация и, таким образом, некоторый анализ многомерных данных уже является сложной задачей (теперь ругайтесь…), поскольку KMC часто используется для понимания данных, это не помогает из-за двусмысленности.

Чтобы объяснить суть проблемы, давайте сгенерируем трехмерный набор данных с четко различимыми кластерами.

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

data, targets = make_blobs(
    n_samples=400,
    n_features=3,
    centers=3,
    cluster_std=0.5,
    shuffle=True,
    random_state=0)

ax.scatter(data[:, 0], data[:, 1], 
    zs=data[:, 2], zdir='z', s=25, c='black', depthshade=True)
ax.set_xlabel('x0 [a.u.]')
ax.set_ylabel('x1 [a.u.]')
ax.set_zlabel('x2 [a.u.]')
ax.set_title('Original distribution.')
plt.grid()
plt.show()

Хотя существует бесконечно много способов спроецировать этот набор 3D-данных на 2D, существует три основных ортогональных подпространства:

Глядя на проекцию x2 : x0, набор данных выглядит так, как будто в нем всего два кластера. Нижнее правое «сверхскопление», по сути, представляет собой две отдельные группы, и даже если мы угадываем K справа (K = 3), это выглядит как очевидная ошибка, несмотря на кластеры очень локализованы.

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

В этом больше смысла!

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

В случае N, N ›3 функций мы не сможем отобразить весь набор данных, а количество 2D-проекций будет масштабироваться квадратично с N :

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

Нерегулярные наборы данных

Пока мы говорили о проблемах, которые «на нашей стороне». Мы рассмотрели очень хорошо подготовленный набор данных и обсудили проблемы со стороны аналитики. Однако что делать, если набор данных не соответствует нашему решению или наше решение не соответствует задаче? Это именно тот случай, когда распределение данных имеет странные или неправильные формы.

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

fig, axs = plt.subplots(1, 3, figsize=(14, 4))

# unequal variance
X, y = make_blobs(n_samples=1400,
    cluster_std=[1.0, 2.5, 0.2],
    random_state=2)
y_pred = KMeans(n_clusters=3, random_state=2).fit_predict(X)
colors = [['r', 'g', 'b'][c] for c in y_pred]

axs[0].scatter(X[:, 0], X[:, 1], 
	color=colors, edgecolor='k', alpha=0.5)
axs[0].set_title("Unequal Variance")

# anisotropically distributed data
X, y = make_blobs(n_samples=1400, random_state=156)
transformation = [
	[0.60834549, -0.63667341],
	[-0.40887718, 0.85253229]
]
X = np.dot(X, transformation)
y_pred = KMeans(n_clusters=3, random_state=0).fit_predict(X)
colors = [['r', 'g', 'b'][c] for c in y_pred]

axs[1].scatter(X[:, 0], X[:, 1], 
	color=colors, edgecolor='k', alpha=0.5)
axs[1].set_title("Anisotropicly Distributed Blobs")

# irregular shaped data
X, y = make_moons(n_samples=1400, shuffle=True, 
	noise=0.1, random_state=120)
y_pred = KMeans(n_clusters=2, random_state=0).fit_predict(X)
colors = [['r', 'g', 'b'][c] for c in y_pred]

axs[2].scatter(X[:, 0], X[:, 1], 
	color=colors, edgecolor='k', alpha=0.5)
axs[2].set_title("Irregular Shaped Data")

plt.show()

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

В любом случае из-за неправильности алгоритм KMC работает неэффективно. Поскольку алгоритм обрабатывает каждую точку данных одинаково и полностью независимо от других точек, алгоритм не может определить любую возможную непрерывность или локальные вариации в кластере. Он просто берет одни и те же показатели и применяет их к каждой точке. В результате алгоритм KMC может производить странную или противоречащую интуиции кластеризацию данных, даже если мы правильно угадываем K, а функций N не так много.

Выводы

В этом посте мы обсудили три основные причины, по которым алгоритм кластеризации K-средних дает нам неправильные ответы.

  • Во-первых, поскольку количество кластеров K необходимо определить априори, высока вероятность того, что мы угадываем его неверно.
  • Во-вторых, кластеризация в пространстве более высоких измерений становится обременительной с точки зрения аналитики, и в этом случае KMC предоставит нам информацию, которая может ввести в заблуждение.
  • Наконец, для любых данных неправильной формы KMC, скорее всего, создаст искусственные кластеры, не соответствующие здравому смыслу.

Зная эти три заблуждения, KMC по-прежнему является полезным инструментом, особенно при проверке данных или создании меток.

Там будет больше…

Я планирую вывести статьи на новый уровень и предложить короткие видеоуроки в виде скринкастов.

Если вы хотите быть в курсе видео и будущих статей, подпишитесь на мою рассылку новостей. Вы также можете сообщить мне о своих ожиданиях, заполнив форму. До скорого!

Первоначально опубликовано на https://zerowithdot.com.