Я пытаюсь создать отчет сводной таблицы, который подсчитывает, сколько минут в час водитель находился в сети. Однако мои данные получают неверные результаты, выделенные красным цветом - это точки в данных, где они должны выводить 1 или 100% в режиме онлайн, но они не отображаются наиболее вероятно из-за того, как я работаю с агрегацией данных.
Как вы можете видеть, потому что нет никаких изменений событий в часах 15:00 и 20:00, они заканчиваются как пустые, когда я начинаю выполнять функцию поворота
Вот что я делаю
1.) Я добавляю новые функции для даты и часа, которые будут использоваться для фильтрации в серверной части. Я извлекаю дату и час из столбца отметок времени состояния
2.) Я генерирую задержку и опережение строки данных для сопоставления и проверки смысла для отметок времени следующего и предыдущего события.
В конце концов я буду вычислять для каждой строки начальную временную метку (status_timestamp) и следующую временную метку (lead_status_timestamp), чтобы получить мою продолжительность
, то есть 10:00 |10:30 = 30 минут продолжительности или 50% онлайн в час 10: 00
3.) Я создаю потолок и настил текущей метки времени для правильного определения и выполнения проверок работоспособности.
Есть общие случаи, когда мне нужна эта логика
CASE 1: where event is the first event of the day and timestamps intesect two hours
initialDF
previous | current | next | hour
NaT | 10:58 | 11:05 | 10:00
@apply ceiling to next
previous | current | next | hour
NaT | 10:58 | 11:00 | 10:00
calculate timediff = 2 mins for hour10:00
CASE 2: where event isn't first of the day and timestamp doesn't intersect
initialDF
previous | current | next | hour
9:59 | 10:58 | 10:30 | 10:00
@apply flooring
previous | current | next | hour
9:59 | 10:00 | 10:30 | 10:00
duration calculated as 30minutes
CASE 3:
where event is the last of the day and next timestamp doesn't exist
initialDF
previous | current | next | hour
9:59 | 10:58 | NaT | 10:00
@applyFlooring and change next timestamp to current timestamp
previous | current | next | hour
9:59 | 10:00 | 10:58 | 10:00
duration calculated as 58 minutes
Мне нужна помощь в этом случае
CASE4: where current and next timestamp intersect two hour zones
initialDF
previous | current | next | hour
9:59 | 10:05 | 12:05 | 10:00
because there was no change in events in between hours for this timestamp I cannot calculate the hour duration elapsed for 11:00
I am expected the result to be like this
10:00 60 minutes
11:00 60 minutes
12:00 5 minutes
and the table will look like this
@expectation
driverID 10:00 | 11:00 | 12:00
12345 60 | 60 | 5
but my code output ends up this result which is wrong
@reality
driverID 10:00 | 11:00 | 12:00
12345 60 | | 5
the eleventh hour becomes blank because I have no identifier for it in the raw data.
вот пример кода
datadict = {'driver_id': {1753: '1AA',
1754: '1AA',
1755: '1AA',
1756: '1AA',
1757: '1AA',
1758: '1AA',
1759: '1AA',
1760: '1AA',
1761: '1AA',
1762: '1AA',
1763: '1AA',
1764: '1AA',
1765: '1AA',
1766: '1AA',
1767: '1AA',
1768: '1AA',
1769: '1AA'},
'status_timestamp': {1753: '2019-09-23 09:34:54',
1754: '2019-09-23 10:20:57',
1755: '2019-09-23 11:22:05',
1756: '2019-09-23 12:31:58',
1757: '2019-09-23 13:52:12',
1758: '2019-09-23 14:36:33',
1759: '2019-09-23 16:49:56',
1760: '2019-09-23 17:02:49',
1761: '2019-09-23 17:14:27',
1762: '2019-09-23 17:33:12',
1763: '2019-09-23 17:47:04',
1764: '2019-09-23 18:04:37',
1765: '2019-09-23 18:21:18',
1766: '2019-09-23 18:31:07',
1767: '2019-09-23 19:10:03',
1768: '2019-09-23 21:28:54',
1769: '2019-09-23 22:18:37'},
'hour': {1753: '09:00',
1754: '10:00',
1755: '11:00',
1756: '12:00',
1757: '13:00',
1758: '14:00',
1759: '16:00',
1760: '17:00',
1761: '17:00',
1762: '17:00',
1763: '17:00',
1764: '18:00',
1765: '18:00',
1766: '18:00',
1767: '19:00',
1768: '21:00',
1769: '22:00'},
'start_timestamp': {1753: '2019-09-23 09:34:54',
1754: '2019-09-23 10:00:00',
1755: '2019-09-23 11:00:00',
1756: '2019-09-23 12:00:00',
1757: '2019-09-23 13:00:00',
1758: '2019-09-23 14:00:00',
1759: '2019-09-23 16:00:00',
1760: '2019-09-23 17:00:00',
1761: '2019-09-23 17:14:27',
1762: '2019-09-23 17:33:12',
1763: '2019-09-23 17:47:04',
1764: '2019-09-23 18:00:00',
1765: '2019-09-23 18:21:18',
1766: '2019-09-23 18:31:07',
1767: '2019-09-23 19:00:00',
1768: '2019-09-23 21:00:00',
1769: '2019-09-23 22:00:00'},
'end_timestamp': {1753: '2019-09-23 10:00:00',
1754: '2019-09-23 11:00:00',
1755: '2019-09-23 12:00:00',
1756: '2019-09-23 13:00:00',
1757: '2019-09-23 14:00:00',
1758: '2019-09-23 15:00:00',
1759: '2019-09-23 17:00:00',
1760: '2019-09-23 17:14:27',
1761: '2019-09-23 17:33:12',
1762: '2019-09-23 17:47:04',
1763: '2019-09-23 18:00:00',
1764: '2019-09-23 18:21:18',
1765: '2019-09-23 18:31:07',
1766: '2019-09-23 19:00:00',
1767: '2019-09-23 20:00:00',
1768: '2019-09-23 22:00:00',
1769: '2019-09-23 22:18:37'},
'duration': {1753: 25.1,
1754: 60.0,
1755: 60.0,
1756: 60.0,
1757: 60.0,
1758: 60.0,
1759: 60.0,
1760: 14.45,
1761: 18.75,
1762: 13.87,
1763: 12.93,
1764: 21.3,
1765: 9.82,
1766: 28.88,
1767: 60.0,
1768: 60.0,
1769: 18.62}}
dataset = pd.DataFrame.from_dict(datadict)
dataset
dataset = dataset.sort_values(by=['driver_user_id','status_timestamp'])
#Add date and hour features
dataset['date'] = dataset['status_timestamp'].dt.strftime('%F')
dataset['hour'] = dataset['status_timestamp'].dt.strftime("%H:00")
#Get lag / lead features
dataset['lag_status_timestamp'] = dataset.groupby(['driver_user_id','date'])['status_timestamp'].shift(1)
dataset['lag_status'] = dataset.groupby(['driver_user_id'])['status'].shift(1)
dataset['lag_hour'] = dataset['lag_status_timestamp'].dt.strftime("%H:00")
dataset['lead_status_timestamp'] = dataset.groupby(['driver_user_id','date'])['status_timestamp'].shift(-1)
dataset['lead_status'] = dataset.groupby(['driver_user_id'])['status'].shift(-1)
dataset['lead_hour'] = dataset['lead_status_timestamp'].dt.strftime("%H:00")
### SANITY CHECK
dataset['EventFloor']= dataset['status_timestamp'].dt.floor("H")
dataset['EF_Test']= dataset.apply(lambda x:
'Skip' if str(x.lag_status_timestamp) == 'NaT' else
('Pass' if x.lag_status_timestamp > x.EventFloor else 'Fail'),axis =1)
dataset['start_timestamp']= dataset.apply(lambda x:
x.status_timestamp if x.EF_Test != 'Fail'
else x.EventFloor,axis =1)
dataset['EventCeiling']=dataset['status_timestamp'].dt.ceil("H")
dataset['EC_Test']=dataset.apply(lambda x:
'Skip' if str(x.lead_status_timestamp) == 'NaT' else
('Pass' if x.lead_status_timestamp < x.EventCeiling else 'Fail'),axis =1)
dataset['end_timestamp']=dataset.apply(lambda x:
x.status_timestamp if x.status =='OFFLINE' else
x.lead_status_timestamp if x.EC_Test == 'Pass' else
x.EventCeiling,axis=1)
### merge driver data
dataset = dataset.merge(fact_driver,left_on=["driver_user_id","date"],right_on=["driver_user_id","shift_date"],how="left")
dataset['duration'] = (dataset['end_timestamp']-dataset['start_timestamp']).dt.seconds/60
dataset['duration'] = dataset['duration'].round(2)
dataset= dataset[['driver_user_id', 'name', 'Mobile','driver_id','shift_start','shift_end','expected_hours',
'date',
'lag_status_timestamp','lag_status',
'status_timestamp','status','hour',
'lead_status_timestamp', 'lead_status',
'EF_Test','EC_Test',
'start_timestamp','end_timestamp',
'duration'
]]
dataset_live= dataset[['driver_user_id', 'name', 'Mobile','driver_id','shift_start','shift_end','expected_hours',
'date', 'status_timestamp','hour',
'start_timestamp','status',
'end_timestamp', 'lead_status',
'duration'
]]
display(dataset.head(1))
display(dataset_live.head(1))
def divide_by_60(x):
return (x.sum()/60).round(2)
pivot_i= ['driver_id']
onlinehoursmatrix = pd.pivot_table(dataset.round({'duration':2}),
values='duration',
index=pivot_i,
columns='hour',aggfunc=[lambda x: divide_by_60(x)]
).replace(np.nan,'').reset_index()
onlinehoursmatrix.head(2)
onlinehoursmatrix.columns = [' '.join(col).strip() for col in onlinehoursmatrix.columns.values]
onlinehoursmatrix.columns = [w.replace('<lambda>', '').strip() for w in onlinehoursmatrix.columns]
onlinehoursmatrix = onlinehoursmatrix.sort_values(['driver_id'])
onlinehoursmatrix.head(2)
пс. помощь оценена