2015-11-15 9 views
7

Ich würde gerne Punkte sammeln, die auf eine benutzerdefinierte Entfernung gegeben werden und seltsamerweise scheint es, dass weder scipy noch sklearn clustering Methoden die Spezifikation einer Abstandsfunktion erlauben.Wie spezifiziert man eine Entfernungsfunktion für das Clustering?

Zum Beispiel, in sklearn.cluster.AgglomerativeClustering, das einzige, was ich tun kann, ist eine Affinitätsmatrix eingeben (die sehr Speicher-schwer sein wird). Um diese Matrix zu erstellen, wird empfohlen, sklearn.neighbors.kneighbors_graph zu verwenden, aber ich verstehe nicht, wie ich eine Entfernungsfunktion entweder zwischen zwei Punkten angeben kann. Könnte mich jemand aufklären?

Antwort

8

Alle scipy hierarchischen Clustering-Routinen akzeptieren eine benutzerdefinierte Abstandsfunktion, die zwei 1D-Vektoren akzeptiert, die ein Punktepaar angeben und einen Skalar zurückgeben. Beispielsweise unter Verwendung fclusterdata:

import numpy as np 
from scipy.cluster.hierarchy import fclusterdata 

# a custom function that just computes Euclidean distance 
def mydist(p1, p2): 
    diff = p1 - p2 
    return np.vdot(diff, diff) ** 0.5 

X = np.random.randn(100, 2) 

fclust1 = fclusterdata(X, 1.0, metric=mydist) 
fclust2 = fclusterdata(X, 1.0, metric='euclidean') 

print(np.allclose(fclust1, fclust2)) 
# True 

Valid Eingänge für die metric= kwarg sind die gleichen wie für scipy.spatial.distance.pdist.

+0

Danke für den Tipp. Ich habe fclusterdata ausprobiert, aber es ist fehlgeschlagen, da es anfängt, das Eingabearray zu doubles zu konvertieren, während mein Array strukturiert ist (es enthält Zeichenfolgen). Wie könnte ich damit umgehen? –

+0

Können Sie Beispieldaten posten? –

+0

Sicher: [(b'FOO ', b'67482', 13167), ..., (b'BAR ', b'32798', 1369)]. Aber ich dachte, eine Möglichkeit, das Problem zu umgehen, wäre, das Clustering-Verfahren für die Indizes (d. H. 1, ..., n) auszuführen und diese Indizes innerhalb der Abstandsfunktion zu verwenden, um die richtigen Daten im Ausgangsarray abzurufen. Übrigens brauche ich das Clustering nicht hierarchisch, also kann ich eine k-Means-Methode anstelle von fclusterdata verwenden. –

1

Für hierarchischen Clustering, scipy.cluster.hierarchy.fclusterdata können Ihnen here über das metric= Schlüsselwort-Argument in der Liste eine der Abstandsmetriken verwenden, sofern sie mit der Verknüpfung Methode funktionieren, wie Sie wollen.

+0

Nein, ich muss meine eigene Abstandsfunktion (eigentlich definieren durch den Aufruf geopy). –

+0

Oh, missverstanden. Sie können das tun, indem Sie den kneighbors_graph wie oben beschrieben erstellen, aber eine benutzerdefinierte Metrik mit metric = DistanceMetric.get_metric ('pyfunc', name_of_my_distance_function) angeben, indem Sie die 'DistanceMetric'-Klasse importieren und eine eigene Funktion schreiben berechnet eine Entfernung, sofern es sich um eine gültige Metrik handelt. –

+0

Danke für deinen Tipp, wie man die Entfernungsfunktion benutzt, aber ich gestehe, dass ich wirklich nicht verstehe, was kneghbors_graph tut. Ich verstehe die Ausgabe des Beispiels in der Dokumentation nicht einmal. Ich bin nicht vertraut mit der Verwendung von Graphen in diesem Zusammenhang. Für mich ist es eine Matrix von Abständen zwischen allen Punkten, die einem Clustering-Algorithmus zur Verfügung gestellt werden sollten (oder, besser, eine Möglichkeit, dem Algorithmus selbst eine Abstandsfunktion zu geben). –

1

sklearn hat DBSCAN, die vorberechnete Abstandsmatrizen erlaubt (unter Verwendung einer Dreiecksmatrix, wobei M_ij der Abstand zwischen i und j ist). Dies ist jedoch möglicherweise nicht die Art von Clustering, nach der Sie suchen.

Wie bereits erwähnt, erlaubt scipy.cluster.hierarchy.fclusterdata auch vorberechnete Entfernungsmetriken. Es ist ein Code-Snippet in this reply gegeben, die ein Stück Code gibt eine NxN Matrix von Abständen in ein Format umzuwandeln, die fclusterdata leicht lesen kann:

import scipy.spatial.distance as ssd 
# convert the redundant n*n square matrix form into a condensed nC2 array 
    distArray = ssd.squareform(distMatrix) # distArray[{n choose 2}-{n-i choose 2} + (j-i-1)] is the distance between points i and j