【问题标题】:Calculation based off of previous row (Pandas)基于前一行的计算(熊猫)
【发布时间】:2020-11-12 14:40:36
【问题描述】:

我正在尝试为某些日志数据创建一个事件计数器和自第一个事件计数器以来的天数。下面的 DataFrame 跟踪每天是否发生某个事件。对于每个组,我需要计算任何日期之前和该日期发生的事件数量。我还需要计算自每组第一个事件发生以来的天数

开始DF

group        date  event
    A  2020-07-16       0
    A  2020-07-17       1
    A  2020-07-18       0
    A  2020-07-19       1
    A  2020-07-20       0
    A  2020-07-21       0
    A  2020-07-22       1
    B  2020-07-16       1
    B  2020-07-17       1
    B  2020-07-18       0
    B  2020-07-19       1
    B  2020-07-20       0
    B  2020-07-21       1
    B  2020-07-22       1

生成DF的代码

import pandas as pd
import datetime as datetime
base = datetime.datetime.today()
numdays = 7
date_list = [(base - datetime.timedelta(days=x)).date() for x in range(numdays)]

df = pd.DataFrame(columns=['group', 'date'])
for group in ['A', 'B']:
    tmp = pd.DataFrame({'group': group, 'date': date_list})
    df = df.append(tmp)
df = df.sort_values(['group', 'date'])

groupA_events = [0, 1, 0, 1, 0, 0, 1]
groupB_events = [1, 1, 0, 1, 0, 1, 1]
events = groupA_events + groupB_events
df['event'] = events

结束 DF

group        date  event  counter  since_first
    A  2020-07-16      0         0            0
    A  2020-07-17      1         1            0
    A  2020-07-18      0         1            1
    A  2020-07-19      1         2            2
    A  2020-07-20      0         2            3
    A  2020-07-21      0         2            4
    A  2020-07-22      1         3            5
    B  2020-07-16      1         1            0
    B  2020-07-17      1         2            1
    B  2020-07-18      0         2            2
    B  2020-07-19      1         3            3
    B  2020-07-20      0         3            4
    B  2020-07-21      1         4            5
    B  2020-07-22      1         5            6

我的数据大约有 80 万行(并且还在增长)。我找到了一个可行的解决方案(有点),但执行时间非常长。

【问题讨论】:

    标签: python pandas logging time


    【解决方案1】:

    使用cumsum 获取计数器。之后的天数可以通过将transforming 屏蔽到每个组内有事件的第一天来获得。这很有用,因为如果您的日期不连续,它仍然会正确计算时差。 (clip 所以之前的任何东西都被认为是 0)

    df['counter'] = df.groupby('group').agg(counter=('event', 'cumsum'))
    
    df['date'] = pd.to_datetime(df['date'])
    s_first = df['date'].where(df['event'].eq(1)).groupby(df['group']).transform('first')
    
    df['days_since'] = (df['date'] - s_first).dt.days.clip(lower=0)
    

      group       date  event  counter  days_since
    6     A 2020-07-16      0        0           0
    5     A 2020-07-17      1        1           0
    4     A 2020-07-18      0        1           1
    3     A 2020-07-19      1        2           2
    2     A 2020-07-20      0        2           3
    1     A 2020-07-21      0        2           4
    0     A 2020-07-22      1        3           5
    6     B 2020-07-16      1        1           0
    5     B 2020-07-17      1        2           1
    4     B 2020-07-18      0        2           2
    3     B 2020-07-19      1        3           3
    2     B 2020-07-20      0        3           4
    1     B 2020-07-21      1        4           5
    0     B 2020-07-22      1        5           6
    

    【讨论】:

    • 这完美!太感谢了!!!!增加一层复杂性:如果我有 2 个事件(event1 和 event2)怎么办。如何将 s_first 转换为 event2 在该组已经发生 event1 之后第一次发生?
    • @claytvh 您可以更改发送给where 的掩码。如果您采用 event_1 的 cummax ,它将在第一个 1 之后向前填充它,因此您将使用 df['date'].where(df.groupby('group')['event1'].cummax().eq(1) & df['event2'].eq(1)) 并遵循相同的 groupby 和所有其他步骤。
    【解决方案2】:

    你可以用cumsum + cumcount 做groupby

    df['counter']=df.groupby('group').event.cumsum()
    df['since_first']=df[df['counter'].ne(0)].groupby('group')['counter'].cumcount()
    df['since_first'].fillna(0, inplace=True)
    

    【讨论】:

    • 这给了我错误 ValueError: cannot reindex from a duplicate axis
    • @claytvh 在执行上述操作之前,请检查 do df=df.reset_index()
    猜你喜欢
    • 2016-07-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-08-13
    • 2023-02-13
    • 2017-10-02
    • 1970-01-01
    相关资源
    最近更新 更多