2017-07-11 83 views
8

Moje dane jest tak:Jak wykonać klaster z wagą/gęstością w pythonie? Coś w rodzaju kmeanów z ciężarami?

powerplantname, latitude, longitude, powergenerated 
A, -92.3232, 100.99, 50 
B, <lat>, <long>, 10 
C, <lat>, <long>, 20 
D, <lat>, <long>, 40 
E, <lat>, <long>, 5 

Chcę móc klastra dane do liczby N klastrów (powiedzmy 3). Normalnie bym użyć kmeans:

import numpy as np 

import matplotlib.pyplot as plt 
from scipy.cluster.vq import kmeans2, whiten 
coordinates= np.array([ 
      [lat, long], 
      [lat, long], 
      ... 
      [lat, long] 
      ]) 
x, y = kmeans2(whiten(coordinates), 3, iter = 20) 
plt.scatter(coordinates[:,0], coordinates[:,1], c=y); 
plt.show() 

Problem polega na tym, że nie stanowią jakiejkolwiek wagi (w tym przypadku, mój wartości powergenerated) Chcę idealnie moich klastrów przyjmując wartość „powergenerated” pod uwagę , starając się utrzymać klastry nie tylko przestrzennie blisko, ale także mieć bliskie względnie równemu całemu potergeneracji.

Czy powinienem to robić z kmeans (lub inną metodą)? Czy jest jeszcze coś, co powinienem użyć do tego problemu, który byłby lepszy?

+0

Chcesz skupiska zbliżonym równej wagi? Powinieneś raczej traktować to jako problem optymalizacyjny, a nie klastrowanie. –

Odpowiedz

6

Czy jest tam coś innego I należy używać do tego problemu, który byłby lepszy?

W celu uwzględnienia jednocześnie odległości geograficznej między centralami i wytworzonej mocy należy zdefiniować odpowiednią metrykę. Poniższa funkcja oblicza odległość między dwoma punktami na powierzchni Ziemi od ich szerokości i długości przez haversine formula i dodaje wartość bezwzględną wygenerowanej różnicy mocy pomnożonej przez współczynnik ważenia. Wartość masy określa względny wpływ odległości i różnicy mocy w procesie grupowania.

import numpy as np 

def custom_metric(central_1, central_2, weight=1): 
    lat1, lng1, pow1 = central_1 
    lat2, lng2, pow2 = central_2 

    lat1, lat2, lng1, lng2 = np.deg2rad(np.asarray([lat1, lat2, lng1, lng2])) 

    dlat = lat2 - lat1 
    dlng = lng2 - lng1 

    h = (1 - np.cos(dlat))/2. + np.cos(lat1)*np.cos(lat2)*(1 - np.cos(dlng))/2. 
    km = 2*6371*np.arcsin(np.sqrt(h)) 

    MW = np.abs(pow2 - pow1) 

    return km + weight*MW 

powinienem tego robić z kmeans (lub innej metody)?

Niestety obecne implementacje scipy na kmeans2 i scikit-learn na KMeans obsługuje tylko odległość euklidesową. Alternatywna metoda polegałaby na przeprowadzeniu hierarchical clustering poprzez pakiet klastrowania SciPy, aby zgrupować centrale według właśnie zdefiniowanej metryki.

Demo

Niech najpierw wygenerować dane makiety, czyli wyposażone wektory 8 central z wartościami losowymi:

N = 8 
np.random.seed(0) 
lat = np.random.uniform(low=-90, high=90, size=N) 
lng = np.random.uniform(low=-180, high=180, size=N) 
power = np.random.randint(low=5, high=50, size=N) 
data = np.vstack([lat, lng, power]).T 

Zawartość zmiennej data uzyskano przez fragmencie powyżej wygląda następująco:

array([[ 8.7864, 166.9186, 21. ], 
     [ 38.7341, -41.9611, 10. ], 
     [ 18.4974, 105.021 , 20. ], 
     [ 8.079 , 10.4022, 5. ], 
     [ -13.7421, 24.496 , 23. ], 
     [ 26.2609, 153.2148, 40. ], 
     [ -11.2343, -154.427 , 29. ], 
     [ 70.5191, -148.6335, 34. ]]) 

Aby podzielić te dane na trzy różne grupy, musimy przekazać data i custom_metric do funkcji linkage (sprawdź numer docs, aby dowiedzieć się więcej o parametrze method), a następnie przekaż zwiniętą macierz powiązań do funkcji cut_tree za pomocą n_clusters=3.

from scipy.cluster.hierarchy import linkage, cut_tree 
Z = linkage(data, method='average', metric=custom_metric) 
y = cut_tree(Z, 3).flatten() 

W rezultacie otrzymujemy przynależności do grupy (array y) dla każdego centralny:

array([0, 1, 0, 2, 2, 0, 0, 1]) 

Powyższe wyniki są uzależnione od wartości weight. Jeśli chcesz użyć wartości innego do 1 (np 250) można zmienić domyślną wartość takiego:

def custom_metric(central_1, central_2, weight=250): 

Alternatywnie, można ustawić parametr metric w zaproszeniu do linkage do wyrażenia lambda następująco : metric=lambda x, y: custom_metric(x, y, 250).

Wreszcie, aby uzyskać głębszy wgląd w hierarchicznej/aglomeratów materiałem klastrów można wykreślić go jako dendrogramie:

from scipy.cluster.hierarchy import dendrogram 
dendrogram(Z) 

dendrogram

+0

Przepraszam, miałem na myśli 'dane' zamiast' X'. Już zredagowałem swoją odpowiedź, aby naprawić nazwę zmiennej. – Tonechas

+0

Dzięki. Jak określić wagę = 250? Albo jaką wagę należy ustawić na taką samą cenę? – Rolando

+0

Właściwa wartość "wagi" zależy od odległości między centralami, ich generowanej mocy i względnej ważności, jaką chcesz nadać każdemu czynnikowi w procesie grupowania. Powinieneś wypróbować różne wartości "wagi", dopóki uzyskane wyniki nie będą dla ciebie sensowne. – Tonechas