Python 将函数应用于组,并过滤原始数据帧
我有一个包含对象及其坐标的数据框:Python 将函数应用于组,并过滤原始数据帧,python,pandas,dataframe,group-by,split-apply-combine,Python,Pandas,Dataframe,Group By,Split Apply Combine,我有一个包含对象及其坐标的数据框: id lat lng 0 3816 18.384001 -66.114799 1 5922 20.766100 -156.434998 2 1527 21.291394 -157.843085 3 1419 21.291394 -157.843085 4 1651 21.291394 -157.843085 多个对象可以具有相同的坐标。数据帧很大(数百万条记录)。我有一个坐标为(tar
id lat lng
0 3816 18.384001 -66.114799
1 5922 20.766100 -156.434998
2 1527 21.291394 -157.843085
3 1419 21.291394 -157.843085
4 1651 21.291394 -157.843085
多个对象可以具有相同的坐标。数据帧很大(数百万条记录)。我有一个坐标为(target\u lat,target\u lng)
的目标点。我的目标是尽可能高效地在数据帧中找到距离目标点X英里以内的对象
我正在使用改编自的haversine\u np
函数。它采用参数(lat\u系列,lng\u系列,lat,lng)
,并有效地计算lat\u系列,lng\u系列
(两个系列)和(lat,lng)
(两个数字)之间的所有距离
现在我的问题是如何使用它来过滤距离并选择原始数据帧中的对象
df[mask]
这是我当前的解决方案:
grouper = df.groupby(['lat', 'lng'], sort=False).grouper
lat_series = grouper.result_index.get_level_values(0) # lats of unique (lat, lng) pairs
lng_series = grouper.result_index.get_level_values(1) # lngs of unique (lat, lng) pairs
df['location_index'] = grouper.group_info[0] # assign index of group back to df
distances = haversine_np(lat_series, lng_series, target_lat, target_lng)
mask = distances <= 50 # let's say 50 miles; boolean mask of size = ngroups
loc_indexes = pd.Series(range(grouper.ngroups))[mask] # select group indexes by mask
df[df.location_index.isin(loc_indexes)] # select original records by group indexes
grouper=df.groupby(['lat','lng',sort=False)。grouper
lat_系列=grouper.result_index.get_level_值(0)#唯一(lat,lng)对的lat
lng_series=grouper.result_index.get_level_值(1)#唯一(lat,lng)对的lng
df['location_index']=grouper.group_info[0]#将组的索引分配回df
距离=haversine_np(lat_系列、lng_系列、target_lat、target_lng)
掩码=距离更新:-这里是一个小演示:
In [115]: df
Out[115]:
id lat lng
5 4444 40.0 -121.0
0 1111 40.0 -120.0
In [116]: %paste
threshold = 60
max_lng_factor = 69.17
max_lat_factor = 69.41
target_lat, target_lng = 40, -120
mask = df.lat.sub(target_lat).abs().le(threshold/max_lat_factor) \
& \
df.lng.sub(target_lng).abs().le(threshold/max_lng_factor)
x = df.loc[mask, ['lat','lng']].drop_duplicates()
## -- End pasted text --
In [117]: x
Out[117]:
lat lng
0 40.0 -120.0
如果这两个坐标之间的距离小于我们的阈值(60英里):
结论:我们可以预先过滤纬度,但不能过滤经度:
In [131]: df
Out[131]:
id lat lng
5 4444 40.0 -121.0
0 1111 40.0 -120.0
1 2222 42.0 -121.0
正确的预筛选:
In [132]: mask = df.lat.sub(target_lat).abs().le(threshold/max_lat_factor)
...: x = df.loc[mask, ['lat','lng']].drop_duplicates()
...:
In [133]: x
Out[133]:
lat lng
5 40.0 -121.0
0 40.0 -120.0
检查:
In [135]: df.reset_index() \
...: .merge(x.assign(distance=haversine_np(x.lng, x.lat, target_lng, target_lat))
...: .query("distance <= @threshold"),
...: on=['lat','lng'])
...:
Out[135]:
index id lat lng distance
0 5 4444 40.0 -121.0 52.895044
1 0 1111 40.0 -120.0 0.000000
[135]中的:df.reset_index()\
…:.merge(x.assign(距离=haversine\u np(x.lng,x.lat,target\u lng,target\u lat))
…:.query(“distance也许我在效率方面遗漏了一些东西,但我不明白您为什么要使用.gropper方法。
要获得Lat和长序列,只需参考它们,即df['Lat']或df.Lat,然后您可以直接使用
distances = haversine_np(df.lat, df.lng, target_lat, target_lng)
并创建一个带有
mask = distances <= 50
将只提供真实的元素。这里的问题是lat/lng
列中有许多重复值,我只想计算唯一值的haversine_np
。否则,是的,您的方法将是最简单的方法。其中一个问题是,1度经度仅在赤道,离两极越近,它越小,这将错误地排除距离足够近但经度足够远的点。如果我错了,请纠正我,但我认为这是错误的。最大因子是分母(threshold/max\u lng\u factor
),所以因子最大的矩形实际上是最小的。但是靠近极点的矩形应该更大,所以因子应该更小(在极点处降到零)希望我的解释是有意义的。@ DennisGolomazov,我想你是对的。所以我们只能预过滤<代码>纬度<代码>,而不是<代码>经度< /代码>。这是一个例子。让<代码> TajixLAT,TajiTyLNG =(40,-120)。考虑<代码>点=(40,-121)。
和threshold=60
。那么您的函数将不会选择此点,因为threshold/max_lng_factor=0.867
和df.lng.sub(target_lng).abs()=121-120=1
。但实际上,这些点之间的距离是85km=52.8英里<60
,因此应该选择该点。@DennisGolomazov,是的,非常好的示例-谢谢!你完全正确!我将更正答案。。。
distances = haversine_np(df.lat, df.lng, target_lat, target_lng)
mask = distances <= 50
df[mask]