Pandas динамика c скользящий счетчик последовательности событий - PullRequest
1 голос
/ 23 января 2020

У меня есть следующий фиктивный фрейм данных:

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],

        'Name': ['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

Мне нужен динамический c скользящий счетчик столбца «Событие» для каждой «Группы». Как видно, например, 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      

, чтобы я мог построить Последовательность для мониторинга. Как показано в «Dynami c», возникновение события меняется даже внутри группы! Например, 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

здесь ElapsedTime для первой строки для первой последовательности 'события' A в группе 1 рассчитывается как:

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

, а вторая строка для первой последовательности события 'B' в группе 1 рассчитывается как:

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

Я пробовал скользящий счет , resample, groupby.cumcount () и т. д. в pandas, и ни один из них не возвращает интересующие меня результаты. Я уверен, что сложные комбинации этих методов в групповом режиме должны выполнять свою работу (в по крайней мере, по первому сценарию), но я потратил достаточно времени на поиски, но пока безуспешно. Это вне моего текущего знания pandas!

Еще раз, ваше время и опыт очень ценятся.

1 Ответ

0 голосов
/ 23 января 2020

OK. Я не сдался! Оказалось, что мне потребовалось еще 1-2 часа, чтобы найти решение (в значительной степени вдохновленное этим ответом @DSM), и, черт возьми, я многому научился здесь для тех, кто может столкнуться с таким преобразованием данных, включая Прошедшее время:

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

Happy Pandas -ing! ;)

...