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

时间:2010-12-03 19:28:38

标签: sql database geolocation location cluster-analysis

我有一个用户提交的纬度/经度点数据库,我正在尝试将“关闭”点组合在一起。 “关闭”是相对的,但现在似乎是~500英尺。

起初,我似乎可以按照前3个小数位(纬度/经度相同的行)分组(大约300x300的盒子,了解它会随着你离开赤道而变化)。

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

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

有人能指出我如何做到这一点以及可以使用哪些不同的方法/方法?

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

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

6 个答案:

答案 0 :(得分:7)

有多种方法可以确定两点之间的距离,但是对于在二维图上绘制点,您可能需要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的某些变体。我现在很匆忙,没有时间进行总结,但查看链接和算法,希望其他人能够提供更多细节。祝你好运!

答案 1 :(得分:7)

使用与您在问题中列出的方法类似的方法来获得一组近似结果,然后通过进行适当的计算来缩小近似值。如果您正确地选择了网格大小(即,您的坐标多少),您至少可以希望将要完成的工作量减少到可接受的水平,尽管您必须管理网格大小。

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

如果取你的(x,y,z)三元组并舍入 - 即乘以某个因子并截断为整数 - 那么你有三个整数可以连接以产生一个“盒子名称”,它标识一个盒子在您的“网格”中,该点位于。

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

摆弄到周围,确保你不必搜索太多的盒子,但同时不要带太多额外的积分。我发现对几个不同网格上的每个点进行索引很有用(例如1Km,5Km,25Km,125Km等分辨率)。理想情况下,您只想搜索一个框,请记住,只要目标半径超过网格大小,它就会扩展到至少27个。

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

答案 2 :(得分:5)

也许是矫枉过正,但在我看来clustering problem:距离measure将决定如何计算两个元素的相似性。如果您需要一个不太天真的解决方案,请尝试Data Mining: Practical Machine Learning Tools and Techniques,然后使用WekaOrange

答案 3 :(得分:3)

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

答案 4 :(得分:2)

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

如果您有相邻的人口密集网格,您可以随时在每个网格的中心放置一个圆圈,并优化圆形区域vs(圆圈中的点数*一些可调整的重量)。不完美,但很容易。更好的分组是更复杂的优化问题。

答案 5 :(得分:1)

面临类似的问题,我只是确定经度和纬度,直到获得所需的“接近度”(以米为单位)。就我而言,地板到 4 位数字使我的位置在大约为 1 小时时分组。相距 13 米。

如果 Long 或 Lat 是否定 - 用 ceil 替换 floor

首先 FLOOR(或 CEIL)到所需的精度,然后在舍入的 long 和 lat 上进行 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)。

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

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 米的位置进行分组。 这个数字根据上面的公式而变化:赤道附近较大,北部较小。