给定以下形式的数据框:
日期 | 窗户 | |
---|---|---|
0 | 2009-01-01 00:00:00 | 2 |
1 | 2009-01-02 00:00:00 | 1 |
2 | 2009-01-03 00:00:00 | 3 |
可以通过以下方式生成
df = pd.DataFrame({'date': pd.date_range(start='20090101', end='20090103')})
df['window'] = [2, 1, 3]
目标是为“日期”的过去“窗口”内的每个“新日期”创建一行。以上面的数据框为例,结果应该是:
日期 | 窗户 | 回顾 | 新日期 | |
---|---|---|---|---|
0 | 2009-01-01 00:00:00 | 2 | 0 | 2009-01-01 00:00:00 |
0 | 2009-01-01 00:00:00 | 2 | 1 | 2008-12-31 00:00:00 |
0 | 2009-01-01 00:00:00 | 2 | 2 | 2008-12-30 00:00:00 |
1 | 2009-01-02 00:00:00 | 1 | 0 | 2009-01-02 00:00:00 |
1 | 2009-01-02 00:00:00 | 1 | 1 | 2008-12-31 00:00:00 |
2 | 2009-01-03 00:00:00 | 3 | 0 | 2009-01-03 00:00:00 |
2 | 2009-01-03 00:00:00 | 3 | 1 | 2009-01-02 00:00:00 |
2 | 2009-01-03 00:00:00 | 3 | 2 | 2008-12-31 00:00:00 |
2 | 2009-01-03 00:00:00 | 3 | 3 | 2008-12-30 00:00:00 |
到目前为止我的解决方案是
df['lookback'] = df['window'].apply(lambda x: range(x+1))
df = df.explode('lookback')
df['new_date'] = df[['date', 'lookback']].apply(lambda x: add_biz_dt(x[0], -x[1]), axis=1)
请注意,add_biz_dt() 是我的内部方法,它采用日期时间第一个参数和数字第二个参数,并获取相应的业务日期。我必须使用 add_biz_dt。
我正在努力改进它,使其更加高效。可能有比使用“爆炸”更好的方法,而“应用”方法似乎效率特别低。
一个可能的选项(没有自定义功能):
lookbacks = (
pd.DataFrame(
[
[[(iw, d - pd.Timedelta(iw, unit="D"))
for iw in range(0, w+1)]
for d,w in df.to_numpy()]
])
.T.explode(0)[0].apply(pd.Series)
.set_axis(["lookback", "new_date"], axis=1)
)
out = df.join(lookbacks)
输出:
print(out)
date window lookback new_date
0 2009-01-01 2 0 2009-01-01
0 2009-01-01 2 1 2008-12-31
0 2009-01-01 2 2 2008-12-30
1 2009-01-02 1 0 2009-01-02
1 2009-01-02 1 1 2009-01-01
2 2009-01-03 3 0 2009-01-03
2 2009-01-03 3 1 2009-01-02
2 2009-01-03 3 2 2009-01-01
2 2009-01-03 3 3 2008-12-31