使用Python和KMeans算法对地理位置坐标(纬度、经度对)进行聚类
使用以下代码对地理位置坐标进行聚类,结果得到了3个聚类:
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()
2 个回答
7
这主要取决于你的应用场景:
- 在赤道附近,结果应该比较准确。但在靠近极地的地方,结果就没什么用了。
- 不过,它可能可以作为一个预处理步骤,或者用于对精度要求不高的应用,比如一些小的、互不重叠且非常明显的聚类。
如果你真的需要使用Haversine公式,可以看看这个讨论。正如Anony-Mousse所说:
要注意,Haversine距离不适合用于k-means或平均链接聚类,除非你找到一种聪明的方法来计算最小化方差的均值。如果你的经纬度坐标有-180/+180的环绕,千万不要使用算术平均。
25
k-means算法并不适合用来进行空间聚类,原因你已经提到过了。相反,你可以使用scikit-learn中的DBSCAN算法,配合haversine距离和ball-tree算法来完成这个聚类任务。
这个教程展示了如何使用DBSCAN和haversine来对经纬度的空间数据进行聚类,避免了所有与欧几里得距离相关的问题:
df = pd.read_csv('gps.csv')
coords = df.as_matrix(columns=['lat', 'lon'])
db = DBSCAN(eps=eps, min_samples=ms, algorithm='ball_tree', metric='haversine').fit(np.radians(coords))
需要注意的是,这里特别使用的是scikit-learn的v0.15版本,因为一些早期或晚期的版本似乎需要计算完整的距离矩阵。此外,要注意eps值是以弧度为单位的,而.fit()方法需要以弧度单位传入坐标,以适应haversine距离。