Мне очень жаль, что я задаю много pandas вопросов, я пытаюсь найти расстояние между точками, но там, где существует только один экземпляр user_id
, я не хочу передавать эти пары в функцию гаверсинуса , потому что нет второй пары для вычисления c расстояния. Пример моего кода с использованием случайных данных.
import numpy as np
import pandas as pd
from itertools import chain, repeat
#dict of random data
d = {
'user_id':[4,4,1,2,2,2,7,9,9,10],
'lat':10 + np.random.sample(10) * 80,
'lon':10 + np.random.sample(10) * 80,
'distance_km':list(chain.from_iterable(repeat(0.0,10) for y in range(1))),
'speed_kms':list(chain.from_iterable(repeat(0.0,10) for y in range(1))),
'time':['04:56:14','20:04:45','09:37:51','10:53:44','11:12:17','16:55:52',
'04:49:31','16:23:53','03:23:21','14:21:04'],
'char_class':[True,True,True,False,False,False,False,False,False,False],
'type':list(chain.from_iterable(repeat('n/a',10) for z in range(1)))
}
#make df from dict
df = pd.DataFrame.from_dict(d,orient='index').transpose()
#sort the df
df.sort_values(['user_id','time','char_class'],ascending=[False,True,False],inplace=True)
#zip latlon together to make tuples for below
df['paired'] = list(zip(df.lat,df.lon))
#find elapsed time for user pairs. [not displayed to save some space]
df['elapsed'] = df.sort_values(['user_id','time']).groupby('user_id')['time']
.diff().fillna(pd.Timedelta(seconds=0))
#find dist from points
df.distance_km = df.groupby(['user_id','distance_km']).apply(
haversine_func(df['paired']-df['paired']
.shift())).fillna(0.0)
дает следующий фрейм данных: (Я не указывал столбец прошедшего времени, потому что он просто занимает больше места)
user_id lat lon distance_km speed_kms time char_class type paired
9 10 18.3099 37.5837 0 0 14:21:04 False n/a (18.309894682687393, 37.58366365422602)
8 9 56.4528 61.2092 0 0 03:23:21 False n/a (56.45283963809377, 61.20921073451559)
7 9 33.6459 86.8489 0 0 16:23:53 False n/a (33.645852426505236, 86.84885897513892)
6 7 46.2825 72.0214 0 0 04:49:31 False n/a (46.28253581704867, 72.02142769672362)
0 4 39.9998 75.7089 0 0 04:56:14 True n/a (39.99977593402277, 75.70892442647698)
1 4 18.8519 44.46 0 0 20:04:45 True n/a (18.851925780806642, 44.4600341643822)
3 2 31.9623 74.1928 0 0 10:53:44 False n/a (31.962265405454502, 74.19275419456591)
4 2 71.3837 25.2423 0 0 11:12:17 False n/a (71.38367453710737, 25.242261227675755)
5 2 36.0831 43.7794 0 0 16:55:52 False n/a (36.08311981908213, 43.77939369677742)
2 1 61.1941 68.2175 0 0 09:37:51 True n/a (61.19413548303556, 68.2174579805573)
Я не хочу публиковать haversine_func
, но tl; dr берет пары кортежей (и дополнительные единицы измерения) и вычисляет их, чтобы найти расстояние. Когда я передаю его в .apply
, я получаю сообщение об ошибке:
File: 'blah', line 65:
lat1, lon1 = point1
ValueError: not enough values to unpack (expected 2 got 1)
Я предполагаю, что проблема связана с одиночным user_id
s (1
, 7
, 10
), имеющим только единственная точка. Есть ли способ, которым я могу pandas
распознавать ТОЛЬКО дубликат user_id
s и заполнять отдельные вхождения с помощью 0.0
?
небольшого псевдокода для того, что я пытаюсь сделать:
for pairs in paired:
if user_id == user_id.shift():
haversine(paired, paired.shift())
#replace df['distance'] with above haversine return vals, or 0.0 as appropriate
Я бы хотел, чтобы результат выглядел так:
user_id lat lon distance_km speed_kms time char_class type
9 10 18.3099 37.5837 0.0 0 14:21:04 False n/a
8 9 56.4528 61.2092 0.0 0 03:23:21 False n/a
7 9 33.6459 86.8489 [calced_val] 0 16:23:53 False n/a
6 7 46.2825 72.0214 0.0 0 04:49:31 False n/a
0 4 39.9998 75.7089 0.0 0 04:56:14 True n/a
1 4 18.8519 44.46 [calced_val] 0 20:04:45 True n/a
3 2 31.9623 74.1928 0.0 0 10:53:44 False n/a
4 2 71.3837 25.2423 [calced_val] 0 11:12:17 False n/a
5 2 36.0831 43.7794 [calced_val] 0 16:55:52 False n/a
2 1 61.1941 68.2175 0.0 0 09:37:51 True n/a