Сводка данных, показывающая разрывы в часовых интервалах - PullRequest
0 голосов
/ 30 сентября 2019

Я пытаюсь создать отчет сводной таблицы, который подсчитывает, сколько минут в час водитель находился в сети. Однако мои данные получают неверные результаты, выделенные красным цветом - это точки в данных, где они должны выводить 1 или 100% в режиме онлайн, но они не отображаются наиболее вероятно из-за того, как я работаю с агрегацией данных.

screenshot

Как вы можете видеть, потому что нет никаких изменений событий в часах 15:00 и 20:00, они заканчиваются как пустые, когда я начинаю выполнять функцию поворота

screenshot

Вот что я делаю

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)

пс. помощь оценена

...