遍历pandas坐标组并计算距离

3

我有一个csv数据集,看起来像这样:

    created_date,latitude,longitude
"2018-10-02 16:52:54",20.56314546,-100.40871983
"2018-10-07 18:06:37",20.56899227,-100.40879701
"2018-10-08 11:55:31",20.57479211,-100.39687493
"2018-10-08 11:55:31",20.58076244,-100.36075875
"2018-10-08 11:55:31",20.60529101,-100.40951731
"2018-10-08 11:55:31",20.60783806,-100.37852743
"2018-10-09 18:10:00",20.61098901,-100.38008197
"2018-10-09 18:10:00",20.61148848,-100.40851908
"2018-10-09 18:10:00",20.61327334,-100.34415272
"2018-10-09 18:10:00",20.61397514,-100.33583425

我正在尝试使用pandas将数据按日期分组,并希望遍历每个组并使用haversine函数计算每个组中纬度、经度之间的距离,该函数需要两个坐标作为参数。
为此,我必须计算例如coord1与coord2,coord2与coord3等(从组中)的距离。
我想这样做是为了计算平均行驶距离。然后,我需要将距离相加并除以组数以得到结果。
使用pandas,我已经成功将数据分成了组,但我不确定如何遍历这些组,同时排除没有两个坐标可用于计算距离的组(例如"2018-10-02 16:52:54")。
我的当前Python脚本如下:
col_names = ['date', 'latitude', 'longitude']
data = pd.read_csv('dataset.csv', names=col_names, sep=',', skiprows=1)
grouped = data.groupby('date')
for index, item in grouped:

非常感谢您的咨询。针对您提出的问题,我会尽全力为您解答。根据我理解,您需要一些关于压缩文件的工具和技巧。zip工具可能能够帮助您完成这个任务,但是具体如何操作我还需要了解更多细节。如果您能提供更多信息,我将可以更好地为您提供帮助。


1
使用lambda和groupby进行分组,并定义一个可用于定义距离的函数。 - mad_
1
@mad_'s的评论是正确的方法。如果您可以提供您的函数定义(即使是粗略的定义)和代码,那么我们可以帮助您微调解决方案。 - rahlf23
1个回答

2

这里有一个选项。它涉及在组内执行大量合并,给出所有成对组合。然后删除所有相同行的合并,你就可以计算距离了。

import pandas as pd
import numpy as np

def haversine(lon1, lat1, lon2, lat2):
    # convert degrees to radians 
    lon1 = np.deg2rad(lon1)
    lat1 = np.deg2rad(lat1)
    lon2 = np.deg2rad(lon2)
    lat2 = np.deg2rad(lat2)

    # formula 
    dlon = lon2 - lon1 
    dlat = lat2 - lat1 
    a = np.sin(dlat/2)**2 + np.cos(lat1) * np.cos(lat2) * np.sin(dlon/2)**2
    c = 2 * np.arcsin(np.sqrt(a)) 
    r_e = 6371 
    return c * r_e

代码:

# merge
m = df.reset_index().merge(df.reset_index(), on='created_date')

# remove comparisons of the same event
m = m[m.index_x != m.index_y].drop(columns = ['index_x', 'index_y'])

# Calculate Distance
m['Distance'] = haversine(m.longitude_x, m.latitude_x, m.longitude_y, m.latitude_y)

输出: m

           created_date  latitude_x  longitude_x  latitude_y  longitude_y  Distance
3   2018-10-08 11:55:31   20.574792  -100.396875   20.580762  -100.360759  3.817865
4   2018-10-08 11:55:31   20.574792  -100.396875   20.605291  -100.409517  3.637698
5   2018-10-08 11:55:31   20.574792  -100.396875   20.607838  -100.378527  4.141211
...
30  2018-10-09 18:10:00   20.613975  -100.335834   20.610989  -100.380082  4.617105
31  2018-10-09 18:10:00   20.613975  -100.335834   20.611488  -100.408519  7.569825
32  2018-10-09 18:10:00   20.613975  -100.335834   20.613273  -100.344153  0.869261

获取每个日期的平均值:
m.groupby('created_date').Distance.mean()

#created_date
#2018-10-08 11:55:31    4.021623
#2018-10-09 18:10:00    4.411060
#Name: Distance, dtype: float64

如之前所述,我们对合并的DataFrame进行了子集处理,因此这只会提供具有超过1个测量值的created_dates的输出。


要根据date而不是精确时间进行合并:

df['created_date'] = pd.to_datetime(df.created_date)
df['ng'] = df.groupby(df.created_date.dt.date).ngroup()

m = df.reset_index().merge(df.reset_index(), on='ng')
m = m[m.index_x != m.index_y].drop(columns = ['index_x', 'index_y'])

...

谢谢,那帮了我很多。但是,如果我不按时间戳分离数据,似乎无法获得每日平均值。你有什么想法吗?我想我需要创建一个新的索引来完成合并? - Luis
@Louis 如果要按照“日期”而不是时间戳合并,首先需要将其转换为datetime:“df['created_date'] = pd.to_datetime(df.created_date)”,然后可以创建一个组号:“df['ng'] = df.groupby(df.created_date.dt.date).ngroup()”,然后您应该能够按照上述方式仅使用“on ='ng'”进行合并。确保在合并时重置索引,然后删除索引相等的部分即可。 - ALollz
你可以考虑定义一个新的“日期”列,该列仅包含“created_date_x”或“created_date_y”的日期组成部分。 - ALollz
@ALollz 这是英里还是公里?或者我需要另一个函数将输出转换为这些度量单位之一?最好是英里? - Emm

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接