使用Python和KMeans算法对地理位置坐标(纬度、经度对)进行聚类

19 投票
2 回答
37892 浏览
提问于 2025-04-18 13:25

使用以下代码对地理位置坐标进行聚类,结果得到了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()

用K均值算法来进行位置聚类是否合适,因为它使用的是欧几里得距离,而不是哈弗辛公式作为距离计算方法?

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距离。

撰写回答