Как найти занятость каждый час? - PullRequest
1 голос
/ 22 июня 2019

Я пытаюсь показать, сколько людей в тренажерном зале в любой момент времени.

Мне предоставлены данные для входа в систему, и я хотел бы отображать занятость каждого часа следующим образом:

Date/Time | Occupants
1/1/2018 7:00AM | 4
1/1/2018 8:00AM | 12
1/1/2018 9:00AM | 16
1/1/2018 10:00AM | 13
1/1/2018 11:00AM | 11

Информация для входа предоставляется следующим образом: (PS Я предполагаю, что люди проводят там около 1,5 часов, там примерно 100 000 строк.)

Sign In | Sign Out
1/1/18 9:00 AM  | 1/1/18 10:30 AM
1/1/18 10:16 AM | 1/1/18 11:46 AM
1/1/18 10:18 AM | 1/1/18 11:48 AM
1/1/18 10:29 AM | 1/1/18 11:59 AM
1/1/18 10:30 AM | 1/1/18 12:00 PM
1/1/18 10:33 AM | 1/1/18 12:03 PM
1/1/18 11:27 AM | 1/1/18 12:57 PM
1/1/18 11:36 AM | 1/1/18 1:06 PM
1/1/18 11:37 AM | 1/1/18 1:07 PM
1/1/18 11:51 AM | 1/1/18 1:21 PM
1/1/18 11:52 AM | 1/1/18 1:22 PM

Что было бы хорошим способом агрегировать эти данные в каждый час? Буду признателен за любую помощь.

Спасибо

Ответы [ 4 ]

0 голосов
/ 23 июня 2019

Мое решение работает также с данными с периодами присутствия, отличными от 1,5 часа, но даты должны быть от одного дня (в зависимости от того, как вы собрали данные образца).

Я прочиталваши данные как поля фиксированной ширины с преобразованием в datetime :

df = pd.read_fwf(pd.compat.StringIO(txt), colspecs=[(0, 15), (18, 33)],
    names=['Sign In', 'Sign Out'], parse_dates=[0, 1])

, поэтому с самого начала у меня есть правильные типы данных (нет необходимости в дополнительных вызовах pd.to_datetime ).

Первым подготовительным шагом является создание IntervalIndex :

intervals = pd.IntervalIndex.from_arrays(df['Sign In'], df['Sign Out'], closed='left')

Следующим шагом является создание hrs - список полных часов:

hrs = pd.date_range(df['Sign In'].min(),
    df['Sign Out'].max() + pd.Timedelta('1H'), freq='H')

Обратите внимание, что я добавил 1 дополнительный час к значению max , чтобы после каждого из них был "последний" часвышел.Что-то вроде последнего часа с 0 заполнением, как CHAMI .Если вам это не нужно, просто удалите этот дополнительный час.

Но нам нужна Series с индексом и значениями, установленными в эти часы, поэтому я создал также hours :

hours = pd.Series(hrs, index=hrs)

И, имея эти данные, фактическое вычисление может быть выполнено в виде single инструкции:

occupancy = hours.apply(lambda hr: np.count_nonzero(
    intervals.map(lambda it: hr in it)))

Результат:

2018-01-01 09:00:00    1
2018-01-01 10:00:00    1
2018-01-01 11:00:00    5
2018-01-01 12:00:00    6
2018-01-01 13:00:00    4
2018-01-01 14:00:00    0
Freq: H, dtype: int64

Стоит сравнить с другими ответами:

  • Ответ по CHAMI имеет тип данных float be int ).
  • CHAMI Решение показывает занятость в 10:00 как 5 , тогда как в настоящее время фактически только 1 человек присутствовал.Клиенты с № 2 по 6 вошли позже ( после 10:00).
  • Результаты за 10:00 и последующие часы в его решении "сдвинуты" на 1 час.
  • Неправильно включать в начальные / конечные пробелы имена столбцов (как CHAMI ).
  • krewsider на самом деле показывает только агрегацию знакасобытия входа / выхода , но не занятость.
  • harvpan занял 1,5 шаг в часах (почему?).Другая деталь состоит в том, что он показывает занятость в 9: 00 как 4 (почему?), И его результат является далеко не полным.

Обратите внимание также на такойразница в том, что CHAMI показал 7 занятость в 11: 00 (на самом деле в 12: 00 ), но я показал 6.Причина в том, что я предположил, что если человек № 5 остался острым в 12: 00 , то в это время он уже отсутствовал .

Если вы хотите лечитьтакой человек, который все еще присутствует, измените атрибут closed IntervalIndex на 'Оба' и для ваших данных результат в 12: 00 будет 7 .

0 голосов
/ 22 июня 2019

Вам нужно просто добавить, сколько людей пришло за Sign In время (в нашем случае, 1).Тогда resample это с 1.5H.

df['people'] = 1
df.set_index(['Sign In']).resample('1.5H').count()

Выход:

                    people
Sign In 
2018-01-01 09:00:00 4
2018-01-01 10:30:00 7
0 голосов
/ 23 июня 2019

Это мой снимок

import pandas as pd
from datetime import datetime

# convert to the right type
data['Sign In ']= data['Sign In '].apply(lambda x: datetime.strptime(x, '%d/%m/%y %I:%M %p '))

data[' Sign Out']= data[' Sign Out'].apply(lambda x: datetime.strptime(x, ' %d/%m/%y %I:%M %p'))

# save in and Out 
signin= pd.to_datetime(data['Sign In '])
signout= pd.to_datetime(data[' Sign Out'])

# in groupby you could add [signin.dt.date, signin.dt.hour] if necessary
In = data.groupby([signin.dt.hour]).count().drop(' Sign Out', axis=1)  

Out= data.groupby([signout.dt.hour]).count().drop('Sign In ', axis=1) 

In.index.rename('time', inplace=True)
Out.index.rename('time', inplace=True)

# concatenate in data 
data = pd.concat([In, Out], axis=1).fillna(0)
data['occupancy'] = (data['Sign In '] - data[' Sign Out']).cumsum()

Вывод

print(data) 

      Sign In    Sign Out  occupancy
time                                
9          1.0        0.0        1.0
10         5.0        1.0        5.0
11         5.0        3.0        7.0
12         0.0        3.0        4.0
13         0.0        4.0        0.0
0 голосов
/ 22 июня 2019

Вы просто ищете помощь в агрегации?

Вы можете использовать groupby со счетом.

In = df['Sign In'].groupby([df['Sign In'].apply(lambda x: x.strftime('%B %d, %Y, %H'))]).count()
Out = df['Sign In'].groupby([df['Sign Out'].apply(lambda x: x.strftime('%B %d, %Y, %H'))]).count()

Sign In
January 01, 2018, 09    1
January 01, 2018, 10    5
January 01, 2018, 11    5
Name: Sign In, dtype: int64
Sign Out
January 01, 2018, 10    1
January 01, 2018, 11    3
January 01, 2018, 12    3
January 01, 2018, 13    4
Name: Sign In, dtype: int64

Затем вы можете работать здесь, чтобы переименовать столбцы, применить логику (т.е. это просто текущая дельта) и выполните объединение, чтобы объединить кадры.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...