计算多点之间地理空间距离的最有效方法?

Posted

技术标签:

【中文标题】计算多点之间地理空间距离的最有效方法?【英文标题】:The most efficient way to calculate geospatial distances between many points? 【发布时间】:2019-09-07 17:47:29 【问题描述】:

我有两个数据集,一个描述位置,第二个有不同的点:

locations.head()
  latitude  longitude  geobounds_lon1  geobounds_lat1  geobounds_lon2  geobounds_lat2
0  52.5054   13.33320        13.08830         52.6755         13.7611         52.3382      
1  54.6192    9.99778         7.86496         55.0581         11.3129         53.3608     
2  41.6671  -71.27420       -71.90730         42.0188        -71.0886         41.0958    
3  25.9859  -80.12280       -87.81370         30.9964        -78.9917         24.5071   
4  43.7004   11.51330         9.63364         44.5102         12.4104         42.1654     

points.head()
   category        lat        lon
0       161  47.923132  11.507743 
1       161  47.926479  11.531736 
2       161  47.943670  11.576099   
3       161  57.617577  12.040591  
4        23  52.124071  -0.491918  

我需要计算从每个报价(基于locations.latitudelocations.longitude)到每个类别的每个点(例如161)的距离。对我来说,只有离位置不太远的这些点很重要——我认为使用位置边界可能会有所帮助,所以我不需要计算所有距离然后过滤它们。

对我来说最大的问题是如何有效地过滤每个位置的点(基于类别和边界)并计算从位置点到这些点的距离,因为数据数量非常大(位置和位置几乎有 900 万行)超过 1000 万行点)。

对于距离计算,我尝试了BallTree

RADIANT_TO_KM_CONSTANT = 6367

class BallTreeIndex:
    def __init__(self,lat_longs):
        self.lat_longs = np.radians(lat_longs)
        self.ball_tree_index = BallTree(self.lat_longs, leaf_size=40, metric='haversine')

    def query_radius(self,query,radius):
        radius_radiant = radius / RADIANT_TO_KM_CONSTANT 
        query = np.radians(np.array([query]))
        result = self.ball_tree_index.query_radius(query, r=radius_radiant,
                                                return_distance=True) 
        return result[1][0]

对于过滤点:

condition = (points.category == c) & (points.lat > lat2) & (points.lat < lat1) & (points.lon < lon2) & (points.lon > lon1)
tmp = points[condition]

其中c 是特定类别,lat1lat2lon1lon2 是位置边界。 但是,这会花费很多时间,所以我想知道是否有任何方法可以使其更快。

我想在位置数据框中添加一个新列,例如:

                    distances_161
0 [distance0_0, distance0_1, ...]
1 [distance1_0, distance1_1, ...]
2 [distance2_1, distance2_2, ...]

【问题讨论】:

【参考方案1】:

我不能 100% 确定这是您想要的,但对我来说似乎很有意义。

import numpy as np
import pandas

def haversine_np(lon1, lat1, lon2, lat2):
    """
    Calculate the great circle distance between two points
    on the earth (specified in decimal degrees)

    All args must be of equal length.    

    """
    lon1, lat1, lon2, lat2 = map(np.radians, [lon1, lat1, lon2, lat2])

    dlon = lon2 - lon1
    dlat = lat2 - lat1

    a = np.sin(dlat/2.0)**2 + np.cos(lat1) * np.cos(lat2) * np.sin(dlon/2.0)**2

    c = 2 * np.arcsin(np.sqrt(a))
    km = 6367 * c
    return km




df = 'lon1': [40.7454513], 
'lat1': [-73.9536799], 
'lon2': [40.7060268], 
'lat2': [-74.0110188]
df


df['distance'] = haversine_np(df['lon1'],df['lat1'],df['lon2'],df['lat2'])

结果:

array([6.48545403])

所以,Python 说的是 6.485 英里,而 Google 说的是 6.5 英里。

【讨论】:

以上是关于计算多点之间地理空间距离的最有效方法?的主要内容,如果未能解决你的问题,请参考以下文章

在红宝石中计算汉明距离的最有效方法?

用弧度计算地理空间距离

如何获得两个地理点坐标之间的最短行驶路径和距离?

Python 优雅地利用两点经纬度计算地理空间距离

Python 优雅地利用两点经纬度计算地理空间距离

计算两个地理位置之间的距离