Итерация по группам координат панд и вычисление расстояний

У меня есть набор данных 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, которая принимает 2 координаты в качестве параметров.

Для этого я должен рассчитать расстояние, скажем, coord1 with coord2, coord 2 with coord 3 and so on (from the group)

Я хочу сделать это, чтобы рассчитать среднее пройденное расстояние. Затем мне нужно было бы сложить расстояния и разделить их на количество групп.

С пандами мне удалось разделить свои данные на группы, но я не уверен, как перебирать эти группы, исключая группы (скажем, «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, могут помочь мне в этом.


person Luis    schedule 15.10.2018    source источник
comment
используйте groupby с лямбдой. и определите функцию, которая может использоваться для определения расстояния   -  person mad_    schedule 15.10.2018
comment
Комментарий @mad_ - правильный подход. Если вы можете предоставить свое определение функции (даже грубое определение) с кодом, мы сможем помочь вам настроить решение.   -  person rahlf23    schedule 15.10.2018


Ответы (1)


Вот один вариант. Он включает в себя огромное слияние внутри групп, дающее все попарные комбинации. Затем удалите все одинаковые слияния строк, и вы сможете вычислить расстояния один раз.

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, это обеспечит выходные данные только для created_dates с более чем 1 измерением.


Для слияния на 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'])

...
person ALollz    schedule 15.10.2018
comment
Спасибо, это мне очень помогло. Тем не менее, я не могу получить среднее значение за день, если я не разделяю свои данные по дням, а не по отметке времени. Любая идея о том, как я это сделаю? Я полагаю, мне придется создать новый индекс, в котором выполняется слияние? - person Luis; 15.10.2018
comment
@Louis Чтобы объединиться на основе date, а не метки времени, я бы сначала преобразовал в дату и время: df['created_date'] = pd.to_datetime(df.created_date), а затем вы можете создать номер группы: df['ng'] = df.groupby(df.created_date.dt.date).ngroup(), а затем вы сможете просто объединить on='ng', как указано выше. Обязательно сбросьте индекс при слиянии, а затем отбросьте его туда, где индексы равны. - person ALollz; 15.10.2018
comment
Вы можете рассмотреть возможность определения нового столбца «Дата», который является просто компонентом даты либо created_date_x, либо created_date_y. - person ALollz; 15.10.2018
comment
@ALollz это в милях или км? Или мне нужна другая функция для преобразования вывода этого в одно из этих измерений? Желательно мили? - person Emm; 20.09.2020