通过两个大熊猫加快嵌套for循环DataFrames
我有存储在大熊猫数据帧(df
)与填充剂的斑点作为NaN
用于stop_id, stoplat, stoplon
纬度和经度,并且在另一个数据帧areadf
,其中包含多个拉特/经度和任意ID;这是要填充到df
的信息。通过两个大熊猫加快嵌套for循环DataFrames
我试图连接两个,以便df
中的停止列包含有关最靠近该经纬度点的停靠点的信息,如果在该点的半径R内没有停止,则将其保留为NaN
。
现在我的代码如下,但它需要很长的时间(对于我目前正在运行的内容,需要40分钟以上,在将区域更改为df并使用itertuples之前;不确定差别有多大这将使?),因为有成千上万的经纬度点,并停止每一组数据,这是一个问题,因为我需要在多个文件上运行此。我在寻找建议让它运行得更快。我已经做了一些小小的改进(例如移动到一个数据框,使用itertuples而不是iterrows,在循环外定义lats和lons,以避免在每个循环中从df检索它),但我没有想法加快速度。 getDistance
使用定义的Haversine公式来获得停车标志与给定经纬度之间的距离。
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的半正矢函数从here,只是略作修改,这样就可以解释半径你要。
刚刚通过您的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)
内申请,并找到最接近的值。然后合并这两个dataframes迭代。
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
注意:如果您选择按照这个方法,你必须确保两个dataframes指标复位,或者他们是按顺序从0责令DF的总LEN。所以一定要在运行这个之前重置索引。
df.reset_index(drop=True,inplace=True)
areadf.reset_index(drop=True,inplace=True)
这对加速算法非常有用!从几小时到几秒,还比我使用上面提到的pycon优化实现的方法快了几秒。非常感谢你! – amper
你可以使用,而不是用Cython pypy,pypy编译到c加快在蟒蛇循环 –
1.不要遍历这样的dataframes,采取大熊猫的优势2.使用欧几里得距离作为第一关,并拉出几个最接近的点,因为它比Haversine便宜3.将数据分成经纬网格,其中网格x及其周围8个单元格中的任何内容都不在网格y中的任何东西的R内,并在子集停靠点上运行。 – jeremycg
@jeremycg为了更好地利用熊猫,你有没有建议我研究的功能?谢谢您的回复! – amper