【问题标题】:Pandas dynamic rolling count of sequence of eventsPandas 事件序列的动态滚动计数
【发布时间】:2020-05-09 15:57:01
【问题描述】:

我有以下虚拟数据框:

import pandas as pd
import numpy as np

def random_dates(start, end, n, freq, seed=None):
    if seed is not None:
        np.random.seed(seed)

    dr = pd.date_range(start, end, freq=freq)
    return pd.to_datetime(np.sort(np.random.choice(dr, n, replace=False)))

data = {'Timestamp': random_dates('2018-01-01', '2018-01-02', 21, 'H', seed=[3, 1415]), 
        'Group': [1,1,1,1,1,1,1,1,1,1,1,1,
                 2,2,2,2,2,2,2,2,2],
        
        'Event': ['A','A','A','B','A','A','A','B','A','A','A','B',
                'A','A','B','A','A','B','A','A','B']}

df = pd.DataFrame(data, columns = ['Timestamp', 'Group', 'Event'])
print(df)

             Timestamp  Group Event
0  2018-01-01 00:00:00      1    A
1  2018-01-01 01:00:00      1    A
2  2018-01-01 03:00:00      1    A
3  2018-01-01 04:00:00      1    B
4  2018-01-01 05:00:00      1    A
5  2018-01-01 06:00:00      1    A
6  2018-01-01 07:00:00      1    A
7  2018-01-01 08:00:00      1    B
8  2018-01-01 09:00:00      1    A
9  2018-01-01 12:00:00      1    A
10 2018-01-01 13:00:00      1    A
11 2018-01-01 14:00:00      1    B
12 2018-01-01 15:00:00      2    A
13 2018-01-01 17:00:00      2    A
14 2018-01-01 18:00:00      2    B
15 2018-01-01 19:00:00      2    A
16 2018-01-01 20:00:00      2    A
17 2018-01-01 21:00:00      2    B
18 2018-01-01 22:00:00      2    A
19 2018-01-01 23:00:00      2    A
20 2018-01-02 00:00:00      2    B

我想要每个“组”的“事件”列的动态滚动计数。可以看出,例如df['Group']==1 具有事件序列:

A, A, A, B

其中事件序列每三分之一发生一次,因此序列为 3, 1。而 df['Group']==2 是:

A, A, B

其中事件序列每秒发生一次,因此序列为 2、1。理想情况下,我会:

Group Event Sequence 
1      A      3      
1      B      1      
1      A      3      
1      B      1      
1      A      3      
1      B      1      
2      A      2      
2      B      1      
2      A      2      
2      B      1      
2      A      2      
2      B      1      

这样我就可以绘制序列以进行监控。正如所展示的,通过“动态”,事件的发生正在发生变化,即使在一个组内也是如此!例如df['Group']==1 也可以看到 3、1、3、1、2、1。

用每个事件序列计算经过的时间也很棒。这可以计算为每个组的每个序列的最后一个和第一个事件时间戳之间的差异,我们将有:

Group Event Sequence ElapsedTime
1      A      3      4
1      B      1      1
1      A      3      3
1      B      1      1
1      A      3      5
1      B      1      1
2      A      2      3
2      B      1      1
2      A      2      2
2      B      1      1
2      A      2      2
2      B      1      None

此处第 1 组中“事件”A 的第一个序列的第一行的 ElapsedTime 计算为:

df[df['Group']==1]['Timestamp'].iloc[2] - df[df['Group']==1]['Timestamp'].iloc[0]

第 1 组中第一个“事件”B 序列的第二行计算为:

df[df['Group']==1]['Timestamp'].iloc[3] - df[df['Group']==1]['Timestamp'].iloc[2]

我在 pandas 中尝试过滚动计数、重采样、groupby.cumcount() 等方法,但它们都没有返回我感兴趣的结果。我确信这些方法在 groupby 中的复杂组合时尚应该完成这项工作(至少在第一种情况下),但我已经花了足够的时间尝试和搜索,到目前为止还没有成功。这超出了我目前对 pandas 的了解!

再次感谢您的时间和经验。

【问题讨论】:

  • data内,第三个元素应该是Event而不是Name

标签: python pandas count sequence rolling-computation


【解决方案1】:

好的。我没有放弃!事实证明,我需要另外 1-2 小时才能找到解决方案(很大程度上受到 @DSM 的 this answer 的启发),我学到了很多东西,在这里为那些可能遇到此类数据转换的人,包括经过的时间:

df['Lag'] = df['Timestamp'].shift(-1) 
df['Seq'] = df["Event"].groupby((df.Event != df.Event.shift()).cumsum()).transform('size')
df['SeqID'] = (df.Event != df.Event.shift()).cumsum()

df_grp = df.groupby(['Group','SeqID']).first().reset_index()
df_grp['Elapsed(min)'] =  (df.groupby(['Group','SeqID'])['Lag'].last() - df.groupby(['Group','SeqID'])['Timestamp'].first()).reset_index()[0]/ np.timedelta64(1, 'm')

df_grp = df_grp.drop(['Timestamp','Lag'],axis=1)
print(df_grp)


    Group  SeqID Event  Seq  Elapsed(min)
0       1      1     A    3         240.0
1       1      2     B    1          60.0
2       1      3     A    3         180.0
3       1      4     B    1          60.0
4       1      5     A    3         300.0
5       1      6     B    1          60.0
6       2      7     A    2         180.0
7       2      8     B    1          60.0
8       2      9     A    2         120.0
9       2     10     B    1          60.0
10      2     11     A    2         120.0
11      2     12     B    1           NaN

熊猫快乐! ;)

【讨论】:

猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-01-03
  • 2019-07-26
  • 1970-01-01
  • 2021-02-04
相关资源
最近更新 更多