【问题标题】:Group by time interval for 24 hrs and assign group values按 24 小时的时间间隔分组并分配组值
【发布时间】:2022-10-23 17:32:31
【问题描述】:

我有一个如下所示的 pandas 数据框,其中包含B 列中的日期时间值。


import pandas as pd

data = {'A': ['XYZ', 'XYZ', 'XYZ', 'XYZ', 'PQR', 'PQR', 'PQR', 'PQR', 'CVB', 'CVB', 'CVB', 'CVB'], 
        'B': ['2022-02-16 14:00:31', '2022-02-16 16:11:26', '2022-02-16 17:31:26', '2022-02-16 22:47:46', '2022-02-17 07:11:11', '2022-02-17 10:43:36', '2022-02-17 15:05:11', '2022-02-18 18:06:12', '2022-02-19 09:05:46', '2022-02-19 13:02:16', '2022-02-19 18:05:26', '2022-02-19 22:05:26']}
df = pd.DataFrame(data)
df['B'] = pd.to_datetime(df['B'])
df


     |   A   |          B           |                                 
     +-------+----------------------+
     |  XYZ  |  2022-02-16 14:00:31 |                  
     |  XYZ  |  2022-02-16 16:11:26 |         
     |  XYZ  |  2022-02-16 17:31:26 | 
     |  XYZ  |  2022-02-16 22:47:46 |  
     |  PQR  |  2022-02-17 07:11:11 | 
     |  PQR  |  2022-02-17 10:43:36 |
     |  PQR  |  2022-02-17 15:05:11 |
     |  PQR  |  2022-02-18 18:06:12 |
     |  CVB  |  2022-02-19 09:05:46 |
     |  CVB  |  2022-02-19 13:02:16 |
     |  CVB  |  2022-02-19 18:05:26 |
     |  CVB  |  2022-02-19 22:05:26 |
     +-------+----------------------+

我想对 24 小时间隔期间的日期时间值进行分组,这样我的输出应该如下所示。

Expected Output :

     |   A   |          B           |   Group  |                               
     +-------+----------------------+-----------
     |  XYZ  |  2022-02-16 14:00:31 |     1    |        
     |  XYZ  |  2022-02-16 16:11:26 |     1    |
     |  XYZ  |  2022-02-16 17:31:26 |     1    |
     |  XYZ  |  2022-02-16 22:47:46 |     1    |
     |  PQR  |  2022-02-17 07:11:11 |     1    |  
     |  PQR  |  2022-02-17 10:43:36 |     1    |     
     |  PQR  |  2022-02-17 15:05:11 |     2    |  
     |  PQR  |  2022-02-18 18:06:12 |     3    |  
     |  CVB  |  2022-02-19 09:05:46 |     3    | 
     |  CVB  |  2022-02-19 13:02:16 |     3    |
     |  CVB  |  2022-02-19 18:05:26 |     3    |
     |  CVB  |  2022-02-19 22:05:26 |     4    |
     +-------+----------------------+----------+

目前,我尝试使用下面的代码将B 列中的日期时间值分组为 24 小时间隔时间段,这导致了我没想到的不成功输出。我的 24 小时周期将首先从初始日期时间开始,即 2022-02-16 14:00:31,然后下一个 24 小时周期将从 2022-02-17 15:05:11 开始,依此类推。


df1 = df.reset_index().set_index(df['B']).rename_axis(None)
df1.loc[df1.first('24h').index, "GROUP"] = 1
df1

Actual Output :

     |   A   |          B           |   Group    |                               
     +-------+----------------------+------------+
     |  XYZ  |  2022-02-16 14:00:31 |     1      |        
     |  XYZ  |  2022-02-16 16:11:26 |     1      |
     |  XYZ  |  2022-02-16 17:31:26 |     1      |
     |  XYZ  |  2022-02-16 22:47:46 |     1      |
     |  PQR  |  2022-02-17 07:11:11 |     1      |  
     |  PQR  |  2022-02-17 10:43:36 |     1      |     
     |  PQR  |  2022-02-17 15:05:11 |     NaN    |  
     |  PQR  |  2022-02-18 18:06:12 |     NaN    |  
     |  CVB  |  2022-02-19 09:05:46 |     NaN    | 
     |  CVB  |  2022-02-19 13:02:16 |     NaN    |
     |  CVB  |  2022-02-19 18:05:26 |     NaN    |
     |  CVB  |  2022-02-19 22:05:26 |     NaN    |
     +-------+----------------------+------------+


有没有一种方法可以将 24 小时时间间隔内的日期时间值分组,以便获得如图所示的预期输出?我想要一个高效的解决方案,以便代码可以有效地在 100 万个时间戳上运行。

【问题讨论】:

  • 你如何定义你的 24 小时周期。第一个是否从2022-02-16 14:00:31 开始?它们是连续的还是它们之间是否存在间隙,即第二个周期是从第一个周期的开始 + 24 小时开始,还是从2022-02-17 15:05:11 开始?
  • @Riley:我的 24 小时周期首先从 2022-02-16 14:00:31 开始。第二个周期从第一个周期开始 + 24 小时 (2022-02-16 14:00:31),在我的情况下是 2022-02-17 15:05:11

标签: python-3.x pandas dataframe python-datetime


【解决方案1】:

编辑:更有效的解决方案:

df['day'] = df['B'].dt.day
df['group_id'] = df.groupby('day').ngroup() + 1

这是一个有点长的解决方案我敢肯定有更有效的解决方案,但你可以使用这个:

df['day']=df['B'].dt.day
df2=df.groupby(df['B'].dt.day).agg(count_col=('B', 'count')).sort_index().reset_index().reset_index().drop(['count_col'],axis=1).rename(columns={'index':'group_id','B':'day'})
df=df.merge(df2,how='left',on='day').drop(['day'],axis=1)
print(df)
'''
    A   B                   group_id
0   XYZ 2022-02-16 14:00:31 0
1   XYZ 2022-02-16 16:11:26 0
2   XYZ 2022-02-16 17:31:26 0
3   XYZ 2022-02-16 22:47:46 0
4   PQR 2022-02-17 07:11:11 1
5   PQR 2022-02-17 10:43:36 1
6   PQR 2022-02-17 15:05:11 1
7   PQR 2022-02-18 18:06:12 2
8   CVB 2022-02-19 09:05:46 3
9   CVB 2022-02-19 13:02:16 3
10  CVB 2022-02-19 18:05:26 3
11  CVB 2022-02-19 22:05:26 3
'''

如果您希望 group_id 值从 1 开始:

df['day']=df['B'].dt.day
df.index=df.index +1 
df2=df.groupby(df['B'].dt.day).agg(count_col=('B', 'count')).sort_index().reset_index()
df2.index=df2.index +1
df2=df2.reset_index().drop(['count_col'],axis=1).rename(columns={'index':'group_id','B':'day'})
df=df.merge(df2,how='left',left_on='day',right_on='day').drop(['day'],axis=1)
print(df)
'''
    A   B                   group_id
0   XYZ 2022-02-16 14:00:31 1
1   XYZ 2022-02-16 16:11:26 1
2   XYZ 2022-02-16 17:31:26 1
3   XYZ 2022-02-16 22:47:46 1
4   PQR 2022-02-17 07:11:11 2
5   PQR 2022-02-17 10:43:36 2
6   PQR 2022-02-17 15:05:11 2
7   PQR 2022-02-18 18:06:12 3
8   CVB 2022-02-19 09:05:46 4
9   CVB 2022-02-19 13:02:16 4
10  CVB 2022-02-19 18:05:26 4
11  CVB 2022-02-19 22:05:26 4

'''

【讨论】:

    【解决方案2】:

    至于这个过程的每一步都依赖于上一步的结果,我们不能使用resampletransform。我们必须以规定的方式依次迭代所有数据映射它们:

    step = pd.Timedelta('24H')
    sentinel = df.loc[0, 'B'] + step
    group_id = 1
    for index, value in df['B'].items():
        if value > sentinel:
            sentinel = value + step
            group_id += 1
        df.loc[index, 'Group'] = group_id
    

    我们还可以在生成器的帮助下将这个过程隐藏在Series.map 中,这可能会更快一些:

    def gen(start, step):
        sentinel = start + step
        group_id = 1
        value = yield
        while True:
            if value > sentinel:
                sentinel = value + step
                group_id += 1
            value = yield group_id
    
    marker = gen(df.loc[0, 'B'], pd.Timedelta('24H')).send
    marker(None)
    df['Group'] = df['B'].map(marker)
    del marker
    

    请注意,如果事先对df['B'] 进行了排序,那么所有这些都有效。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-12-20
      • 2011-02-08
      • 2019-06-28
      • 2018-10-12
      • 1970-01-01
      • 2016-09-21
      • 2017-09-06
      • 2021-03-06
      相关资源
      最近更新 更多