【问题标题】:How to find the nearest neighbors for latitude and longitude point on python?如何在python上找到纬度和经度点的最近邻居?
【发布时间】:2016-09-16 09:35:01
【问题描述】:

输入:

point = (lat, long)
places = [(lat1, long1), (lat2, long2), ..., (latN, longN)]
count = L

输出: neighbors = 接近 pointplaces 的子集。 (len(neighbors)=L)

问题: 我可以使用 kd-tree 快速最近邻s 查找具有纬度和经度的点吗? (例如 scipy 中的实现)

坐标x,y中点的地理坐标(经纬度)是否需要变换?

这是解决这个问题的最佳方法吗?

【问题讨论】:

    标签: python geolocation scipy nearest-neighbor kdtree


    【解决方案1】:

    scikit-learn 提供了一个支持Haversine 指标的BallTree 类。另见this SO question

    【讨论】:

    • 这是最好的答案。
    【解决方案2】:

    老实说,我不知道使用 kd-tree 是否能正常工作,但我的直觉是它会不准确。

    我认为您需要使用更大的圆距离来获得准确的距离。

    
    from math import radians, cos, sin, asin, sqrt, degrees, atan2
    
    def validate_point(p):
        lat, lon = p
        assert -90 <= lat <= 90, "bad latitude"
        assert -180 <= lon <= 180, "bad longitude"
    
    # original formula from  http://www.movable-type.co.uk/scripts/latlong.html
    def distance_haversine(p1, p2):
        """
        Calculate the great circle distance between two points 
        on the earth (specified in decimal degrees)
        Haversine
        formula: 
            a = sin²(Δφ/2) + cos φ1 ⋅ cos φ2 ⋅ sin²(Δλ/2)
                            _   ____
            c = 2 ⋅ atan2( √a, √(1−a) )
            d = R ⋅ c
    
        where   φ is latitude, λ is longitude, R is earth’s radius (mean radius = 6,371km);
                note that angles need to be in radians to pass to trig functions!
        """
        lat1, lon1 = p1
        lat2, lon2 = p2
        for p in [p1, p2]:
            validate_point(p)
    
        R = 6371 # km - earths's radius
    
        # convert decimal degrees to radians 
        lat1, lon1, lat2, lon2 = map(radians, [lat1, lon1, lat2, lon2])
    
        # haversine formula 
        dlon = lon2 - lon1
        dlat = lat2 - lat1
    
        a = sin(dlat/2)**2 + cos(lat1) * cos(lat2) * sin(dlon/2)**2
        c = 2 * asin(sqrt(a)) # 2 * atan2(sqrt(a), sqrt(1-a))
        d = R * c
        return d
    

    【讨论】:

    • 在哪里可以找到此代码中使用的函数validate_point?我假设它检查纬度和经度是否在 -90 和 90 之间?
    • 这个答案有点不完整,没有回答 OP 的问题。函数distance_haversine() 计算以纬度/经度给出的两点之间的距离(以公里为单位),但它没有回答如何使用此度量找到最近邻居的问题。
    • @lumbric 从技术上讲你是正确的。我提供了如何计算距离的方法,因为问题的一部分是询问是否需要转换地理点。最终的答案是,如果使用 distance_havesine,您不需要转换它们。您只需找到到每组点的距离并选择最小的。
    • @MarcelWilson 啊,是的,你是对的,你的答案可以很容易地用于计算所有成对距离,然后取最小值。这是可能的,但不是最优的。对于较大的值(假设 >10 000 点),这将使用大量内存并花费大量时间。它需要 O(n^2) 时间和内存,而最佳解决方案应该是 O(n*log(n)) 时间,例如使用某种索引,如 k-trees。由于 OP 询问了 k-trees,我认为他对最佳解决方案感兴趣。
    • @MarcelWilson 是的,当然。如果距离很大,则信任欧几里得度量是有风险的。我认为应该可以找到使用 Haversine 度量解决 O(n*log(n)) 问题的算法。我不确定 KDTree,但 sklearn 中的 BallTree 支持 Haversine 指标(我不确定是否有任何陷阱)。
    【解决方案3】:

    认为您正在尝试解决k Nearest Neighbor 问题。

    由于您的数据集是二维的,所以 kd-tree 会很好地工作,一般来说,我不知道辣。

    但是,如果您的积分开始生活在更高的维度中,那么kd-tree will not be a smart choice

    【讨论】:

    • 数据未以 2D 形式给出,点以 lat/lon 为单位,无法准确转换为 2D 坐标。可以使用 Haversine 公式计算点之间的距离,但它与 2D 中的点不相同(我不知道 kd-tree 是否适用)。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-09-01
    相关资源
    最近更新 更多