Scikit-Learn: прогнозирование новых точек с помощью DBSCAN

Я использую DBSCAN для кластеризации некоторых данных с помощью Scikit-Learn (Python 2.7):

from sklearn.cluster import DBSCAN
dbscan = DBSCAN(random_state=0)
dbscan.fit(X)

Однако я обнаружил, что не было встроенной функции (кроме «fit_predict»), которая могла бы назначать новые точки данных Y кластерам, идентифицированным в исходных данных, X. Метод K-средних имеет «прогноз» функции, но я хочу иметь возможность делать то же самое с DBSCAN. Что-то вроде этого:

dbscan.predict(X, Y)

Таким образом, плотность может быть выведена из X, но возвращаемые значения (назначения / метки кластера) предназначены только для Y. Насколько я могу судить, эта возможность доступна в R, поэтому я предполагаю, что она также каким-то образом доступна в Python. Я просто не могу найти для этого никакой документации.

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


person slaw    schedule 07.01.2015    source источник


Ответы (5)


Кластеризация - это не классификация.

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

Но что-то не так с scipys DBSCAN:

random_state: numpy.RandomState, необязательно:

Генератор, используемый для инициализации центров. По умолчанию numpy.random.

DBSCAN не «инициализирует центры», потому что в DBSCAN нет центров.

В значительной степени алгоритм кластеризации only, где вы можете назначать новые точки старым кластерам, является k-средним (и его многочисленными вариациями). Поскольку он выполняет «классификацию 1NN», используя центры кластеров предыдущих итераций, затем обновляет центры. Но большинство алгоритмов не работают как k-средства, поэтому вы не можете скопировать это.

Если вы хотите классифицировать новые точки, лучше обучить классификатору результат кластеризации.

Возможно, версия R использует классификатор 1NN для прогнозирования; возможно, с дополнительным правилом, что точкам назначается метка шума, если их расстояние 1NN больше, чем эпсилон, mabye также использует только основные точки. Может быть нет.

Получите документ DBSCAN, он не обсуждает "предсказание" IIRC.

person Has QUIT--Anony-Mousse    schedule 07.01.2015
comment
Кластеризация k-средних в Scikit-learn имеет метод прогнозирования: predict(X): Predict the closest cluster each sample in X belongs to., и это обычно то, что мы собираемся делать с прогнозированием в контексте кластеризации. - person Sid; 27.09.2017
comment
@Sid, за исключением того, что только для ближайших k-средних имеет смысл и будет согласовываться с метками кластера. С DBSCAN это не приведет к тем же меткам, что и fit_predict, т. Е. Будет несовместимым. - person Has QUIT--Anony-Mousse; 09.02.2020

Хотя у Anony-Mousse есть несколько хороших моментов (кластеризация действительно не классифицирует), я думаю, что возможность назначать новые точки имеет свою полезность. *

На основе оригинальной статьи о DBSCAN и robertlaytons на github.com/scikit-learn, я предлагаю пройти через базовые точки и назначить кластеру первую базовую точку, которая находится в пределах eps от вашей новой точки. Тогда гарантируется, что ваша точка будет как минимум пограничной точкой назначенного кластера в соответствии с определениями, используемыми для кластеризации. (Имейте в виду, что ваша точка может рассматриваться как шум и не назначена кластеру)

Я сделал быструю реализацию:

import numpy as np
import scipy as sp

def dbscan_predict(dbscan_model, X_new, metric=sp.spatial.distance.cosine):
    # Result is noise by default
    y_new = np.ones(shape=len(X_new), dtype=int)*-1 

    # Iterate all input samples for a label
    for j, x_new in enumerate(X_new):
        # Find a core sample closer than EPS
        for i, x_core in enumerate(dbscan_model.components_): 
            if metric(x_new, x_core) < dbscan_model.eps:
                # Assign label of x_core to x_new
                y_new[j] = dbscan_model.labels_[dbscan_model.core_sample_indices_[i]]
                break

    return y_new

Метки, полученные путем кластеризации (dbscan_model = DBSCAN(...).fit(X) и метки, полученные из одной и той же модели для одних и тех же данных (dbscan_predict(dbscan_model, X)), иногда различаются. Я не совсем уверен, является ли это где-то ошибкой или результатом случайности.

РЕДАКТИРОВАТЬ: Я думаю, что вышеупомянутая проблема с разными результатами прогнозирования может быть связана с возможностью того, что граничная точка может быть близка к нескольким кластерам. Обновите, если вы проверите это и найдете ответ. Неопределенность может быть решена путем перетасовки основных точек каждый раз или путем выбора ближайшей точки вместо первой.

*) Рассматриваемый случай: я хотел бы оценить, подходят ли кластеры, полученные из подмножества моих данных, для другого подмножества или являются просто особым случаем. Если он обобщает, он поддерживает достоверность кластеров и примененных ранее этапов предварительной обработки.

person kidmose    schedule 17.02.2016
comment
Можно ли предсказать новые точки данных с помощью агломеративной кластеризации? - person javac; 27.03.2019
comment
Возможно, да, но я думаю, что вышеупомянутые проблемы не менее актуальны. В приведенном выше случае я воспользовался тем, что DBSCAN имеет понятие близости. IIRC Aglo. Кластеризации нет, поэтому вам нужно ввести новую, например вдохновленный K-NN. Я предлагаю действительно обратить внимание на ответ @anony-mousse. - person kidmose; 28.03.2019
comment
Из руководства пользователя sklearn: even though the core samples will always be assigned to the same clusters, the labels of those clusters will depend on the order in which those samples are encountered in the data. Second and more importantly, the clusters to which non-core samples are assigned can differ depending on the data order. - person sandyp; 17.10.2019

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

def dbscan_predict(model, X):

    nr_samples = X.shape[0]

    y_new = np.ones(shape=nr_samples, dtype=int) * -1

    for i in range(nr_samples):
        diff = model.components_ - X[i, :]  # NumPy broadcasting

        dist = np.linalg.norm(diff, axis=1)  # Euclidean distance

        shortest_dist_idx = np.argmin(dist)

        if dist[shortest_dist_idx] < model.eps:
            y_new[i] = model.labels_[model.core_sample_indices_[shortest_dist_idx]]

    return y_new
person nkaenzig    schedule 25.07.2018

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

Работает это так:

clusterer = hdbscan.HDBSCAN(min_cluster_size=15, prediction_data=True).fit(data)
test_labels, strengths = hdbscan.approximate_predict(clusterer, test_points)
person Benten    schedule 30.07.2019

Здесь уже есть отличные ответы на этот вопрос. Я предлагаю попробовать HDBSCAN. Он предоставляет approximate_predict() метод, который может быть тем, что вам нужно.

person Bahador    schedule 16.06.2020
comment
добавить подробное объяснение того, как это решит проблему - person Arghya Sadhu; 16.06.2020