You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在不使用df.iterrows()的情况下向量化标记时间序列连续事件

问题描述

给定如下时间序列DataFrame:

时间(time)事件(event)
2020-01-01 12:00:001
2020-01-01 12:00:01NaN
2020-01-01 12:00:021
2020-01-01 12:00:031
2020-01-01 12:00:04NaN
2020-01-01 12:00:05NaN
2020-01-01 12:00:061
2020-01-01 12:00:07NaN

希望生成如下汇总DataFrame:

事件ID(event_id)开始时间(time_start)结束时间(time_stop)
12020-01-01 12:00:002020-01-01 12:00:01
22020-01-01 12:00:022020-01-01 12:00:04
32020-01-01 12:00:062020-01-01 12:00:07

思路是先添加event_i列,为每个连续事件组填充序号(1、2、3……),再生成汇总表,但卡在事件序号标记步骤。可以用df.iterrows()实现,但该方法不被推荐,请问如何通过向量化操作完成标记?

示例代码:

import pandas as pd
import numpy as np
# define mini-dataset as an example
data= {'time': ['2020-01-01 12:00:00', '2020-01-01 12:00:01', '2020-01-01 12:00:02','2020-01-01 12:00:03',
              '2020-01-01 12:00:04','2020-01-01 12:00:05', '2020-01-01 12:00:06', '2020-01-01 12:00:07',
              '2020-01-01 12:00:08', '2020-01-01 12:00:09','2020-01-01 12:00:10'],
     'event': [1,np.nan,1,1,np.nan,np.nan,1,np.nan,1,1,np.nan]}
df = pd.DataFrame(data)
df['time']=pd.to_datetime((df['time']))

# give a sequential number to each event
df['event_i'] = np.nan

# for each event-number, group by and stack: event_id,  time_start time_stop
# ...
解决方案

可以通过向量化的分组标记完成事件序号的生成,核心思路是识别连续事件组的起始点,再通过累加起始点的数量来生成序号,具体步骤如下:

1. 标记事件组的起始点

首先,判断每行是否是一个新事件组的开始:当当前行event为1,且上一行event为NaN时,标记为1(起始点),否则为0。用shift()方法实现:

# 标记事件组的起始位置:当前event为1且前一行event为NaN时,视为新组开始
df['is_start'] = (df['event'] == 1) & (df['event'].shift(1).isna())

2. 生成事件组序号

对起始点的标记进行累加,得到每个事件组的初始序号,再通过向前填充补全非事件行(event为NaN)的序号:

# 累加起始点得到初始序号,再向前填充补全非事件行的序号
df['event_i'] = df['is_start'].cumsum()
df['event_i'] = df['event_i'].where(df['event'].notna(), np.nan).ffill()

这一步完成后,event_i列会为每个连续事件组(包括后续的NaN终止行)分配对应的序号。

3. 生成汇总DataFrame

按event_i分组,提取每组的第一个时间作为开始时间,最后一个时间作为结束时间,再重置索引得到事件ID:

# 按事件组分组,提取起始和结束时间
summary_df = df.groupby('event_i').agg(
    time_start=('time', 'first'),
    time_stop=('time', 'last')
).reset_index()

# 重命名列并调整顺序
summary_df = summary_df.rename(columns={'event_i': '事件ID(event_id)'})
summary_df = summary_df[['事件ID(event_id)', 'time_start', 'time_stop']]
summary_df.columns = ['事件ID(event_id)', '开始时间(time_start)', '结束时间(time_stop)']

完整代码

import pandas as pd
import numpy as np

# 定义数据集
data= {'time': ['2020-01-01 12:00:00', '2020-01-01 12:00:01', '2020-01-01 12:00:02','2020-01-01 12:00:03',
              '2020-01-01 12:00:04','2020-01-01 12:00:05', '2020-01-01 12:00:06', '2020-01-01 12:00:07',
              '2020-01-01 12:00:08', '2020-01-01 12:00:09','2020-01-01 12:00:10'],
     'event': [1,np.nan,1,1,np.nan,np.nan,1,np.nan,1,1,np.nan]}
df = pd.DataFrame(data)
df['time']=pd.to_datetime(df['time'])

# 1. 标记事件组起始点
df['is_start'] = (df['event'] == 1) & (df['event'].shift(1).isna())

# 2. 生成事件组序号
df['event_i'] = df['is_start'].cumsum()
df['event_i'] = df['event_i'].where(df['event'].notna(), np.nan).ffill()

# 3. 生成汇总表
summary_df = df.groupby('event_i').agg(
    time_start=('time', 'first'),
    time_stop=('time', 'last')
).reset_index()

summary_df = summary_df.rename(columns={'event_i': '事件ID(event_id)'})
summary_df = summary_df[['事件ID(event_id)', 'time_start', 'time_stop']]
summary_df.columns = ['事件ID(event_id)', '开始时间(time_start)', '结束时间(time_stop)']

print(summary_df)

运行后输出的汇总表与需求一致,全程使用向量化操作,避免了iterrows()的低效问题。


内容的提问来源于stack exchange,提问作者Kris De Beleir

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.14 06:17:03