Python - 3 番目の列の異なる値ごとに、行とその直前の行の間の距離を計算するにはどうすればよいですか?

okwaves2024-01-24  4

次のようなデバイス、日付、緯度/経度の列を含むデータフレームがあります。

e5c0e3a5    2019-09-23 00:25:48 -44.132 -30.369
e5c0e3a5    2019-09-23 00:30:48 -43.437 -30.633
...
a5c0d8b8    2019-09-23 03:20:48 -30.132 -40.369
a5c0d8b8    2019-09-23 03:50:12 -30.437 -41.633

レコードはユーザーごとおよび時間ごとに並べ替えられます。時刻 t と時刻 t+1 (または、最初の nan、t、t-1 を避けるために、行 2 から開始) における各ユーザーの移動距離を測定する必要があります。

from geopy. distance import geodesic 関数を使用して距離を計算しており、結果として次のスタイルのデータフレームが必要です。

e5c0e3a5    2019-09-23 00:25:48 20
a5c0d8b8    2019-09-23 03:50:12 50
...

行 2 を取得し、行 1 の距離を測定することで、距離 (km) が 20 であると計算しました。

より一般的に言えば、ある行とその直前の行の間で、異なるデバイスごとに操作 (測地線) を実行するにはどうすればよいでしょうか?



------------------------

私はベクトル化されたアプローチを試しました: geodesic(df[['long', 'lat']].to_numpy(), df[['s_long', 's_lat']].to_numpy()) ただし、測地線は配列では機能しません。 順次シフトされる各行間の距離 pandas.Series.shift と .apply の使用
import pandas as pd
from geopy.distance import geodesic

# set up data and dataframe; extra data has been added
data = {'code': ['e5c0e3a5', 'e5c0e3a5', 'e5c0e3a5', 'a5c0d8b8', 'a5c0d8b8', 'a5c0d8b8'],
        'datetime': ['2019-09-23 00:25:48', '2019-09-23 00:30:48', '2019-09-23 00:35:48', '2019-09-23 03:20:48', '2019-09-23 03:50:12', '2019-09-23 04:00:12'],
        'long': [-44.132, -43.437, -40.654, -30.132, -30.437, -30.000],
        'lat': [-30.369, -30.633, -29.00, -40.369, -41.633, -43.345]}

df = pd.DataFrame(data)

# sort the dataframe by code and datetime
df = df.sort_values(['code', 'datetime']).reset_index(drop=True)

# # add a shifted columns
df[['s_long', 's_lat']] = df[['long', 'lat']].shift(-1)

# # drop na; the first shifted row will be nan, which won't work with geodesic
df.dropna(inplace=True)

# # apply geodesic to calculate distance between each sequentially shifted row
df['distance_miles'] = df[['long', 'lat', 's_long', 's_lat']].apply(lambda x: geodesic((x[0], x[1]), (x[2], x[3])).miles, axis=1)

# display(df)
       code             datetime    long     lat  s_long   s_lat  distance_miles
0  a5c0d8b8  2019-09-23 03:20:48 -30.132 -40.369 -30.437 -41.633        78.43026
1  a5c0d8b8  2019-09-23 03:50:12 -30.437 -41.633 -30.000 -43.345       106.74601
2  a5c0d8b8  2019-09-23 04:00:12 -30.000 -43.345 -44.132 -30.369      1206.65789
3  e5c0e3a5  2019-09-23 00:25:48 -44.132 -30.369 -43.437 -30.633        49.76606
4  e5c0e3a5  2019-09-23 00:30:48 -43.437 -30.633 -40.654 -29.000       209.63396
コードグループ内のみの距離 .groupby 'code' および .GroupBy.apply 関数、get_ distance。 関数内のコードは、グループごとに適用されることを除いて、前のコードと同じです。
def get_distance(d: pd.DataFrame) -> pd.DataFrame:
    v = d.copy()  # otherwise, working on d will do an inplace update to df, which will cause unexpected/undesired results.
    v.drop(columns=['code'], inplace=True)  # code will be in the index, so a code column is not needed
    v[['s_long', 's_lat']] = v[['long', 'lat']].shift(-1)
    v.dropna(inplace=True)
    v['dist_miles'] = v[['long', 'lat', 's_long', 's_lat']].apply(lambda x: geodesic((x['long'], x['lat']), (x['s_long'], x['s_lat'])).miles, axis=1)
    return v


# set up data and dataframe; extra data has been added
data = {'code': ['e5c0e3a5', 'e5c0e3a5', 'e5c0e3a5', 'a5c0d8b8', 'a5c0d8b8', 'a5c0d8b8'],
        'datetime': ['2019-09-23 00:25:48', '2019-09-23 00:30:48', '2019-09-23 00:35:48', '2019-09-23 03:20:48', '2019-09-23 03:50:12', '2019-09-23 04:00:12'],
        'long': [-44.132, -43.437, -40.654, -30.132, -30.437, -30.000],
        'lat': [-30.369, -30.633, -29.00, -40.369, -41.633, -43.345]}

df = pd.DataFrame(data)

# sort the dataframe by code and datetime
df = df.sort_values(['code', 'datetime']).reset_index(drop=True)

# apply the function to the groups
test = df.groupby('code').apply(get_distance)

# display(test)
                       datetime    long     lat  s_long   s_lat  dist_miles
code                                                                       
a5c0d8b8 0  2019-09-23 03:20:48 -30.132 -40.369 -30.437 -41.633    78.43026
         1  2019-09-23 03:50:12 -30.437 -41.633 -30.000 -43.345   106.74601
e5c0e3a5 3  2019-09-23 00:25:48 -44.132 -30.369 -43.437 -30.633    49.76606
         4  2019-09-23 00:30:48 -43.437 -30.633 -40.654 -29.000   209.63396

0

総合生活情報サイト - OKWAVES
総合生活情報サイト - OKWAVES
生活総合情報サイトokwaves(オールアバウト)。その道のプロ(専門家)が、日常生活をより豊かに快適にするノウハウから業界の最新動向、読み物コラムまで、多彩なコンテンツを発信。