如何对彼此“接近”的纬度/经度点进行分组?

Posted

技术标签:

【中文标题】如何对彼此“接近”的纬度/经度点进行分组?【英文标题】:How to group latitude/longitude points that are 'close' to each other? 【发布时间】:2011-05-19 22:45:24 【问题描述】:

我有一个用户提交的纬度/经度点数据库,并试图将“接近”点组合在一起。 “接近”是相对的,但目前似乎约为 500 英尺。

起初,我似乎可以按前 3 位小数点具有相同纬度/经度的行进行分组(大约是一个 300x300 的框,理解它会随着您远离赤道而改变)。

但是,这种方法似乎很缺乏。 “接近度”不能与每个小数位所代表的距离有显着差异。它没有考虑到两个位置可能在第 3 个(或任何一个)小数位有不同的数字,但仍然在该位置所代表的距离内(33.123933.1240)。

我还考虑过 A 点和 C 点都与 B 点“接近”(但不是彼此)的情况——它们应该组合在一起吗?如果是这样,当 D 点“接近”C 点(并且没有其他点)时会发生什么 - 它也应该被分组。当然,我必须确定所需的行为,但是如何实现呢?

谁能指出正确的方向,如何做到这一点以及可以使用哪些不同的方法/方法?

我觉得我错过了一些明显的东西。

目前数据是一个 mysql 数据库,供 php 应用程序使用;但是,如果它们是实现此目的的关键部分,我对其他存储方法持开放态度。这里。

【问题讨论】:

这里可能有一些信息:en.wikipedia.org/wiki/Geodatabase 没有。除非您解释您的目标是什么,否则没有人可以为您指明正确的方向。为什么要对点进行分组? @Unreason - 更详细一点,这些点代表用户“标记”某些位置,假设如果多个用户标记了彼此靠近的位置,则应仅将其计为一个位置.然而,将彼此相距约 500 英尺的纬度/经度点分组的既定目标似乎非常具体,并且已经产生了信息丰富的答案。 @TimLytle 你能告诉我你最终是如何解决你的问题的吗? 【参考方案1】:

有多种方法可以确定两点之间的距离,但要在二维图形上绘制点,您可能需要Euclidean distance。如果(x1, y1)代表你的第一个点,(x2, y2)代表你的第二个点,那么距离是

d = sqrt( (x2-x1)^2 + (y2-y1)^2 )

关于分组,您可能希望使用某种二维均值来确定事物彼此之间的“接近”程度。比如你有(x1, y1)(x2, y2)(x3, y3)三个点,你可以通过简单的平均找到这三个点的中心:

x(mean) = (x1+x2+x3)/3
y(mean) = (y1+y2+y3)/3

然后您可以查看每个距离中心有多近,以确定它是否应该成为“集群”的一部分。


定义集群的方法有很多种,所有这些方法都使用clustering algorithm 的一些变体。我现在很着急,没有时间总结,但请查看链接和算法,希望其他人能够提供更多细节。祝你好运!

【讨论】:

知道如何使用更多的点来实现这种分组方法吗? 是的,我希望你不会问这个问题 :) 有许多非常复杂的聚类算法,我会更新帖子以反映其中的一些。 距离只是故事的一部分。可能有无限数量的点位于圆心在 (0,0) 和 r="distance" 的圆上。而且它们可能彼此相距很远。您还应该确定角度。当然,一些聚类算法是该问题的真正答案。【参考方案2】:

使用类似于您在问题中概述的方法来获得一组近似结果,然后通过进行适当的计算来减少该近似值。如果你正确地选择了你的网格大小(即你把你的坐标四舍五入),你至少可以希望将要做的工作量减少到一个可以接受的水平,尽管你必须管理那个网格大小是多少。

例如,PostgreSQL 的 earthdistance 扩展通过将纬度/经度对转换为 (x,y,z) 笛卡尔坐标来工作,将地球建模为一个均匀的球体。 PostgreSQL 有一个复杂的索引系统,它允许将这些坐标或它们周围的框索引到 R-trees 中,但是你可以将一些东西拼凑在一起,没有它仍然有用。

如果您将 (x,y,z) 三倍并四舍五入 - 即乘以某个因子并截断为整数 - 然后您将拥有三个整数,您可以将它们连接起来生成一个“盒子名称”,用于标识一个盒子在点所在的“网格”中。

如果您想搜索某个目标点 X 公里内的所有点,您可以在该点周围生成所有“框名称”(一旦您将目标点转换为 (x,y,z) 三元组嗯,这很容易)并消除所有不与地球表面相交的框(诡计,但在每个角落使用x^2+y^2+z^2=R^2 公式会告诉你)你最终会得到一个框列表,目标点可以在-因此,只需搜索与其中一个框匹配的所有点,这也会为您返回一些额外的点。因此,作为最后阶段,您需要计算到目标点的实际距离并消除一些(同样,这可以通过在笛卡尔坐标中工作并将您的目标大圆距离半径转换为割线距离来加快速度)。

折腾归结为确保您不必搜索太多的框,但同时不要带来太多的加分。我发现在几个不同的网格上索引每个点很有用(例如,1Km、5Km、25Km、125Km 等的分辨率)。理想情况下,您只想搜索一个框,请记住,一旦您的目标半径超过您的网格大小,它就会扩展到至少 27 个。

我已经使用这种技术使用 Lucene 构建空间索引,而不是在 SQL 数据库中进行计算。它确实有效,尽管设置它有些麻烦,并且索引需要一段时间才能生成并且非常大。使用 R-tree 来保存所有坐标是一种更好的方法,但需要更多的自定义编码——这种技术基本上只需要快速的哈希表查找(因此可能适用于所有的 NoSQL 数据库)这些天很流行,应该也可以在 SQL 数据库中使用)。

【讨论】:

【参考方案3】:

也许矫枉过正,但在我看来 clustering problem: distance measure 将决定如何计算两个元素的相似度。如果您需要更简单的解决方案,请尝试Data Mining: Practical Machine Learning Tools and Techniques,并使用Weka 或Orange

【讨论】:

【参考方案4】:

如果我要解决它,我会从网格开始。将每个点放在网格上的一个正方形中。寻找人口密集的网格。如果相邻的网格没有被填充,那么你就有了一个不错的组。

如果您有相邻的密集网格,您始终可以在每个网格的中心放置一个圆圈,并针对圆圈面积与(圆圈中的点数 * 一些可调权重)进行优化。不完美,但很容易。更好的分组是更复杂的优化问题。

【讨论】:

【参考方案5】:

如果您考虑纬度和经度,则需要在实时数据中考虑几个因素:障碍物,例如河流和湖泊,以及设施,例如桥梁和隧道。您不能简单地将它们分组;如果您使用简单算法,因为 k 意味着您将无法对它们进行分组。我认为您应该使用空间聚类方法作为分区 CLARANS 方法。

【讨论】:

【参考方案6】:

面对类似的问题,我刚刚地板经度和纬度,直到我得到所需的“接近度”(以米为单位)。就我而言,4位数的地板让我的位置在大约时被分组。相距 13 米。

如果 Long 或 Lat 是 negatives - 将 floor 替换为 ceil

首先 FLOOR(或 CEIL)到所需的精度,然后在舍入的经纬度上进行 GROUP。

测量两个地理位置之间距离的代码是从Getting distance between two points based on latitude/longitude借来的

from math import sin, cos, sqrt, atan2, radians

R = 6373.0
lat1 = radians(48.71953)
lon1 = radians(-73.72882)
lat2 = radians(48.719)
lon2 = radians(-73.728)
    
dlon = lon2 - lon1
dlat = lat2 - lat1

a = sin(dlat / 2)**2 + cos(lat1) * cos(lat2) * sin(dlon / 2)**2
c = 2 * atan2(sqrt(a), sqrt(1 - a))

distance = (R * c)*1000

print("Distance in meters:", round(distance))

距离(米):84

正如预期的那样,在相同的角度下,距离在南方较大,北方较小。 对于相同的坐标,但在赤道上,距离为 109 米(将纬度修改为 0.71953 和 0.719)。

我修改了下面的位数,始终保持一键Long和一键Lats,并测量得到的距离:

lat1 = radians(48.71953)
lon1 = radians(-73.72882)
lat2 = radians(48.71954)
lon2 = radians(-73.72883)
Distance in meters  1

lat1 = radians(48.7195)
lon1 = radians(-73.7288)
lat2 = radians(48.7196)
lon2 = radians(-73.7289)
Distance in meters  13

lat1 = radians(48.719)
lon1 = radians(-73.728)
lat2 = radians(48.720)
lon2 = radians(-73.729)
Distance in meters  133

lat1 = radians(48.71)
lon1 = radians(-73.72)
lat2 = radians(48.72)
lon2 = radians(-73.73)
Distance in meters  1333

总结:Floor / Ceil 将经度和纬度设为 4 位数字,将帮助您在相距约 13 米的位置进行分组。 这个数字根据上面的公式而变化:赤道附近较大,北部较小。

【讨论】:

以上是关于如何对彼此“接近”的纬度/经度点进行分组?的主要内容,如果未能解决你的问题,请参考以下文章

如何按纬度对我的 WP7 应用程序的兴趣点进行分组

分组/分桶纬度和经度

如何将相同的纬度和经度分组以在画面中显示多个位置

当它们彼此靠近时对点进行分组

如何将时间戳彼此接近的会话分组?

如何按距离(以英里为单位)从 C# 中的给定纬度/经度对纬度/经度列表进行排序?