通过两个PANDAS数据框架加速嵌套的循环



我在pandas dataframe( df)中存储了一个纬度和经度,用于stop_id, stoplat, stoplon的填充点为NaN,在另一个dataframe areadf中,其中包含更多的lats/lons/lons和一个任意ID;这是要填充到df的信息。

我正在尝试连接两个,以便df中的停止列包含有关最接近该lat/lon点的停止的信息,或者如果在该点的半径R内没有停止,则将其作为NaN

现在我的代码如下,但是需要很长的时间(在我目前运行的时间> 40分钟之前,在更改DF和使用Itertuples之前;不确定这是什么区别会制造吗?)由于每组数据集都有成千上万的LAT/LON点,因此这是一个问题,因为我需要在多个文件上运行此数据。我正在寻找提出的建议,以使其运行速度更快。我已经做出了一些非常小的改进(例如,使用iTertuples而不是iTerrows,将lats和lons定义在循环外部,以避免在每个循环中从DF中检索它)超速加速。getDistance使用定义的Haversine公式来获取停止符号与给定的LON点之间的距离。

import pandas as pd
from math import cos, asin, sqrt
R=5
lats = df['lat']
lons = df['lon']
for stop in areadf.itertuples():
    for index in df.index:
        if getDistance(lats[index],lons[index],
                       stop[1],stop[2]) < R:
            df.at[index,'stop_id'] = stop[0] # id
            df.at[index,'stoplat'] = stop[1] # lat
            df.at[index,'stoplon'] = stop[2] # lon
def getDistance(lat1,lon1,lat2,lon2):
    p = 0.017453292519943295     #Pi/180
    a = (0.5 - cos((lat2 - lat1) * p)/2 + cos(lat1 * p) * 
         cos(lat2 * p) * (1 - cos((lon2 - lon1) * p)) / 2)
    return 12742 * asin(sqrt(a)) * 100

样本数据:

df
lat        lon         stop_id    stoplat    stoplon
43.657676  -79.380146  NaN        NaN        NaN
43.694324  -79.334555  NaN        NaN        NaN
areadf
stop_id    stoplat    stoplon
0          43.657675  -79.380145
1          45.435143  -90.543253

所需的:

df
lat        lon         stop_id    stoplat    stoplon
43.657676  -79.380146  0          43.657675  -79.380145
43.694324  -79.334555  NaN        NaN        NaN

一种方法是从这里使用numpy haversine函数,只是修改了,以便您可以考虑所需的半径。

使用apply的df正义迭代,并在给定半径内找到最接近的值

def haversine_np(lon1, lat1, lon2, lat2,R):
    """
    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
    if km.min() <= R:
        return km.argmin()
    else:
        return -1
df['dex'] = df[['lat','lon']].apply(lambda row: haversine_np(row[1],row[0],areadf.stoplon.values,areadf.stoplat.values,1),axis=1)

然后合并两个数据范围。

df.merge(areadf,how='left',left_on='dex',right_index=True).drop('dex',axis=1)
         lat        lon  stop_id    stoplat    stoplon
0  43.657676 -79.380146      0.0  43.657675 -79.380145
1  43.694324 -79.334555      NaN        NaN        NaN

NOTE :如果选择遵循此方法,则必须确保两个数据范围索引都是重置的,或者它们是从0到DF的总LEN依次订购的。因此,请确保在运行此之前重置索引。

df.reset_index(drop=True,inplace=True)
areadf.reset_index(drop=True,inplace=True) 

最新更新