【发布时间】:2020-11-24 23:08:59
【问题描述】:
问题总结:
我有两个数据框。第一个数据帧 (df1) 相对较小(几乎总是少于 100 个观测值,通常少于 50 个),具有一组点标识符及其纬度/经度坐标。第二个数据框(df2)非常大(数十万个观测值),它也有纬度/经度坐标。我希望在 df2 中创建两个新列:第一个具有离 df1 最近的点的标识符,第二个具有到该点的距离。我目前的方法非常笨拙,我认为可以显着优化。对于其他上下文,有一个 df1(小数据帧),但我将对多个 df2s(大数据帧)重复此过程。
设置/示例数据:
# imports:
import pandas as pd
import geopy.distance
from faker import Faker
# creating sample data:
Faker.seed(0)
fake=Faker()
id1=[]
lat1=[]
lon1=[]
id2=[]
lat2=[]
lon2=[]
length1=10 # length of df1
length2=100 # length of df2
for x in range(length1):
a=fake.local_latlng()
id1.append(x)
lat1.append(float(a[0]))
lon1.append(float(a[1]))
for x in range(length2):
a=fake.local_latlng()
id2.append(x)
lat2.append(float(a[0]))
lon2.append(float(a[1]))
dict1={
'loc_id' : id1,
'lat' : lat1,
'lon' : lon1,
}
dict2={
'point_id' : id2,
'lat' : lat2,
'lon' : lon2,
}
df1=pd.DataFrame(dict1)
df2=pd.DataFrame(dict2)
当前解决方案:
# calculating distances:
for x in range(len(df1)):
loc_id=df1.iloc[x]['loc_id']
pt1=(df1.iloc[x]['lat'],df1.iloc[x]['lon'])
for y in range(len(df2)):
pt2=(df2.iloc[y]['lat'],df2.iloc[y]['lon'])
dist=geopy.distance.distance(pt1,pt2).miles
df2.loc[y,x]=dist
# determining minimum distance and label:
temp_cols=list(range(len(df1)))
df2['min_dist']=df2[temp_cols].min(axis=1)
df2['min_loc']=df2[temp_cols].idxmin(axis=1)
# removing extra columns:
df2=df2.drop(temp_cols,axis=1)
print(df2.head())
可能的解决方案:
这段代码显然很慢,因为我计算了每对点的距离。从概念上讲,我认为这可以改进,但我在实施改进时遇到了麻烦。一些想法:
- 矢量化操作。 This 接受的答案似乎表明对向量的操作更快,但我不知道如何在向量上实现 geopy.distance.distance() 函数(或者如果可能的话)。
- 通过比较可以说是“支配”的点来消除点。这样,例如,如果一个点在纬度/经度上都比另一个大,那么当与我必须检查的集合中的纬度/经度点中较小的点进行比较时,我可能能够消除它。我想这会增加前端的工作/处理,但最终会通过减少我为每个点检查的点数来获得回报。不过,弄清楚该算法对我来说并不明显。
- 我也许可以将点进行某种分箱,将它们分成彼此相邻的组,从而获得更小的候选集以相互比较。也许有可能在计算距离之前找出最近的点。危险在于 df1 中的某些点也可能非常接近。
其他详情: 两点具有相同距离的几率很小,如果出现的话,我很高兴随机选择任何最接近的点。
【问题讨论】:
标签: python pandas latitude-longitude nearest-neighbor geopy