2015-11-15 21 views
7

Mi piacerebbe raggruppare i punti dati a una distanza personalizzata e stranamente, sembra che né i metodi di clustering scipy né sklearn consentono la specifica di una funzione di distanza.Come specificare una funzione di distanza per il clustering?

Ad esempio, in sklearn.cluster.AgglomerativeClustering, l'unica cosa che posso fare è inserire una matrice di affinità (che sarà molto ricca di memoria). Per costruire questa stessa matrice, si consiglia di utilizzare sklearn.neighbors.kneighbors_graph, ma non capisco come sia possibile specificare una funzione di distanza tra due punti. Qualcuno potrebbe illuminarmi?

risposta

8

Tutte le routine di clustering gerarchico scipy accettano una funzione di distanza personalizzata che accetta due vettori 1D che specificano una coppia di punti e restituisce uno scalare. Ad esempio, utilizzando 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 

ingressi validi per il metric= kwarg sono gli stessi per scipy.spatial.distance.pdist.

+0

Grazie per il suggerimento. Ho provato fclusterdata ma non è riuscito poiché inizia convertendo l'array di input in doubles mentre il mio array è strutturato (contiene stringhe). Come potrei affrontarlo? –

+0

Potresti pubblicare alcuni dati di esempio? –

+0

Certo: [(b'FOO ', b'67482', 13167), ..., (b'BAR ', b'32798', 1369)]. Ma stavo pensando, un modo per aggirare il problema sarebbe quello di eseguire il metodo di clustering sugli indici (vale a dire 1, ..., n) e utilizzare questi indici all'interno della funzione distance per recuperare i dati corretti nell'array iniziale. A proposito, non ho bisogno che il clustering sia gerarchico, quindi potrei usare un metodo k-means invece di fclusterdata. –

1

Per il clustering gerarchico, scipy.cluster.hierarchy.fclusterdata consente di utilizzare una qualsiasi delle metriche di distanza inclusi nell'elenco here tramite l'argomento metric= parola chiave, a condizione che lavora con il metodo di collegamento che si desidera.

+0

No, devo definire la mia propria funzione di distanza (in realtà chiamando geopy). –

+0

Oh, incompreso. Puoi farlo costruendo il kneighbors_graph come ti dice sopra, ma specificando una metrica definita dall'utente usando 'metric = DistanceMetric.get_metric ('pyfunc', name_of_my_distance_function)', importando la classe 'DistanceMetric' e scrivendo la tua funzione che calcola una distanza, a condizione che sia una metrica valida. –

+0

Grazie per il tuo suggerimento su come usare la funzione distanza, ma confesso di non capire davvero cosa fa il kneighbors_graph. Non capisco nemmeno l'output dell'esempio fornito nella documentazione. Non ho familiarità con l'uso di grafici in quel contesto. Per me, è una matrice di distanze tra tutti i punti che dovrebbero essere forniti ad un algoritmo di clustering (o, meglio, un modo per dare all'algoritmo stesso una funzione di distanza). –

1

sklearn ha DBSCAN che consente matrici di distanza precomputed (utilizzando una matrice triangolare dove M_ij è la distanza tra i e j). Ma questo potrebbe non essere il tipo di cluster che stai cercando.

Inoltre, come indicato da qualcun altro, scipy.cluster.hierarchy.fclusterdata consente anche le metriche di distanza precalcolate. C'è un frammento di codice dato a this reply che dà un po 'di codice per trasformare una matrice NxN di distanze in un formato che fclusterdata può facilmente leggere:

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