提取那些至少相距 3 度的点
Extract those points which are at least 3 degrees far from each other
我在地球表面有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
重要:你说过你想“提取那些至少相距3度的点”但是那么你已经使用了 Euclidean distance with math.hypot()
. As , this should use the Haversine angular distance.
由于您的点是 "(经度,以度为单位的纬度)",它们首先需要是 converted to radians。并且应该翻转这些对,以便按照 haversine_distances()
函数的要求,纬度排在第一位。这可以通过以下方式完成:
XY_r = [(math.radians(lat), math.radians(lon)) for lon, lat in XY]
这是关键 - none 组合或循环是必要的。如果 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)}
根据之前的编辑和您的原始代码:
您的前两次尝试给出的结果都是空的,原因是:
results = []
for point in XY:
...
for result in results:
results
被初始化为一个空列表。所以for result in results
循环会直接退出。循环内没有任何内容执行。
由于重复,第三次尝试得到了 32 个结果。你有:
for point in XY:
...
for point in XY:
所以你得到的一些 point
将是相同的点数。
避免 循环中的重复:
为其添加检查并转到下一个迭代:
if (x1, y1) == (x2, y2):
continue
顺便说一句,您正在破坏 point
变量,因为它在两个循环中都被重用了。它不会导致问题,但会使您的代码更难调试。要么让它们成为 point1
和 point2
,或者更好,而不是 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
...
您还需要将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)}
(结果相同,只是输入数据巧合而已。)
我在地球表面有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
重要:你说过你想“提取那些至少相距3度的点”但是那么你已经使用了 Euclidean distance with math.hypot()
. As
由于您的点是 "(经度,以度为单位的纬度)",它们首先需要是 converted to radians。并且应该翻转这些对,以便按照 haversine_distances()
函数的要求,纬度排在第一位。这可以通过以下方式完成:
XY_r = [(math.radians(lat), math.radians(lon)) for lon, lat in XY]
这是关键 - none 组合或循环是必要的。如果 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)}
根据之前的编辑和您的原始代码:
您的前两次尝试给出的结果都是空的,原因是:
results = []
for point in XY:
...
for result in results:
results
被初始化为一个空列表。所以for result in results
循环会直接退出。循环内没有任何内容执行。
由于重复,第三次尝试得到了 32 个结果。你有:
for point in XY:
...
for point in XY:
所以你得到的一些 point
将是相同的点数。
避免 循环中的重复:
为其添加检查并转到下一个迭代:
if (x1, y1) == (x2, y2): continue
顺便说一句,您正在破坏
point
变量,因为它在两个循环中都被重用了。它不会导致问题,但会使您的代码更难调试。要么让它们成为point1
和point2
,或者更好,而不是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 ...
您还需要将
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)}
(结果相同,只是输入数据巧合而已。)