提问人:Collin 提问时间:8/30/2023 最后编辑:Collin 更新时间:8/30/2023 访问量:68
使用 Pandas DataFrames 按天分箱设备状态时间
Binning state time of a device by day using Pandas DataFrames
问:
我有一个 Pandas 数据帧,其中包含电源启用/禁用命令与时间的关系。该索引目前未使用。您可以使用以下命令自行创建它:
pd.DataFrame(
{'command_timestamp': {
0: pd.Timestamp('2023-08-01 15:39:42'),
1: pd.Timestamp('2023-08-02 03:30:39'),
2: pd.Timestamp('2023-08-02 16:09:35'),
4: pd.Timestamp('2023-08-02 17:30:16'),
5: pd.Timestamp('2023-08-02 17:32:05'),
6: pd.Timestamp('2023-08-02 17:45:43'),
7: pd.Timestamp('2023-08-03 17:48:01'),
8: pd.Timestamp('2023-08-03 18:20:11'),
9: pd.Timestamp('2023-08-04 18:49:37'),
10: pd.Timestamp('2023-08-07 21:13:05')},
'command': {
0: 'enable',
1: 'disable',
2: 'enable',
4: 'enable',
5: 'enable',
6: 'disable',
7: 'enable',
8: 'disable',
9: 'enable',
10: 'disable'}})
我想做什么
我需要按天计算设备的“开启时间”。想象一下,实际数据集比这个示例集大得多。我似乎无法想出好的解决方案,更不用说不涉及遍历数据帧和检查大量语句的解决方案了。if
需要考虑的一些假设和事项:
- 可以忽略连续的启用或禁用命令(即,如果设备已经打开,则另一个“启用”不会执行任何操作,并且没有缺少命令)。
- 虽然鉴于前一点,我们无法确定,但我们将假设,如果数据集的第一个命令是“启用”,则设备在此之前一整天都处于关闭状态。
- 同样,如果第一个命令是“disable”,我们将假设它在那之前一整天都处于开启状态。
- 如果数据集的最后一个命令是“启用”,我们将假设设备在当天的剩余时间里处于开启状态。
- 如果一天打开,直到第二天(或多天后)才关闭,则第一天的开启时间应持续到午夜,接下来几天的开启时间应从午夜开始。换句话说,一天的开机时间不应超过 24 小时。
对于一点上下文,这是为了表示设备的“每日利用率”,而不是计算“连续开启时间”等。
示例数据预期结果
以下是示例数据集的手动计算:
results = {
'2023-08-01': (
pd.Timestamp('2023-08-02 00:00:00') -
pd.Timestamp('2023-08-01 15:39:42')),
'2023-08-02': (
pd.Timestamp('2023-08-02 03:30:39') -
pd.Timestamp('2023-08-02 00:00:00')
) + (
pd.Timestamp('2023-08-02 17:45:43') -
pd.Timestamp('2023-08-02 16:09:35')
),
'2023-08-03': (
pd.Timestamp('2023-08-03 18:20:11') -
pd.Timestamp('2023-08-03 17:48:01')
),
'2023-08-04': (
pd.Timestamp('2023-08-05 00:00:00') -
pd.Timestamp('2023-08-04 18:49:37')
),
'2023-08-05': (
pd.Timestamp('2023-08-06 00:00:00') -
pd.Timestamp('2023-08-05 00:00:00')
),
'2023-08-06': (
pd.Timestamp('2023-08-07 00:00:00') -
pd.Timestamp('2023-08-06 00:00:00')
),
'2023-08-07': (
pd.Timestamp('2023-08-07 21:13:05') -
pd.Timestamp('2023-08-07 00:00:00')
)
}
答:
1赞
ifly6
8/30/2023
#1
好的,我现在我想我明白了你的问题。首先,创建虚构的条目来标记您的一天界限。
df = pd.concat([
df.set_index('command_timestamp'),
df.reindex(pd.date_range(
start=df['command_timestamp'].min().date(),
end=df['command_timestamp'].max().date(),
freq='D'))
]).sort_index()
(我假设 start 是 。然后假设最后一个状态延续到虚构的日边界。然后进行差异。您必须通过才能访问正确的功能。disable
to_series
df['command'] = df['command'].ffill().fillna('disable')
df['diff'] = df.index.to_series().diff().shift(-1)
然后,按日期分组以及过滤的总和将产生所需的结果:
>>> df.groupby(df.index.to_series().dt.date) \
... .apply(lambda d: d.loc[d['command'] == 'enable',
... 'diff'].sum())
2023-08-01 0 days 08:20:18
2023-08-02 0 days 05:06:47
2023-08-03 0 days 00:32:10
2023-08-04 0 days 05:10:23
2023-08-05 1 days 00:00:00
2023-08-06 1 days 00:00:00
2023-08-07 0 days 21:13:05
dtype: timedelta64[ns]
解释性说明。在按求和分组之前,数据框的相关列如下所示:
command diff
2023-08-01 00:00:00 disable 0 days 15:39:42
2023-08-01 15:39:42 enable 0 days 08:20:18
2023-08-02 00:00:00 enable 0 days 03:30:39
2023-08-02 03:30:39 disable 0 days 12:38:56
2023-08-02 16:09:35 enable 0 days 01:20:41
2023-08-02 17:30:16 enable 0 days 00:01:49
2023-08-02 17:32:05 enable 0 days 00:13:38
2023-08-02 17:45:43 disable 0 days 06:14:17
2023-08-03 00:00:00 disable 0 days 17:48:01
2023-08-03 17:48:01 enable 0 days 00:32:10
2023-08-03 18:20:11 disable 0 days 05:39:49
2023-08-04 00:00:00 disable 0 days 18:49:37
2023-08-04 18:49:37 enable 0 days 05:10:23
2023-08-05 00:00:00 enable 1 days 00:00:00
2023-08-06 00:00:00 enable 1 days 00:00:00
2023-08-07 00:00:00 enable 0 days 21:13:05
2023-08-07 21:13:05 disable NaT
改为读作 可能更具说教性。diff
time_elapsed
评论
0赞
Collin
8/30/2023
感谢您的解决方案!我以前从未使用过 - 感觉我将来一定会更多地使用它。对于以下任何人,我进行了以下修改:1)在参数中添加一天,以便可以计算最后一天的ON时间;2) 将第一个条目(在一天行的开头连接后)设置为与第二个条目(原始第一个样本)相反;3) 在最终系列输出上运行。df.groupby()
end
pd.date_range()
command
.fillna(pd.Timedelta(0))
groupby.apply()
评论