按日期区间跨CSV匹配SF1季度数据填充至DAILY文件的实现方案
最优实现方案:基于Pandas向量化区间匹配的财报数据填充
核心逻辑是利用pd.merge_asof的内置区间匹配能力替代手写循环字典遍历,在保证逻辑完全符合需求的前提下,性能较手写循环方案提升两个数量级以上,同时避免边界判断的人为错误。
实现步骤
1. 前置数据预处理
- 统一两个数据集的日期字段为
datetime格式,避免字符串格式匹配的误差 - 分别对SF1、DAILY按
ticker + 日期升序排序,这是merge_asof能正常工作的必要条件 - 从SF1中仅提取需要的目标字段,减少内存占用
2. 核心匹配逻辑
无需手动构建ticker->披露日期列表的循环字典,利用merge_asof的内置特性自动实现区间匹配:
- 匹配规则:对DAILY中的每一行,在同
ticker范围内,查找所有早于该行交易日期的最近一条SF1披露记录 - 自动适配业务要求:某条SF1记录从披露日(含)开始生效,直到同ticker的下一条SF1披露日当天自动切换为新值,完全匹配“2010-01-01披露的季度数据覆盖到2010-03-04下一次披露前”的区间填充规则
核心可运行代码
import pandas as pd # 定义需要从SF1传递的目标字段 TARGET_FIELDS = [ 'accoci', 'assets', 'assetsavg', 'assetsc', 'assetsnc', 'assetturnover', 'bvps', 'capex', 'cashneq', 'cashnequsd', 'cor', 'consolinc', 'currentratio', 'de', 'debt', 'debtc', 'debtnc', 'debtusd', 'deferredrev', 'depamor', 'deposits', 'divyield', 'dps', 'ebit' ] # 读取原始CSV sf1 = pd.read_csv("SF1.csv") daily = pd.read_csv("DAILY.csv") # 统一日期格式 sf1['datekey'] = pd.to_datetime(sf1['datekey']) daily['date'] = pd.to_datetime(daily['date']) # 预处理SF1:保留需要的字段、排序 sf1_processed = sf1[['ticker', 'datekey'] + TARGET_FIELDS].sort_values( by=['ticker', 'datekey'] ).reset_index(drop=True) # 预处理DAILY:排序 daily_processed = daily.sort_values( by=['ticker', 'date'] ).reset_index(drop=True) # 执行区间匹配合并 merged_result = pd.merge_asof( left=daily_processed, right=sf1_processed, left_on='date', right_on='datekey', by='ticker', # 仅在相同ticker范围内匹配,避免跨股票数据串值 direction='backward' # 取不晚于当前交易日期的最近一次财报披露值 ) # 清理临时匹配键,保留DAILY原有字段+新增的SF1目标字段 merged_result = merged_result.drop(columns=['datekey']) # 导出最终结果 merged_result.to_csv("merged_output.csv", index=False)
方案优势
- 性能最优:merge_asof底层采用二分查找实现匹配,时间复杂度为
O((N+M)logM)(N为DAILY总行数,M为SF1总记录数),完全避免了iterrows、逐行遍历字典的Python层循环开销,千万行级数据也可在分钟级完成处理 - 逻辑严谨:自动处理区间边界,不会出现“披露日当天漏匹配”“下一次披露日未及时切换新值”的人为代码错误
- 低维护成本:无需手动构建披露日期列表、计算每个区间的右边界、逐行判断DAILY日期落在哪个区间,代码量减少70%以上
- 符合金融数据常识:对于早于标的首次财报披露日期的DAILY行,对应目标字段自动填充为NaN,不存在无依据的硬填值问题
注意事项
- 必须保证SF1和DAILY都按匹配键(
ticker、对应日期)升序排序,否则merge_asof会返回错误的匹配结果 - 如果存在同ticker同
datekey的重复SF1记录,需要先对SF1做去重(按ticker + datekey保留最后更新的一条),避免合并时出现重复行 - 可适配不同披露时点规则:如果需要将下一次披露日当天仍使用上一季度的旧值,仅需将SF1的匹配键设置为
datekey + pd.Timedelta(days=1),即可实现“披露次日生效”的逻辑,不需要改动核心匹配代码
内容的提问来源于stack exchange,提问作者George Adams
相关产品推荐
相关产品推荐

