web-dev-qa-db-ja.com

Scikit-Learn:DBSCANによる新しいポイントの予測

DBSCANを使用して、Scikit-Learn(Python 2.7)を使用して一部のデータをクラスター化しています。

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

ただし、元のデータXで識別されたクラスターに新しいデータポイントYを割り当てることができる組み込み関数( "fit_predict"以外)がないことがわかりました。K平均法には "予測"があります関数ですが、DBSCANでも同じことができるようにしたいと考えています。このようなもの:

dbscan.predict(X, Y)

そのため、密度はXから推測できますが、戻り値(クラスターの割り当て/ラベル)はYに対してのみです。私が知ることができることから、この機能はRで使用できるため、Pythonでも何らかの方法で使用できると想定しています。これに関するドキュメントが見つからないようです。

また、DBSCANを新しいデータのラベル付けに使用できない理由を探してみましたが、正当な理由は見つかりませんでした。

31
slaw

クラスタリングは分類ではありません。

クラスタリングにはラベルがありません。それを予測マインドセットに絞り込みたい場合(これは最良のアイデアではありません)、本質的には学習せずに予測です。これは、クラスタリングに使用できるラベル付きのトレーニングデータがないためです。表示内容に基づいて、データの新しいラベルを作成する必要があります。ただし、これを単一のインスタンスで実行することはできません。「一括予測」しかできません。

しかし、scipys DBSCANに問題があります:

random_state:numpy.RandomState、オプション:

センターを初期化するために使用されるジェネレータ。デフォルトはnumpy.randomです。

DBSCANにはセンターがないため、DBSCANは「センターを初期化」しません。

古いポイントに新しいポイントを割り当てることができるonlyクラスタリングアルゴリズムはほとんどk-means(およびその多くのバリエーション)です。以前の反復クラスター中心を使用して「1NN分類」を実行するため、中心を更新します。しかし、ほとんどのアルゴリズムはk-meansのように機能しないため、これをコピーすることはできません。

新しいポイントを分類する場合は、クラスタリング結果で分類子をトレーニングするのが最善です。

Rバージョンが行っていることは、1NN分類器を予測に使用していることです。 1NN距離がイプシロンより大きい場合、ポイントにノイズラベルが割り当てられるという追加のルールを使用して、コアポイントのみを使用することもできます。そうでないかもしれない。

DBSCANペーパーを入手してください。「予測」IIRCについては説明していません。

17
Anony-Mousse

Anony-Mousseにはいくつかの良い点がありますが(クラスタリングは実際には分類されていません)、新しい点を割り当てることができると便利です。 *

[〜#〜] dbscan [〜#〜] に関する元の論文と github.com/scikit-learn に関するrobertlaytonsのアイデアに基づいて、コアポイントと新しいポイントの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))は異なる場合があります。これがどこかのバグか、ランダム性の結果。

編集:予測結果が異なるという上記の問題は、境界点が複数のクラスターに近い可能性があることに起因すると考えられます。これをテストして答えを見つけたら更新してください。あいまいさは、毎回コアポイントをシャッフルするか、最初のコアポイントではなく最も近いコアポイントを選択することで解決できます。

*)目前の事例:データのサブセットから取得したクラスターが他のサブセットにとって意味があるのか​​、それとも単に特殊なケースであるのかを評価したいと思います。一般化すると、クラスターの有効性と前処理の前のステップが適用されます。

18
kidmose

ここでは、わずかに異なる、より効率的な実装です。また、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
4
nkaenzig

これはまったく同じアルゴリズムではありませんが、sklearn HDBSCANを使用して新しいポイントの近似予測を実行できます。 こちら を参照してください。

それはこのように動作します:

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