【问题标题】:Extract those points which are at least 3 degrees far from each other提取彼此相距至少 3 度的点
【发布时间】:2021-06-04 19:06:44
【问题描述】:

我在地球表面有 9 个点(经度,纬度,度数)如下。

XY = [(100, 10), (100, 11), (100, 13), (101, 10), (101, 11), (101, 13), (103, 10), (103, 11), (103, 13)]
print (len(XY))
# 9

我想提取彼此相距至少 3 度的点。

我试过如下。

results = []

for point in XY:
    x1,y1 = point

    for result in results:
        x2,y2 = result

        distance = math.hypot(x2 - x1, y2 - y1)

        if distance >= 3:
            results.append(point)

print (results)

但是输出是空的。

编辑 2

from sklearn.metrics.pairwise import haversine_distances
from math import radians

results = []

for point in XY:
    x1,y1 = [radians(_) for _ in point]

    for result in results:  
        distance = haversine_distances((x1,y1), (x2,y2))    
        print (distance)

        if distance >= 3:
            results.append(point)

print (results)

结果还是空

编辑 3

results = []

for point in XY:
    x1,y1 = point

    for point in XY:        
        x2,y2 = point

        distance = math.hypot(x2 - x1, y2 - y1)
        print (distance)

        if distance >= 3:
            results.append(point)

print (results)
print (len(results))
# 32   # unexpected len

【问题讨论】:

  • math.hypot() 计算点之间的欧几里得距离,但是您需要确定它们之间相对于某些线段(可能是水平轴)的角距离。
  • 我认为问题出在 pythonic 循环中
  • 如果值是经度和纬度,那么它们之间的角距离是从地球中心到这些点的两条假想线之间的角距离。不管如何计算或计算什么,你是对的,循环的编写方式存在问题。您需要遍历 pairs 点并比较计算值。您还需要将每一个与所有其他的进行比较。

标签: python python-3.x geometry coordinates


【解决方案1】:

重要提示:您说过要“提取彼此相距至少 3 度的点”,但后来您使用了 @987654321 @ 与math.hypot()。作为mentioned by @martineau,这应该使用Haversine angular distance

由于您的点是“(以度为单位的经度,纬度)”,它们首先需要是converted to radians。根据haversine_distances() 函数的要求,应翻转这些对,以便首先出现纬度。这可以通过以下方式完成:

XY_r = [(math.radians(lat), math.radians(lon)) for lon, lat in XY]

这是关键 - 没有必要进行组合或循环。如果haversine_distances() 在点列表中传递,它将计算它们之间的距离all 并以数组数组的形式提供结果。然后可以将这些转换回度数并进行检查;或将3 degrees 转换为弧度,然后检查h-dists。

import math
import numpy as np
from sklearn.metrics.pairwise import haversine_distances

XY = [(100, 10), (100, 11), (100, 13), (101, 10), (101, 11), (101, 13), (103, 10), (103, 11), (103, 13)]

# convert to radians and flip so that latitude is first
XY_r = [(math.radians(lat), math.radians(lon)) for lon, lat in XY]
distances = haversine_distances(XY_r)  # distances array-of-arrays in RADIANS
dist_criteria = distances >= math.radians(3)  # at least 3 degrees (in radians) away
results = [point for point, result in zip(XY, dist_criteria) if np.any(result)]

print(results)
print(len(results))
print('<3 away from all:', set(XY) - set(results))

输出:

[(100, 10), (100, 11), (100, 13), (101, 10), (101, 13), (103, 10), (103, 11), (103, 13)]
8
<3 away from all: {(101, 11)}

Wrt 之前的编辑和您的原始代码:

因此,您的前两次尝试都给出了空结果:

results = []

for point in XY:
    ...
    for result in results:

results 被初始化为一个空列表。所以for result in results循环会直接退出。循环内不执行任何操作。

由于重复,第三次尝试得到 32 个结果。你有:

for point in XY:
    ...
    for point in XY:

所以你得到的一些points 将是同一点。

为了避免在循环中出现重复

  1. 为它添加一个检查并进入下一个迭代:

    if (x1, y1) == (x2, y2):
        continue
    

    顺便说一句,您正在修改 point 变量,因为它在两个循环中都被重用了。它不会导致问题,但会使您的代码更难调试。要么让他们point1point2,或者更好,而不是for point in XY: x1, y1 = point,你可以直接做for x1, y1 in XY——这叫做tuple unpacking

    for x1, y1 in XY:
        for x2, y2 in XY:
            if (x1, y1) == (x2, y2):
                continue
            ...
    
  2. 您还需要将result 更改为set 而不是列表,这样当它与另一个点的距离超过3 时,相同的点不会重新添加到结果中。集合不允许重复,这样点就不会在结果中重复

    使用itertools.combinations() 获得不重复的唯一点对。这允许您跳过重复检查(除非 XY 实际上有重复点)并将前一个块缩减为一个 for 循环:

    import itertools
    import math
    
    results = set()  # unique results
    for (x1, y1), (x2, y2) in itertools.combinations(XY, r=2):
        distance = math.hypot(x2 - x1, y2 - y1)  # WRONG! see above
        if distance >= 3:
            # add both points
            results.update({(x1, y1), (x2, y2)})
    
    print(results)
    print(len(results))
    print('<3 away from all:', set(XY) - results)
    

    (错误的)输出:

    {(103, 11), (100, 13), (101, 13), (100, 10), (103, 10), (101, 10), (103, 13), (100, 11)}
    8
    <3 away from all: {(101, 11)}
    

    (结果是一样的,只是输入数据的巧合而已。)

【讨论】:

  • 由于点的坐标是经度和纬度,OP 显然需要计算Haversine 角距离,而不是欧几里得 - 并且需要比较它们的所有可能配对。
  • @martineau 我确实在底部提到了这一点。但是提供完全正确的答案是有意义的。我还需要转换lat-long from degrees to radians。将编辑。
  • @martineau 是的,同意这一点,所以更新了我的答案。包括能够跳过所有的循环/组合制作。确实使用了角度转换函数而不是手动使用公式。
  • @thunder:嗯,有点意思。结果是相同的,因为在地球大小的球体表面的相对较小的角距离上,所描述的区域几乎是平坦的,因此近似于欧几里得。
  • @thunder 作为一个显示远处点差异的数值示例:考虑两个点(0, 0), (30, 70)。以度为单位的半正弦角距离为72.77,但欧几里得距离为76.15。有关哪种点组合产生更大差异的更多详细信息,请参阅gis-exchange answer
猜你喜欢
  • 2014-12-21
  • 1970-01-01
  • 2016-12-30
  • 1970-01-01
  • 2020-11-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-03-09
相关资源
最近更新 更多