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)
Chcesz skupiska zbliżonym równej wagi? Powinieneś raczej traktować to jako problem optymalizacyjny, a nie klastrowanie. –