高效组合 groupby、last 和 count in pandas

Efficiently combining groupby, last and count in pandas

我想从日志列表中获取特定事件类型在每个时间戳处的活动事件数。

示例日志输入如下所示:

time id event
2022-03-01 10:00 1 A
2022-03-01 11:00 2 B
2022-03-01 12:00 3 A
2022-03-01 13:00 1 B
2022-03-01 14:00 4 A
2022-03-01 15:00 2 C
2022-03-01 16:00 1 A
... ... ...

我想要的基本上是在 df 中每次有多少 ids 有活动的事件 A,就像下面的 table。

time eventA
2022-03-01 10:00 1
2022-03-01 11:00 1
2022-03-01 12:00 2
2022-03-01 13:00 1
2022-03-01 14:00 2
2022-03-01 15:00 2
2022-03-01 16:00 3
... ...

我通过一些基本的 pandas 操作实现了这一点:

df = pd.DataFrame(
    {
        "time": pd.date_range("2022-03-01 10:00", periods=7, freq="H"),
        "id": [1, 2, 3, 1, 4, 2, 1],
        "event": ["A", "B", "A", "B", "A", "C", "A"],
    }
)
timestamps = df.time
values = []
for timestamp in timestamps:
    filtered_df = df.loc[df.time <= timestamp]
    eventA = filtered_df.groupby("id").last().groupby("event").count().["time"]["A"]
    values.append({"time": timestamp, "eventA": eventA})

df_count = pd.DataFrame(values)

但就我而言,我必须超过 50,000 行,这种基本方法在时间上变得非常低效。

是否有更好的方法来达到预期的效果?我想可能有一些 pandas groupby 聚合方法可以在这里提供帮助,但我发现 none 对我有帮助。

df.set_index(['time', 'id']).unstack().fillna(method='ffill')\
    .stack().value_counts(['time', 'event']).unstack().fillna(0)

第一行负责从 id 每个 id 每小时 forward-filling NaNs

获取最新事件
                    event               
id                      1    2    3    4
time                                    
2022-03-01 10:00:00     A  NaN  NaN  NaN
2022-03-01 11:00:00     A    B  NaN  NaN
2022-03-01 12:00:00     A    B    A  NaN
2022-03-01 13:00:00     B    B    A  NaN
2022-03-01 14:00:00     B    B    A    A
2022-03-01 15:00:00     B    C    A    A
2022-03-01 16:00:00     A    C    A    A

第二行进行计数,因此

event                  A    B    C
time                              
2022-03-01 10:00:00  1.0  0.0  0.0
2022-03-01 11:00:00  1.0  1.0  0.0
2022-03-01 12:00:00  2.0  1.0  0.0
2022-03-01 13:00:00  1.0  2.0  0.0
2022-03-01 14:00:00  2.0  2.0  0.0
2022-03-01 15:00:00  2.0  1.0  1.0
2022-03-01 16:00:00  3.0  0.0  1.0