【问题标题】:Pandas Grouper calculate time elapsed between eventsPandas Grouper 计算事件之间经过的时间
【发布时间】:2021-09-15 18:40:48
【问题描述】:

我正在尝试使用 Grouper 查找两个事件之间经过的时间,但无法这样做。请帮帮我。以下是 i/p 和预期的 o/p

输入

ID   Status           Datetime
A    Online     24/09/2017  7:00:00 AM
A    Offline    24/09/2017  7:30:00 AM     
A    Offline    24/09/2017  8:30:00 AM
A    Online     24/09/2017  9:30:00 AM
A    Offline    24/09/2017  10:00:00 AM
B    Offline    24/09/2017  6:00:00 AM
B    Online     24/09/2017  7:30:00 AM     
B    Online     24/09/2017  9:10:00 AM
B    Offline    24/09/2017  9:30:00 AM
B    Online     24/09/2017  9:40:00 AM
B    Offline    24/09/2017  10:00:00 AM

输出

ID        Hour_start                  Hour_end              Online_time
A    24/09/2017  7:00:00 AM     24/09/2017  8:00:00 AM          1800
A    24/09/2017  8:00:00 AM     24/09/2017  9:00:00 AM           0
A    24/09/2017  9:00:00 AM     24/09/2017  10:00:00 AM         1800
B    24/09/2017  6:00:00 AM     24/09/2017  7:00:00 AM           0
B    24/09/2017  7:00:00 AM     24/09/2017  8:00:00 AM          1800
B    24/09/2017  8:00:00 AM     24/09/2017  9:00:00 AM          3600
B    24/09/2017  9:00:00 AM     24/09/2017  10:00:00 AM         3000

使用 Pandas Grouper

df_output = df.groupby(['ID',pd.Grouper(key='Datetime', freq='H'),'status'])['event_time'].diff().dt.seconds.fillna(0)

但这并没有考虑到Status列的Online&Offline的情况

请帮帮我。 TIA

【问题讨论】:

  • 输出中的Hour_start ,Hour_end 与初始df 中的Datetime 列之间的关系是什么?
  • Hour_start & Hour_end 是 ID 存在的一小时间隔。 Datetime是ID活动状态的时间戳(在线/离线)
  • @wwnde 你还需要什么吗?你能帮忙吗?
  • 好的尽快恢复
  • 为什么输出开始时间的第一个 B 是早上 7 点而不是早上 6 点?

标签: python pandas numpy


【解决方案1】:

我假设源 DataFrame 中的 Datetime 列属于 datetime64 类型。

我的解决方案基于 2 级分组,首先按 ID,然后(经过一些 中间操作)按小时计算。

定义2个函数:

  1. onTimeById,计算每个ID(“外部”分组级别)的在线时间

    def onTimeById(grp):
        wrk = grp[grp.Status != grp.Status.shift()]
        wrk = wrk.set_index('Datetime').Status
        wrk = wrk.reindex(wrk.index.union(pd.date_range(wrk.index.min(),
            wrk.index.max(), freq='H'))).ffill()
        res = wrk.groupby(pd.Grouper(freq='H')).apply(onTimeByHour)
        rv = res.iloc[:-1].reset_index().rename(columns={'index': 'Hour_start',
            'Status': 'Online_time'})
        rv.insert(1, 'Hour_end', res.index[1:])
        return rv
    
  2. onTimeByHour,计算每个小时在线时间(“内部”分组级别):

    def onTimeByHour(grp2):
        if grp2.size > 1:
            dd = grp2.index.to_series().diff()
            rv = dd[grp2 == 'Offline'].sum().seconds
            if grp2.iloc[-1] == 'Online':
                rv += 3600 - dd.sum().seconds
            return rv
        return 0 if grp2.iloc[0] == 'Offline' else 3600
    

然后运行:

res = df.groupby('ID').apply(onTimeById).reset_index(level=0).reset_index(drop=True)

对于您的源数据,结果是:

  ID          Hour_start            Hour_end  Online_time
0  A 2017-09-24 07:00:00 2017-09-24 08:00:00         1800
1  A 2017-09-24 08:00:00 2017-09-24 09:00:00            0
2  A 2017-09-24 09:00:00 2017-09-24 10:00:00         1800
3  B 2017-09-24 06:00:00 2017-09-24 07:00:00            0
4  B 2017-09-24 07:00:00 2017-09-24 08:00:00         1800
5  B 2017-09-24 08:00:00 2017-09-24 09:00:00         3600
6  B 2017-09-24 09:00:00 2017-09-24 10:00:00         3000

要了解此解决方案如何工作的所有详细信息,请将“A”组保存在 一个变量,例如运行:

gr = df.groupby('ID')
grp = gr.get_group('A')

然后执行 onTimeById 中的每条指令并查看结果。

应用相同的方法来跟踪 onTimeByHour 的工作原理。

【讨论】:

  • 感谢您的回答。我能够在一个小数据集上运行它,但在主数据集上我得到一个ValueError: cannot reindex from a duplicate axis。我在 Datetime 上有重复,因为它不是唯一的。
  • 您的 Datetime 列可能包含某些 ID 的非唯一日期/时间。确保每个 ID 都有唯一的日期/时间。
  • 谢谢。我删除了重复项,它起作用了。但是,当我交叉检查样本时得到不正确的值。知道为什么吗?
  • 问另一个问题,你的数据样本得到了这些不正确的值。
猜你喜欢
  • 2013-01-21
  • 2016-09-18
  • 1970-01-01
  • 1970-01-01
  • 2019-07-21
  • 2014-09-04
  • 2020-12-05
  • 2013-12-06
  • 1970-01-01
相关资源
最近更新 更多