问题描述
是否有一种简单的方法可以根据占用率提取房间每小时的分钟数?我想大致了解一下会议室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中!
下面的链接将为您提供数据示例。
解决方法
在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
。还假设start
和stop
字段是time
类型。 “ some_time / another_time”只是您感兴趣的时间范围的占位符。