Есть ли простой способ извлечь количество минут в час, в которых использовалась комната, в зависимости от уровня заполняемости? Я хотел бы получить информацию о том, сколько минут использовалась комната 1 с 08: 00: 00- 08:59:59, 09: 00: 00-09: 59: 59 и т. Д.

Я сделал это вручную, создав временные интервалы для каждого часа, начиная с 08:00:00 и заканчивая 08:59:59. Затем я использовал формулу sumif, чтобы получить количество минут, в течение которых комната была занята в час в течение одного дня (всего 9 часов в день).

Поскольку я хочу увидеть, сколько минут в час заняты в разных комнатах, и сравнить их, мне интересно, есть ли более простой способ сделать это? Было бы здорово иметь формат, который можно было бы использовать для всех комнат. Однако, поскольку все комнаты будут иметь разные отметки времени, это может быть сложно?

Если кто-нибудь знает, как это сделать в SQL или Python, это тоже будет очень полезно, особенно в SQL!

Ссылка ниже предоставит вам пример данных.

Example of what the data looks like

1
Molly 6 Окт 2020 в 15:35

2 ответа

Лучший ответ

В python структура данных, наиболее аналогичная электронной таблице или таблице SQL, - это DataFrame из библиотеки pandas.

Сначала мы можем читать данные из электронной таблицы следующим образом:

import pandas as pd

df = pd.read_excel("<your filename>", parse_dates=[1])

df["Time"] = df.Timestamp.dt.time

Здесь я предполагаю, что вы удалили незавершенную работу (таблица справа на изображении) и что данные находятся на первом листе файла Excel (в противном случае нам придется передать дополнительные параметры).

Я убедился, что первый столбец (Timestamp) правильно понимается как содержащий данные даты и времени. По умолчанию предполагается, что 09.01.2020 ... относится к 1 сентября в американском стиле - я догадываюсь , что вы хотите; можно передать дополнительные параметры, если вы действительно имели в виду 9 января (именно так я бы прочитал эту дату).

Затем я перезаписал столбец Time объектом time, извлеченным из Timestamp, на самом деле это не обязательно, но позволяет получить данные как можно ближе к тому, что было в электронной таблице. DataFrame теперь выглядит так:

            Timestamp Room name  Occupancy %      Time
0 2020-09-01 08:04:01    Room 1            0  08:04:01
1 2020-09-01 09:04:01    Room 1          100  09:04:01
2 2020-09-01 09:19:57    Room 1            0  09:19:57
3 2020-09-01 09:48:57    Room 1            0  09:48:57
4 2020-09-01 09:53:01    Room 1          100  09:53:01
5 2020-09-01 10:05:01    Room 1          100  10:05:01
6 2020-09-01 10:08:57    Room 1          100  10:08:57
7 2020-09-01 10:13:01    Room 1          100  10:13:01

(Обратите внимание, что в следующий раз было бы хорошо включить что-то вроде этого текста в свой вопрос, это значительно упрощает построение ответа, если данные не нужно тщательно собирать вместе)

Теперь есть много вещей, которые мы можем сделать с DataFrame, подобным этому, но я собираюсь попытаться добраться туда, куда вы хотите, как можно быстрее.

Мы начнем с использования столбца Timestamp в качестве «индекса» и добавления строки для времени 08:00:00, потому что в настоящее время он не является частью вашего набора данных, но вы указали, что хотите его.


df2 = df.set_index("Timestamp")

df2.loc[pd.Timestamp("09.01.2020 08:00:00")] = ("Room1", 0.0, None)

df2.sort_index(inplace=True)

Результат выглядит так:

                    Room name  Occupancy %      Time
Timestamp                                           
2020-09-01 08:00:00    Room 1          0.0      None
2020-09-01 08:04:01    Room 1          0.0  08:04:01
2020-09-01 09:04:01    Room 1        100.0  09:04:01
2020-09-01 09:19:57    Room 1          0.0  09:19:57
2020-09-01 09:48:57    Room 1          0.0  09:48:57
2020-09-01 09:53:01    Room 1        100.0  09:53:01
2020-09-01 10:05:01    Room 1        100.0  10:05:01
2020-09-01 10:08:57    Room 1        100.0  10:08:57
2020-09-01 10:13:01    Room 1        100.0  10:13:01

Теперь самый простой способ сделать это - начать с повышения частоты дискретизации и прямого заполнения данных.

upsampled = df2.resample("1min").ffill()

upsampled - это огромный DataFrame со значением для каждой секунды в диапазоне. Заполнение вперед гарантирует, что ваш процент занятости переносится вперед каждую секунду, пока одна из ваших исходных точек данных не скажет «здесь изменилось». После изменения новое значение переносится на следующую точку данных и т. Д.

Это сделано для обеспечения необходимого разрешения по времени. Обычно я бы уменьшил разрешение. Вас интересовал каждый час:

downsampled = upsampled.resample("1h").mean()

Взяв среднее значение, мы получим в нашем выводе только числовые столбцы, то есть «занятость», и здесь вы получите следующее:

                     Occupancy %
Timestamp                       
2020-09-01 08:00:00     0.000000
2020-09-01 09:00:00    38.194444
2020-09-01 10:00:00   100.000000

Но вы указали, что можете сделать это "для каждой комнаты", поэтому могут быть другие данные, например, «Комната 2». В этом случае у нас есть категориальный столбец Room name, по которому нам нужно сгруппировать.

Это немного сложнее, потому что это означает, что мы должны сгруппировать перед повышением дискретизации, чтобы избежать двусмысленности. Это создаст MultiIndex. Мы должны свернуть «групповой» уровень индекса, затем группировать и уменьшить выборку!


grouped = df.groupby("Room name", as_index=False).resample('1s').ffill()

grouped.index = grouped.index.get_level_values(1)

result = grouped.groupby("Room name").resample("1h").mean()

Который будет выглядеть примерно так:

                               Occupancy %
Room name Timestamp                       
Room 1    2020-09-01 08:00:00     0.000000
          2020-09-01 09:00:00    38.194444
          2020-09-01 10:00:00   100.000000
Room 2    2020-09-01 08:00:00     0.000000
          2020-09-01 09:00:00    38.194444
          2020-09-01 10:00:00   100.000000

(Я просто продублировал данные для комнаты 1 как комнаты 2, поэтому числа те же самые)

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

Таким образом, все решение:

import pandas as pd

df = pd.read_excel("<your filename>", parse_dates=[1])

df2 = df.set_index("Timestamp")

# prepend some dummy rows for every different room name
for room_name in df2["Room name"].unique():
    df2.loc[pd.Timestamp("09.01.2020 08:00:00")] = (room_name, 0.0, None)


df2.sort_index(inplace=True)

grouped = df.groupby("Room name", as_index=False).resample('1s').ffill()

grouped.index = grouped.index.droplevel(0)

result = (
    grouped
        .groupby("Room name")
        .resample("1h")
        .mean()
        .unstack(level=0)
        .div(100)  # % -> fraction
        .mul(60)  # fraction -> minutes
        .astype(int)  # nearest number of whole minutes
)

# no longer 'Occupancy %', so drop the label
result.columns = result.columns.droplevel(0)  

Давая result как

Room name                Room 1 Room 2
Timestamp                             
2020-09-01 08:00:00           0      0
2020-09-01 09:00:00          22     22
2020-09-01 10:00:00          60     60

Что, надеюсь, близко к тому, что вам нужно.

1
Paddy Alton 6 Окт 2020 в 16:35

В качестве отправной точки:

SELECT
    room_name, sum(start-stop)
FROM 
    room_table
WHERE 
    timestamp BETWEEN 'some_time' AND 'another_time'
GROUP BY
    room_name

Где в приведенной выше таблице SQL - room_table. Также предполагается, что поля start и stop относятся к типам time. Some_time / another_time - это просто заполнители для интересующего вас диапазона времени.

0
Adrian Klaver 6 Окт 2020 в 14:16