根据Excel中的占用率每小时提取分钟

问题描述

是否有一种简单的方法可以根据占用率提取房间每小时的分钟数?我想大致了解一下会议室1从08:00:00- 08:59:59,09:00:00-09:59:59..etc

我通过为每小时从fex 08:00:00到08:59:59结束的每个小时创建时间间隔来手动完成此操作。然后,我使用了sumif公式来计算每天一小时房间每天被占用的分钟数(每天总计9个小时)。

我想查看不同房间每小时占用多少分钟并进行比较,所以我想知道是否有更简单的方法?拥有我可以用于所有房间的格式,将是很棒的。但是,由于所有房间都有不同的时间戳,这可能很难吗?

如果有人知道如何用sql或Python做到这一点,那也将非常有帮助,尤其是在sql中!

下面的链接将为您提供数据示例。

Example of what the data looks like

解决方法

在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 ...表示9月1日的美式风格-我正在猜测这就是您想要的;如果您确实是指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我们可以做很多事情,但是我将尝试尽可能直接地到达您想去的地方。

我们将从使用“时间戳记”列作为“索引”开始,并在时间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。我们必须折叠索引的“组”级别,然后 then 组并进行下采样!


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,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

希望与您所追求的相近。

,

作为起点:

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

上面的SQL表为room_table。还假设startstop字段是time类型。 “ some_time / another_time”只是您感兴趣的时间范围的占位符。