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-means имеет функцию "predict", но я хочу иметь возможность сделать то же самое с DBSCAN. Что-то вроде этого:--3-->

dbscan.predict(X, Y)

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

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

3 ответов


кластеризация не является классификацией.

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

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

random_state: numpy.RandomState, дополнительно :

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

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

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

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

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

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


в то время как 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)) иногда отличаются. Я не совсем уверен, что это ошибка или результат случайности.

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

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


здесь немного другая и более эффективная реализация. Кроме того, вместо того, чтобы взять первую лучшую точку ядра, которая находится в радиусе 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