Как выполнить кластер с весами / плотностью в python? Что-то вроде kmeans с весами?
мои данные таковы:
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
Я хочу иметь возможность кластеризировать данные в N количество кластеров (скажем, 3). Обычно я бы использовал 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()
проблема в том, что это не учитывает никакого взвешивания (в этом случае мое значение powergenerated), я хочу, чтобы в идеале мои кластеры учитывали значение "powergenerated", пытаясь сохранить кластеры не только пространственно близко, но и близко к относительно равному общему powergenerated.
должен ли я делать это с kmeans (или каким-либо другим методом)? Или есть что-то еще, что я должен использовать для этой проблемы, что было бы лучше?
1 ответов
или есть что-то еще, что я должен использовать для этой проблемы, что было бы лучше?
чтобы одновременно учитывать географическое расстояние между центральными центрами и генерируемую мощность, вы должны определить правильную метрику. Функция ниже вычисляет расстояние между двумя точками на поверхности Земли от их широты и долготы через haversine формула и добавляет абсолютное значение генерируемой мощности разница умножается на весовой коэффициент. Значение веса определяет относительное влияние расстояния и разности мощностей в процессе кластеризации.
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
должен ли я делать это с kmeans (или каким-либо другим методом)?
к сожалению, в текущей реализации это составляющей kmeans2
и пакет scikit-узнать KMeans
поддерживает только евклидово расстояние. Альтернативный метод будет состоять в выполнении иерархическая кластеризация через пакет кластеризации SciPy для группировки центров в соответствии с только что определенной метрикой.
демо
давайте сначала сгенерируем фиктивные данные, а именно векторы функций для 8 центров со случайными значениями:
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
содержание переменной data
данный фрагмент выше выглядит следующим образом:
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. ]])
чтобы разделить эти данные на три разные группы, мы должны пройти data
и custom_metric
до linkage
функция (проверьте docs чтобы узнать больше о параметре method
), а затем передайте возвращенную матрицу связей в