基于Pandas实现多资产半小时时间序列向前填充(ffill)的技术问询
解决方法:生成多资产的半小时时间序列并向前填充
我之前也碰到过一模一样的需求,核心就是先给每个资产生成覆盖起止日期的完整半小时时间轴,再和原始数据合并后按资产分组填充。下面给你一步步拆解实现:
第一步:准备基础环境与参数
首先确保时区统一(你代码里提到了欧洲时区,这里以Europe/London为例),定义好起止日期:
import pandas as pd from datetime import datetime import pytz some_time = datetime(2018,4,2,20,20,42) tz = pytz.timezone('Europe/London') # 起始日期设为指定时间的当天0点(带时区) start_date = datetime(some_time.year, some_time.month, some_time.day, tzinfo=tz) # 示例结束日期设为起始日次日(你可以根据需求修改) end_date = start_date + pd.Timedelta(days=1)
第二步:模拟/加载原始数据
假设你的原始数据包含asset_id、timestamp(带时区)和some_property字段,这里先模拟一份测试数据:
raw_data = pd.DataFrame({ 'asset_id': ['A', 'A', 'B', 'B'], 'timestamp': [ start_date + pd.Timedelta(hours=1), start_date + pd.Timedelta(hours=3), start_date + pd.Timedelta(hours=2), start_date + pd.Timedelta(hours=4) ], 'some_property': [10, 20, 30, 40] })
第三步:生成每个资产的完整时间序列
这一步是关键——要确保每个资产都有从start_date到end_date的所有半小时时间点:
# 获取所有唯一的资产ID unique_assets = raw_data['asset_id'].unique() # 逐个资产生成完整时间轴 full_time_frames = [] for asset in unique_assets: # 创建半小时频率的时间索引(必须和起止日期时区一致) time_index = pd.date_range(start=start_date, end=end_date, freq='30min', tz=tz) # 组合成该资产的空时间序列DataFrame asset_frame = pd.DataFrame({ 'asset_id': [asset] * len(time_index), 'timestamp': time_index }) full_time_frames.append(asset_frame) # 合并所有资产的时间序列 full_df = pd.concat(full_time_frames, ignore_index=True)
第四步:合并原始数据并向前填充
把原始数据的some_property值匹配到完整时间轴上,然后按资产分组向前填充缺失值:
# 左连接:保留所有时间点,原始数据存在的点会填充some_property,否则为NaN merged_df = pd.merge(full_df, raw_data, on=['asset_id', 'timestamp'], how='left') # 按资产分组,先排序时间再向前填充 final_df = merged_df.groupby('asset_id').apply( lambda x: x.sort_values('timestamp').ffill() ).reset_index(drop=True)
备选方法:用groupby + resample(注意坑点)
如果你想用groupby+resample的方式,需要确保原始数据的timestamp是带时区的索引,并且resample时指定时区,否则会出现时区不匹配错误:
# 先把timestamp设为索引 raw_data_indexed = raw_data.set_index('timestamp') # 分组后按半小时重采样,向前填充 final_df_alt = raw_data_indexed.groupby('asset_id').resample('30min', tz=tz).ffill().reset_index()
⚠️ 注意:这种方法如果原始数据的最早时间晚于start_date,不会生成start_date到原始数据最早时间之间的时间点,所以如果需要完整覆盖起止日期,第一种方法更可靠。
内容的提问来源于stack exchange,提问作者Jim O
相关产品推荐
相关产品推荐

