Как рассчитать расстояние гаверсинуса между текущей и предыдущей строкой?

У меня есть df, который выглядит так, где я сгруппирован по идентификатору

 id     lat          lon
 1       NaN         NaN
 1       40.121      23.749
 1      -56.154     -39.572
 1       21.908      17.537
 1       31.221     -36.186
 1      -56.655      0.016
 2       NaN         NaN
 2      -36.438      14.874
 2      -21.422      81.271
 2       43.961     -95.551
 3       NaN         NaN
 3       79.821     -56.781

Используя функцию haversine, я хотел бы рассчитать расстояние от текущей строки до предыдущей строки. Таким образом, первая запись нового столбца будет рассчитана с использованием

широта 1 = 40,121

долгота 1 = 23,749

широта 2 = -56,154

долгота 2 = -39,572


person Del-m10    schedule 20.02.2019    source источник


Ответы (1)


Адаптировано из этого ответа. Связанный ответ показывает, как вычислить расстояние между каждой строкой и некоторым фиксированным значением долготы/широты - моя адаптация позволяет ему работать в вашем случае.

Во-первых, получите все необходимые значения в одной строке, используя shift:

df['lon2'] = df['lon'].shift(-1)
df['lat2'] = df['lat'].shift(-1)

Предоставление:

    id     lat     lon    lat2    lon2
0    1     NaN     NaN  40.121  23.749
1    1  40.121  23.749 -56.154 -39.572
2    1 -56.154 -39.572  21.908  17.537
3    1  21.908  17.537  31.221 -36.186
4    1  31.221 -36.186 -56.655   0.016
5    1 -56.655   0.016     NaN     NaN
6    2     NaN     NaN -36.438  14.874
7    2 -36.438  14.874 -21.422  81.271
8    2 -21.422  81.271  43.961 -95.551
9    2  43.961 -95.551     NaN     NaN
10   3     NaN     NaN  79.821 -56.781
11   3  79.821 -56.781     NaN     NaN

Затем определите функцию для расчета расстояния:

from numpy import cos, sin, arcsin, sqrt
from math import radians

def haversine(row):
    lon1 = row['lon']
    lat1 = row['lat']
    lon2 = row['lon2']
    lat2 = row['lat2']
    lon1, lat1, lon2, lat2 = map(radians, [lon1, lat1, lon2, lat2])
    dlon = lon2 - lon1 
    dlat = lat2 - lat1 
    a = sin(dlat/2)**2 + cos(lat1) * cos(lat2) * sin(dlon/2)**2
    c = 2 * arcsin(sqrt(a)) 
    km = 6367 * c
    return km

И примените его к своим данным, используя apply:

df['distance'] = df.apply(haversine, axis=1)

Предоставление:

    id     lat     lon    lat2    lon2      distance
0    1     NaN     NaN  40.121  23.749           NaN
1    1  40.121  23.749 -56.154 -39.572  12237.017692
2    1 -56.154 -39.572  21.908  17.537  10187.684397
3    1  21.908  17.537  31.221 -36.186   5387.540299
4    1  31.221 -36.186 -56.655   0.016  10343.267833
5    1 -56.655   0.016     NaN     NaN           NaN
6    2     NaN     NaN -36.438  14.874           NaN
7    2 -36.438  14.874 -21.422  81.271   6543.302199
8    2 -21.422  81.271  43.961 -95.551  17480.809345
9    2  43.961 -95.551     NaN     NaN           NaN
10   3     NaN     NaN  79.821 -56.781           NaN
11   3  79.821 -56.781     NaN     NaN           NaN

Который, я считаю, показывает результаты, которые вы ищете (я протестировал первый, и он кажется правильным).

Если хотите, вы можете избавиться от двух вторичных столбцов широта/долгота после завершения вычислений:

df.drop(['lat2', 'lon2'], axis=1, inplace=True)

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

person thesilkworm    schedule 20.02.2019
comment
Спасибо за помощь! Один быстрый вопрос: когда вы используете функцию haversine в apply (), почему вам не нужно также вставлять аргумент? - person Del-m10; 21.02.2019
comment
apply() эффективно перебирает каждую строку, автоматически передавая строку (или столбец, если вы установите ось = 0, а не 1) в качестве параметра функции. - person thesilkworm; 21.02.2019