Кластеризация - очень сложная проблема, потому что никогда не бывает по-настоящему «правильного» ответа, когда ярлыки не существуют.

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

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

Справочная информация: кластеризация - сложная задача 😬

Для алгоритмов кластеризации нет бесплатного обеда, и хотя один алгоритм может хорошо соответствовать определенному набору данных, нет никаких гарантий, что он будет работать с другим набором данных точно так же. Точно так же кластеризация сильно зависит от контекста, целей и решений исследователя, что добавляет огня аргументу о том, что не существует такой вещи, как универсально оптимальный метод, который будет просто производить естественные кластеры, как отмечает Хеннинг в What are Истинные кластеры? Хеннинг 2015 .

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

Кластерные данные, противоречащие предположениям, вызывают у практикующего специалиста двоякую головоломку:

  1. Как оформить конкретную схему индивидуализации?
  2. Какую технику кластеризации выбрать?

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

Будьте осторожны с вашей метрикой 📈

Когда метки недоступны, обычно выбирают объективную метрику, такую ​​как Силуэтный балл, для оценки, а затем определяют окончательный результат кластеризации. Silhouette Score измеряет связность и разделение кластеров с индексом от -1 до 1. Он НЕ учитывает шум при вычислении индекса и использует расстояния. Расстояние не применимо для метода, основанного на плотности. Отсутствие шума в вычислении объективной метрики нарушает внутреннее предположение кластеризации на основе плотности.

На помощь приходит проверка кластеризации на основе плотности 🌈

Проверка кластеризации на основе плотности или DBCV работает для алгоритмов кластеризации на основе плотности именно потому, что она учитывает шум и фиксирует свойство формы кластеров через плотности, а не расстояния (см. Исходный документ)

Как поясняется в документе, окончательный результат DBCV представляет собой взвешенную сумму значений «индекса достоверности» кластеров. Это дает оценку от -1 до 1, причем чем больше значение, тем лучше решение для кластеризации.

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

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

Однако, помимо меток Groundtruth, он предоставляет объективные критерии, по которым можно судить о том, насколько хорошо разделены кластеры техники на основе плотности.

Реальный пример 🚀

Хватит, давайте рассмотрим реальный пример.

Блокнот доступен в библиотеке Amazon Denseclus.

В этом примере вы будете использовать синтетический набор данных об оттоке для воображаемой телекоммуникационной компании с результатом Отток? помечено как Истина (отток) или Ложь (не отток). Функции включают сведения о клиенте, такие как план и информация об использовании. Набор данных об оттоке общедоступен и упоминается в книге Discovering Knowledge in Data by Daniel T. Larose. Автор приписывает его репозиторию наборов данных машинного обучения в Ирвине Калифорнийского университета.

Данные включают как числовые, так и категориальные особенности, но будут использовать Denseclus для преобразования их в более низкое, плотное пространство для формирования кластеров. Подробнее о DenseClus см. Здесь. Все необходимые преобразования выполняются под капотом. Просто позвони fit.

# This runs in about a minute or two
from denseclus import DenseClus

import logging # to further silence deprecation warnings

logging.captureWarnings(True)
clf = DenseClus(
    random_state=SEED,
    umap_combine_method="intersection_union_mapper"
)

clf.fit(df)

Под капотом, среди прочего, Denseclus использует HDBSCAN для кластеризации данных.

Давайте посмотрим, как разделились данные.

embedding = clf.mapper_.embedding_
labels = clf.score()
clustered = (labels >= 0)

cnts = pd.DataFrame(labels)[0].value_counts()
cnts = cnts.reset_index()
cnts.columns = ['cluster','count']
print(cnts.sort_values(['cluster']))
cluster  count
4       -1      9
3        0   1234
0        1   1265
1        2   1253
2        3   1239

При исследовании обнаруживается ровно 4 почти равномерно распределенных кластера, где -1 представляет шум, обнаруженный в данных.

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

_=sns.jointplot(
    x=embedding[clustered, 0], y=embedding[clustered, 1], hue=labels[clustered], kind="kde"
)

Как видите, внутри этого фрагмента данных сформировано 4 отдельных острова. Вокруг этих плотностей сформировались кластеры, что является именно тем поведением, которое мы ожидаем от DenseClus.

Вы можете дополнительно подтвердить результат, построив дерево, по которому были разделены плотности.

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

_=clf.hdbscan_.condensed_tree_.plot(
    select_clusters=True,
    selection_palette=sns.color_palette("deep", np.unique(clusters).shape[0]),
)

Наконец, давайте подтвердим, что большинство точек данных охватываются нашими кластерами (подсказка: нет только 9) и оценкой DBCV.

coverage = np.sum(clustered) / embedding.shape[0]

print(f"Coverage {coverage}")
print(f"DBCV score {clf.hdbscan_.relative_validity_}")
Coverage 0.9982
DBCV score 0.2811143727637039

DBCV составляет 0,28 по шкале от -1 до 1.

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

Настройка гиперпараметров 🦾

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

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

В дополнение к рассмотрению этих гиперпараметров вы также рассмотрите методы выбора кластера с ожиданием массы и разбиение кластеров по дереву с листом (подробности см. В hdbscan: Hierarchical density based clustering In, McInnes, J. Healy, S. Astels 2017 ).

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

Это приводит к более мелким и однородным кластерам, которые с большей вероятностью будут мелкозернистыми.

from sklearn.model_selection import RandomizedSearchCV
import hdbscan
from sklearn.metrics import make_scorer


logging.captureWarnings(True)
hdb = hdbscan.HDBSCAN(gen_min_span_tree=True).fit(embedding)

# specify parameters and distributions to sample from
param_dist = {'min_samples': [10,30,50,60,100],
              'min_cluster_size':[100,200,300,400,500,600],  
              'cluster_selection_method' : ['eom','leaf'],
              'metric' : ['euclidean','manhattan'] 
             }

#validity_scroer = "hdbscan__hdbscan___HDBSCAN__validity_index"
validity_scorer = make_scorer(hdbscan.validity.validity_index,greater_is_better=True)


n_iter_search = 20
random_search = RandomizedSearchCV(hdb
                                   ,param_distributions=param_dist
                                   ,n_iter=n_iter_search
                                   ,scoring=validity_scorer 
                                   ,random_state=SEED)

random_search.fit(embedding)


print(f"Best Parameters {random_search.best_params_}")
print(f"DBCV score :{random_search.best_estimator_.relative_validity_}")
Best Parameters {'min_samples': 100, 'min_cluster_size': 300, 'metric': 'manhattan', 'cluster_selection_method': 'eom'}
DBCV score :0.48886415007392386

Оценка DBCV теперь выросла с 0,28 до 0,488.

DenseClus по умолчанию min_samples на 15 и min_cluster_size на 100. Результаты случайного поиска имеют кластеры большего размера и более строгие, что приводит к более высокой плотности и более высокому баллу :) Расстояние между кварталом или Манхэттеном, похоже, тоже способствует увеличению.

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

Давайте подтвердим это, посмотрев, как были разделены кластеры, и снова визуализировав результаты.

# evalute the clusters
labels = random_search.best_estimator_.labels_
clustered = (labels >= 0)
    
coverage = np.sum(clustered) / embedding.shape[0]
total_clusters = np.max(labels) + 1
cluster_sizes = np.bincount(labels[clustered]).tolist()

print(f"Percent of data retained: {coverage}")
print(f"Total Clusters found: {total_clusters}")
print(f"Cluster splits: {cluster_sizes}")


_=sns.jointplot(
    x=embedding[clustered, 0], y=embedding[clustered, 1], hue=labels[clustered], kind="kde"
)
Percent of data retained: 1.0
Total Clusters found: 3
Cluster splits: [2501, 1236, 1263]

Что интересно, шума достаточно не обнаружено. Два кластера абсолютно одинаковы, а один почти совмещает их размер.

Визуализация данных на одном и том же срезе дает нам представление о том, что здесь произошло. Кластеры под номерами 3 и 2 из нашего предыдущего запуска теперь объединены.

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

_=sns.jointplot(
    x=embedding[clustered, 1], y=embedding[clustered, 2], hue=labels[clustered], kind="kde"
)

Подведение итогов 🥂

Надеюсь, вам понравилось поближе познакомиться с тем, как настроить гиперпараметры для HDBSCAN !!!

В этом посте вы рассмотрели, почему кластеризация и метрики кластеризации могут усложняться, затем вы узнали о DBCV как объективной метрике и затем применили ее с помощью Amazon Denseclus и HDBSCAN.

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

  • Какие еще типы фреймворков оптимизации вы можете использовать вместо случайного поиска?
  • Какие еще типы гиперпараметров можно использовать для настройки?
  • Какие еще меры здесь возможны для дальнейшей валидации кластера?
  • Можно ли настроить какие-либо другие гиперпараметры в Denseclus для достижения более высокого балла?

Ссылка

«Силуэты: графическое средство для интерпретации и проверки кластерного анализа», Rousseeuw 1987

«Проверка кластеризации на основе плотности», Moulavi et al. 2014 г.

«Hdbscan: иерархическая кластеризация на основе плотности», Макиннес, Дж. Хили, С. Астелс, 2017