多索引DataFrame按BM频率重采样:后续日期缺失问题求助
解决多索引DataFrame按BM重采样时缺失后续日期的问题
你的问题根源在于:groupby('id').resample('BM') 会基于每个id自身的时间范围生成重采样索引——也就是说,每个id只在自己有数据的时间段内生成BM日期,一旦过了该id最后一条非NaN数据的日期,就不会继续生成后续日期。
要让所有id都延续到统一的结束日期,你需要先定义全局的BM时间序列,再让每个id对齐这个序列。下面是两种可行的实现方式:
方法一:先拆堆再重采样(更高效)
- 首先确定你需要的全局时间范围:可以取整个数据集的最早BM日期,再手动指定结束日期(比如你想要到2024年12月的最后一个工作日)
- 把多索引DataFrame拆成宽表(id为列),对齐全局时间序列后再恢复成多索引
import pandas as pd # 假设你的原DataFrame是多索引:df.index = pd.MultiIndex.from_tuples([(date, id), ...], names=['date', 'id']) # 步骤1:定义全局BM时间序列 # 取整个数据集的最早日期,转成BM格式 start_bm = df.index.get_level_values('date').min().to_period('BM').start_time # 手动指定结束日期(比如2024年12月的最后一个工作日) end_bm = pd.to_datetime('2024-12-31').to_period('BM').start_time # 生成完整的BM日期序列 full_bm_dates = pd.date_range(start=start_bm, end=end_bm, freq='BM') # 步骤2:拆成宽表并对齐全局日期 df_wide = df.unstack(level='id') # 把id转成列,date作为索引 # 重采样对齐全局日期,保留BM频率 df_resampled_wide = df_wide.reindex(full_bm_dates).asfreq('BM') # 步骤3:恢复成原多索引格式 df_final = df_resampled_wide.stack(level='id').reset_index().set_index(['date', 'id'])
方法二:GroupBy自定义函数(更直观)
通过自定义函数,让每个id的组都对齐全局的BM日期序列:
# 先定义全局BM时间序列(同方法一) start_bm = df.index.get_level_values('date').min().to_period('BM').start_time end_bm = pd.to_datetime('2024-12-31').to_period('BM').start_time full_bm_dates = pd.date_range(start=start_bm, end=end_bm, freq='BM') # 自定义重采样函数:让每个组对齐全局日期 def resample_to_full_range(group): return group.reindex(full_bm_dates).asfreq('BM') # 应用到每个id的组 df_final = df.groupby('id', group_keys=False).apply(resample_to_full_range)
关键说明
- 如果你不需要从数据集最早日期开始,也可以直接手动指定
start_bm(比如pd.to_datetime('2014-01-31')) asfreq('BM')会保留BM频率的索引,同时将原数据中没有的日期填充为NaN,符合你的需求
内容的提问来源于stack exchange,提问作者senorita.xi
相关产品推荐
相关产品推荐

