高级索引:我需要修改时间序列数据以回填特定时间戳的所有缺失值

Advanced Indexing: I need to munge time series data to backfill all missing values for a specific timestamp

输入二维数据:

ticker, date, time, price
AAPL, 12-04-2021, 9:45:00, 10000
AAPL, 12-04-2021, 9:51:00, 10005
AMZN, 12-04-2021, 9:46:00, 10007
AMZN, 12-04-2021, 9:52:00, 10010

期望的输出:

一个回填的分层数据框,可以通过日期、时间戳和工具进行索引,但它包含每个观察到的代码和时间戳的所有缺失时间戳的条目。此处的虚拟数据显示 AAPL 在 9:45 A.M 和 9:51 处有 2 个观察到的价格,它们不与 AMZN 的其他两个时间戳价格相交。我想做的是为每个观察到的索引创建一个时间戳条目,然后使用下一个可用时间观察来填充它。所以本质上我想要

df["12-04-2021", "9:46:00", "AAPL"]到return10005,在9:51

的观察

df["12-04-2021", "9:45:00", "AMZN"]到return10007,在9:46

的观察

或者通常需要将数据重组为

ticker, date, time, price
AAPL, 12-04-2021, 9:45:00, 10000
AAPL, 12-04-2021, 9:46:00, 10005
AAPL, 12-04-2021, 9:51:00, 10005
AAPL, 12-04-2021, 9:52:00, 10005 [Should be the next available value in time possible]
AMZN, 12-04-2021, 9:45:00, 10007
AMZN, 12-04-2021, 9:46:00, 10007
AMZN, 12-04-2021, 9:51:00, 10010
AMZN, 12-04-2021, 9:52:00, 10010

这是样本虚拟数据,但通常在市场交易时间内的时间戳范围内会有更多的日期和代码,我考虑过是应该先执行回填还是索引数据帧然后回填。我想我需要从根本上了解如何设置数据帧,以便为丢失的时间戳分配 NA 值,因为无论我现在尝试什么,都会给我一个 KeyError 而不是 NA 值。

我试过了

df = pd.read_csv(`DATA`, index_col=['date', 'time', 'ticker'])
df = df.stack(dropna=False)
df.update(df.groupby(['date', 'time', 'ticker']).bfill())

但我认为我并没有从根本上理解如何将 [date,time] 列指定为通用字段,该字段必须具有观测值或 NA 才能开始回填。对于我尝试过的大多数组合,我都遇到了关键错误。

任何关于如何理解这一点的想法将不胜感激,如果你一路走到这里,谢谢。

我建议将 datetimes 转换为日期时间,然后按 Series.unstack with backfilling and forward filling missing values and then reshape back by DataFrame.stack:

重塑
df['datetimes'] = pd.to_datetime(df.pop('date') + ' ' + df.pop('time'))

df = (df.set_index(['ticker','datetimes'])['price']
        .unstack()
        .bfill(axis=1)
        .ffill(axis=1)
        .stack()
        .reset_index(name='col2'))

print (df)
  ticker           datetimes     col2
0   AAPL 2021-12-04 09:45:00  10000.0
1   AAPL 2021-12-04 09:46:00  10005.0
2   AAPL 2021-12-04 09:51:00  10005.0
3   AAPL 2021-12-04 09:52:00  10005.0
4   AMZN 2021-12-04 09:45:00  10007.0
5   AMZN 2021-12-04 09:46:00  10007.0
6   AMZN 2021-12-04 09:51:00  10010.0
7   AMZN 2021-12-04 09:52:00  10010.0

df['date'] = df['datetimes'].dt.date
df['time'] = df['datetimes'].dt.time
print (df)
  ticker           datetimes     col2        date      time
0   AAPL 2021-12-04 09:45:00  10000.0  2021-12-04  09:45:00
1   AAPL 2021-12-04 09:46:00  10005.0  2021-12-04  09:46:00
2   AAPL 2021-12-04 09:51:00  10005.0  2021-12-04  09:51:00
3   AAPL 2021-12-04 09:52:00  10005.0  2021-12-04  09:52:00
4   AMZN 2021-12-04 09:45:00  10007.0  2021-12-04  09:45:00
5   AMZN 2021-12-04 09:46:00  10007.0  2021-12-04  09:46:00
6   AMZN 2021-12-04 09:51:00  10010.0  2021-12-04  09:51:00
7   AMZN 2021-12-04 09:52:00  10010.0  2021-12-04  09:52:00

使用 GroupBy.apply 和 lambda 函数的解决方案:

df['datetimes'] = pd.to_datetime(df.pop('date') + ' ' + df.pop('time'))

dates = df['datetimes'].drop_duplicates().sort_values()

f = lambda x: x.reindex(dates, method='bfill').ffill()
df = (df.set_index('datetimes').groupby(['ticker'])['price'].apply(f)
        .reset_index(name='col2')
        )
    
print (df)
  ticker           datetimes     col2
0   AAPL 2021-12-04 09:45:00  10000.0
1   AAPL 2021-12-04 09:46:00  10005.0
2   AAPL 2021-12-04 09:51:00  10005.0
3   AAPL 2021-12-04 09:52:00  10005.0
4   AMZN 2021-12-04 09:45:00  10007.0
5   AMZN 2021-12-04 09:46:00  10007.0
6   AMZN 2021-12-04 09:51:00  10010.0
7   AMZN 2021-12-04 09:52:00  10010.0