【问题标题】:Finding random closest neighbours in 3D在 3D 中查找随机最近的邻居
【发布时间】:2019-11-28 11:50:45
【问题描述】:

当给定 750 人的姓名和 GPS 位置(纬度、经度和海拔)时,我正在尝试实现 Python 代码,以查找随机选择的个人的 10 个最近邻居的姓名。

import random
    #random = rand.sample(range(0,750), 10)
    coords = [(random.random()*2.0, random.random()*2.0, random.random()*2.0) for _ in range(750)]

【问题讨论】:

  • 指定单位和距离计算的首选方法会很有用。
  • 坐标是否靠近? (在一些小的经纬度边界框内,例如纽约市)还是整个世界?我们无法从您的代码中分辨出来,因为没有任何单位。然后你需要决定你的距离度量是圆形的、笛卡尔的(还是曼哈顿的)。但请向我们展示一些实际坐标示例,比如五个。

标签: python geopandas


【解决方案1】:

为此,您应该在球坐标中工作,或者您可以转换为笛卡尔坐标。使用笛卡尔坐标系假设您测量距离的方式是直接距离,而不是大椭圆弧。

import numpy as np
from sklearn.neighbors import DistanceMetric

R = 6371 # approximate radius of earth in km

# coordinates in (lat,lon,elv) in units of (rad,rad,km)
coords = np.random.random((750, 3)) * 2
cart_coords = np.array([((R+coord[2]) * np.cos(coord[0]) * np.cos(coord[1]),
                         (R+coord[2]) * np.cos(coord[0]) * np.sin(coord[1]),
                         (R+coord[2]) *np.sin(coord[0])) for coord in coords])

# calculate distances between points
dist = DistanceMetric.get_metric('euclidean')
dist_vals = dist.pairwise(cart_coords)

# pick a random person
random_person = np.random.choice(np.arange(750))
top_ten = np.where(dist_vals[random_person] < sorted(dist_vals[random_person])[11])[0]
# remove self from list
top_ten = top_ten[top_ten!=random_person]

print(top_ten)

如果您想忽略海拔并使用hassine公式,您可以查看此帖子Vectorizing Haversine distance calculation in Python

地球是一个椭球体,两极半径和赤道半径相差约 21 公里。如果你真的想更深入,你可以研究大地测量学。 astropy 是解决这类问题的好包https://docs.astropy.org/en/stable/api/astropy.coordinates.spherical_to_cartesian.html

【讨论】:

    【解决方案2】:

    你不能只使用距离公式来计算给定 x,y,z 的两点之间的距离,其中 d=sqrt((x2-x1)^2+(y2-y1)^2+(z2- z1)^2) 得到随机选择的人与所有其他元素之间的距离。只需计算每个人与随机人的距离,然后只存储最低的十个值

    【讨论】:

    • 数据不是笛卡尔坐标。由于纬度/经度坐标会自行环绕,因此如果不先准备数据,那将无法正常工作。
    【解决方案3】:

    您可以使用 sklearn 中出色的 BallTree:

    import numpy as np
    from sklearn.neighbors import BallTree
    
    coords = np.random.random((750, 3)) * 2
    tree = BallTree(coords)
    random_person = np.random.choice(np.arange(750))
    closest_people = tree.query(coords[None, random_person], k=10)[1]
    

    【讨论】:

    • BallTree 确实有一个“haversine”距离度量,但它是一个二维纬度/经度测量值,据我所知不适用于高度。
    • 在对所使用的坐标系和单位采取一些措施之前,可能会出现问题。例如,第 180 条子午线穿过斐济,这会给这段代码带来问题。
    • 这不仅仅是haversine问题。在这个问题中(假设纬度/经度的度数),它在两个维度上比较了几百公里,在径向方向上没有单位。
    猜你喜欢
    • 2020-11-05
    • 2021-04-29
    • 1970-01-01
    • 1970-01-01
    • 2015-02-03
    • 1970-01-01
    • 2019-06-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多