Pandas跨DataFrame查询计算的向量化加速方案
向量化优化实现方案
核心思路是完全去掉Python层逐行循环,通过预分组计算全市场所有股票各年度的首尾价格+表关联匹配的方式实现,所有操作均为pandas底层C实现的向量化逻辑,千万级数据量下耗时可从小时级压缩到秒级。
实现步骤
1. 预处理价格表
先对全量价格数据做一次全局排序、去重,提前标记每条价格记录对应的收益年度,这一步全表只跑一次:
import pandas as pd import numpy as np # 提前去重,避免同一ticker同一日期多条记录干扰结果 prices_df = prices_df.drop_duplicates(subset=['ticker', 'date'], keep='last') # 按股票代码、日期全局排序,替代循环里的单票排序 prices_df = prices_df.sort_values(by=['ticker', 'date']).reset_index(drop=True) # 标记每条价格所属的收益计算年度,100%对齐原逻辑的区间规则 # 原逻辑区间为[Y-01-01, Y+1-01-01](Y=基本面year+1),因此每年1月1日的价格归属于上一年度的收益计算 prices_df['calc_year'] = prices_df['date'].dt.year jan1_mask = (prices_df['date'].dt.month == 1) & (prices_df['date'].dt.day == 1) prices_df.loc[jan1_mask, 'calc_year'] -= 1
2. 批量计算所有股票各年度收益率
按ticker+calc_year分组,直接取每个分组的首尾价格计算收益率,不需要逐股票、逐年份筛选:
annual_return_df = ( prices_df .groupby(['ticker', 'calc_year'], as_index=False) .agg( # 注意:原代码用的是closeadj复权价,如果你的表中字段名是close就替换成'close' start_price=('closeadj', 'first'), end_price=('closeadj', 'last') ) ) annual_return_df['annual_return'] = (annual_return_df['end_price'] - annual_return_df['start_price']) / annual_return_df['start_price']
3. 关联匹配基本面表
给基本面表生成匹配键,通过左连接直接关联对应收益率,匹配不到数据的位置填充'n/a'和原逻辑保持一致:
# 原逻辑中基本面year对应收益年度为year+1 fundamentals_df['match_year'] = fundamentals_df['year'].astype(int) + 1 # 左连接匹配,无循环 result = fundamentals_df.merge( annual_return_df[['ticker', 'calc_year', 'annual_return']], left_on=['ticker', 'match_year'], right_on=['ticker', 'calc_year'], how='left' ) # 对齐原逻辑的空值返回规则,若后续需要做数值计算建议保留np.nan不要转字符串 result['annual_return'] = result['annual_return'].fillna('n/a') # 清理临时字段 result = result.drop(columns=['match_year', 'calc_year'])
注意事项
- 如果你不需要把后一年1月1日的价格算入上一年度收益区间(即严格使用自然年[Y-01-01, Y-12-31]的价格),直接去掉
jan1_mask相关的年度偏移逻辑,用date.dt.year作为calc_year即可。 - 计算前务必检查价格表的停牌、缺失值情况,如果某年度内价格记录不足2条,分组计算的收益率会存在偏差,可在分组聚合后增加过滤逻辑。
- 替换字符串
'n/a'为np.nan可以避免收益率字段变成object类型,后续做统计、回测时性能会更高。
内容的提问来源于stack exchange,提问作者ng150716
相关产品推荐
相关产品推荐

