如何用Pandas将事件起止时长数据转为布尔时间序列?
高效将事件时间数据转换为布尔格式的Pandas方案
假设你的原始事件数据结构如下(以分钟粒度为例):
import pandas as pd # 示例输入:事件ID、起始时间、持续时长(分钟) df_events = pd.DataFrame({ 'event_id': [1, 2], 'start_time': pd.to_datetime(['2024-01-01 10:00:00', '2024-01-01 10:05:00']), 'duration_min': [3, 4] })
目标是生成按时间粒度展开的布尔矩阵(事件发生时标记为1,否则为0),以下是两种无需嵌套循环的高效实现方案:
方案一:利用IntervalIndex矢量化判断
这种方法通过时间区间匹配实现,完全基于Pandas矢量化操作,性能最优:
# 1. 计算每个事件的结束时间,并创建时间区间索引 df_events['end_time'] = df_events['start_time'] + pd.to_timedelta(df_events['duration_min'], unit='m') event_intervals = pd.IntervalIndex.from_arrays(df_events['start_time'], df_events['end_time'], closed='left') # 2. 生成覆盖所有事件的完整时间序列(freq参数可调整粒度,如'S'代表秒) min_time = df_events['start_time'].min() max_time = df_events['end_time'].max() full_timestamps = pd.date_range(start=min_time, end=max_time, freq='T') # 3. 批量判断每个时间戳是否落在事件区间内,转换为整数布尔值 result = pd.DataFrame( data=[event_intervals.contains(ts) for ts in full_timestamps], index=full_timestamps, columns=[f'event_{eid}' for eid in df_events['event_id']] ).astype(int)
方案二:生成事件时间点后透视聚合
适合需要更灵活处理时间粒度的场景:
# 1. 为每个事件生成所有包含的时间戳并展开 event_time_points = df_events.apply( lambda row: pd.date_range( row['start_time'], row['start_time'] + pd.to_timedelta(row['duration_min'], unit='m'), freq='T', closed='left' ), axis=1 ).explode() # 2. 整理数据格式,标记事件存在 event_time_points = event_time_points.reset_index().rename(columns={'index': 'event_id', 0: 'timestamp'}) event_time_points['value'] = 1 # 3. 生成完整时间序列,合并后透视填充0 full_timestamps = pd.date_range( start=df_events['start_time'].min(), end=df_events['end_time'].max(), freq='T' ).to_frame(name='timestamp') result = full_timestamps.merge(event_time_points, on='timestamp', how='left') result = result.pivot(index='timestamp', columns='event_id', values='value').fillna(0).astype(int) result.columns = [f'event_{col}' for col in result.columns]
方案优势
两种方案都避免了Python嵌套循环的低效问题,利用Pandas内部的C扩展实现矢量化计算,处理数百个跨小时的事件时,性能比循环提升数十倍甚至上百倍。可通过调整freq参数适配秒、小时等不同时间粒度。
内容的提问来源于stack exchange,提问作者Apollo42
相关产品推荐
相关产品推荐

