基于时间窗口(未来/过去)为Pandas DataFrame创建新列
如何给Pandas DataFrame添加未来时间窗口的事件标记
我来帮你搞定这个需求!你想要给每个ID的每一行标记未来指定时间窗口内e_1是否出现True,用一个时间增量列表来灵活控制窗口,对吧?下面是具体的实现步骤和代码,亲测好用~
第一步:准备数据并预处理
首先得把基础工作做扎实:确保日期列是datetime类型,并且数据按ID和日期排序,这样后续的时间窗口计算才准确。
import pandas as pd # 模拟你的原始数据 data = { 'ID': [1,1,1,2,2], 'date': ['2016-02-01', '2016-02-02', '2016-02-03', '2016-02-01', '2016-02-02'], 'e_1': [False, False, True, False, True] } df = pd.DataFrame(data) # 把date列转为datetime格式,这一步是核心前提! df['date'] = pd.to_datetime(df['date']) # 按ID和日期排序,保证每个ID的时间序列是连续有序的 df = df.sort_values(['ID', 'date']).reset_index(drop=True)
第二步:定义时间增量列表
你可以根据需求灵活定义时间窗口,比如1天、2天、5天、1个月。这里要注意:天用Timedelta,月用DateOffset——因为月份的天数不固定,Timedelta处理不了这类可变时长的单位。
# 自定义时间增量列表,想加多少窗口都可以扩展 time_deltas = [ pd.Timedelta(days=1), pd.Timedelta(days=2), pd.Timedelta(days=5), pd.DateOffset(months=1) # 处理月份必须用DateOffset ]
第三步:编写分组处理函数
因为每个ID的时间序列是独立的,所以我们要按ID分组处理。这里用rolling时间窗口来实现,比逐行遍历效率高太多,适合大数据量场景:
def add_future_event_flags(group, deltas): # 先把组内数据按日期倒序排列,这样"未来"的行就跑到前面了 group_sorted = group.sort_values('date', ascending=False) for delta in deltas: # 生成友好的列名,比如"future_1_day"、"future_1_month" if isinstance(delta, pd.Timedelta): col_name = f'future_{delta.days}_day{"s" if delta.days !=1 else ""}' elif isinstance(delta, pd.DateOffset): col_name = f'future_{delta.months}_month{"s" if delta.months !=1 else ""}' # 用时间窗口rolling,closed='left'表示排除当前行的日期(只看未来的时间) # any()检查窗口内是否有True出现 future_flag = group_sorted['e_1'].rolling( window=delta, closed='left', on='date' ).any() # 把结果按原顺序放回原组 group[col_name] = future_flag.sort_index(ascending=True).values return group # 把函数应用到每个ID组 df_with_flags = df.groupby('ID').apply(add_future_event_flags, deltas=time_deltas).reset_index(drop=True)
第四步:查看最终结果
运行完上面的代码,你就得到了带标记列的DataFrame,结果大概是这样的:
| ID | date | e_1 | future_1_day | future_2_days | future_5_days | future_1_month |
|---|---|---|---|---|---|---|
| 1 | 2016-02-01 | False | False | True | True | True |
| 1 | 2016-02-02 | False | True | True | True | True |
| 1 | 2016-02-03 | True | False | False | False | False |
| 2 | 2016-02-01 | False | True | True | True | True |
| 2 | 2016-02-02 | True | False | False | False | False |
一些关键注意事项
- 一定要确保
date列是datetime类型,否则时间窗口计算会直接报错。 - 处理月份、季度这类不固定天数的时间单位,必须用
pd.DateOffset,不能用pd.Timedelta。 closed='left'参数是为了排除当前日期的记录,如果你想包含当前日期,可以改成closed='both',根据你的实际需求调整。
内容的提问来源于stack exchange,提问作者nanounanue
相关产品推荐
相关产品推荐

