Scikit-Learn: prévoir de nouveaux points avec DBSCAN
j'utilise DBSCAN pour regrouper certaines données en utilisant Scikit-Learn (Python 2.7):
from sklearn.cluster import DBSCAN
dbscan = DBSCAN(random_state=0)
dbscan.fit(X)
cependant, j'ai trouvé qu'il n'y avait pas de fonction intégrée (à part "fit_predict") qui pourrait assigner les nouveaux points de données, Y, aux clusters identifiés dans les données originales, X. La méthode K-means a une fonction "predict" mais je veux pouvoir faire la même chose avec DBSCAN. Quelque chose comme ceci:
dbscan.predict(X, Y)
de sorte que la densité peut être déduite de X mais les valeurs de retour (cluster assignations / labels) sont uniquement pour Y. D'après ce que je peux dire, cette capacité est disponible en R donc je suppose qu'elle est aussi disponible en Python. Je n'arrive pas à trouver de documentation pour ça.
aussi, j'ai essayé de chercher des raisons pour lesquelles DBSCAN ne peut pas être utilisé pour étiqueter de nouvelles données, mais je n'ai trouvé aucune justification.
3 réponses
Le regroupement n'est pas une classification.
Le regroupement n'est pas marqué. Si vous voulez le presser dans un État d'esprit de prédiction (ce qui n'est pas la meilleure idée), alors il essentiellement prédit sans apprentissage. Parce qu'il n'y a pas de données de formation étiquetées disponibles pour le regroupement. Il doit créer de nouveaux labels pour les données, basés sur ce qu'il voit. Mais vous ne pouvez pas faire cela sur une seule instance, vous pouvez seulement "prédire en bloc".
mais il y a quelque chose qui ne va pas avec scipys DBSCAN:
random_state
: numpy.RandomState, en option :Le générateur utilisé pour initialiser les centres. Par défaut à numpy.aléatoire.
DBSCAN ne "initialise pas les centres", parce qu'il n'y a pas de centres dans DBSCAN.
à peu près le algorithme de clustering où vous pouvez assigner de nouveaux points aux anciens clusters est K-means (et ses nombreuses variations). Parce qu'il exécute un "1NN classification " à l'aide des itérations précédentes centres de regroupement, puis met à jour les centres. Mais la plupart des algorithmes ne fonctionnent pas comme K-means, donc vous ne pouvez pas copier ça.
Si vous voulez classer de nouveaux points, il est préférable de former un classificateur sur votre résultat de clustering.
ce que la version R fait peut - être, c'est utiliser un classificateur 1NN pour la prédiction; peut-être avec la règle supplémentaire que les points sont assignés l'étiquette de bruit, si leur distance 1NN est plus grande que epsilon, mabye aussi en utilisant les points de base seulement. Peut-être pas.
obtenir le papier de DBSCAN, il ne traite pas de "prédiction" IIRC.
alors Qu'Anony-Mousse a quelques bons points (le regroupement n'est pas une classification) je pense que la capacité d'attribuer de nouveaux points a son utilité. *
basé sur le document original sur DBSCAN et robertlaytons idées sur github.com/scikit-learn, je suggère de passer par les points de base et d'affecter au cluster du premier point de base qui est à l'intérieur de eps
de votre nouveau point.
Ensuite, il est garanti que votre point au moins être un point limite de la grappe assignée selon les définitions utilisées pour le regroupement.
(Soyez conscient que votre point pourrait être considéré comme du bruit et non assigné à un cluster)
j'ai fait une rapide mise en œuvre:
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
les labels obtenus par clustering (dbscan_predict(dbscan_model, X)) diffèrent parfois. Je ne suis pas sûr que ce soit un bug quelque part ou le résultat d'un hasard.
EDIT: je pense que le problème ci-dessus des résultats de prédiction différents pourrait provenir de la possibilité qu'un point limite puisse être proche de plusieurs grappes. Veuillez mettre à jour si vous le testez et trouver une réponse. L'ambiguïté pourrait être résolue en mélangeant les points centraux à chaque fois ou en choisissant le point le plus proche au lieu du premier point central.
*) cas présent: j'aimerais évaluer si les grappes obtenues à partir d'un sous-ensemble de mes données ont du sens pour un autre sous-ensemble ou est simplement un cas spécial. Si elle se généralise, elle soutient la validité des clusters et les premières étapes de pré-traitement appliquées.
Voici une implémentation légèrement différente et plus efficace. De plus, au lieu de prendre le premier meilleur point central qui se trouve dans le rayon eps, le point le plus proche de l'échantillon est pris.
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