
本文详解如何将宽格式股价 dataframe(日期为索引、股票列为列)与交易记录 dataframe(含 date 和 symbol 列)高效关联,通过 stack + merge 实现精准价格匹配。
在量化分析或回测系统中,常需将交易指令(如买入/卖出某只股票)与其对应的历史价格对齐。典型场景是:一个 DataFrame 以日期为行索引、股票代码为列(宽格式),存储每日收盘价;另一个 DataFrame 记录每笔交易的日期(Date)、标的(Symbol)、方向(Order)和数量(Shares)。目标是为每笔交易添加当日该股票的成交价格(Price),生成带价格信息的交易明细表。
关键难点在于:第一个 DataFrame 是宽格式且索引为日期,而第二个 DataFrame 的日期是普通列,且需按“日期+股票代码”双重键匹配价格。直接使用 pd.concat() 或 join 并不适用——这不是简单的行拼接或索引对齐,而是基于多字段的查找式合并。
正确解法是:先将宽格式价格表转换为长格式(即“日期-股票-价格”三元组),再与交易表按 Date 和 Symbol 字段进行内连接(inner merge)。核心步骤如下:
- 重塑价格 DataFrame:使用 .stack() 将列名(如 'AAPL', 'IBM')转为新列(默认为 level_1),原索引(日期)自动成为 level_0;再用 .reset_index(name='Price') 展平并命名价格列;
- 执行合并:以交易表的 ['Date', 'Symbol'] 为左键,重塑后价格表的 ['level_0', 'level_1'] 为右键,指定 how='inner' 仅保留有价格匹配的交易;
- 清理冗余列:删除临时生成的 level_0 和 level_1 列,保留语义清晰的字段。
✅ 示例代码(假设 df_prices 索引为 DatetimeIndex,df_trades 含 Date 和 Symbol 列):
# 步骤1:将宽格式价格表转为长格式 price_long = df_prices.stack().reset_index(name='Price') price_long.columns = ['Date', 'Symbol', 'Price'] # 显式重命名,提升可读性 # 步骤2:与交易表合并(推荐显式列名,避免 level_x 混淆) result = df_trades.merge(price_long, on=['Date', 'Symbol'], how='inner') # 输出结果(自动包含 Date, Symbol, Order, Shares, Price) print(result)
? 注意事项:
- 确保 df_trades['Date'] 与 df_prices.index 的数据类型一致(建议统一为 datetime64[ns]),可用 pd.to_datetime() 强制转换;
- 若存在某日某股票无价格数据(如停牌),how='inner' 会自动过滤掉该交易;如需保留并填充 NaN,改用 how='left';
- stack() 默认忽略 NaN 值,若原始价格表含空值,对应组合不会出现在长格式中;
- 对于大规模数据,可提前对 df_trades 和 price_long 的合并键列设置索引或使用 pd.merge(..., sort=False) 提升性能。
该方法逻辑清晰、无循环、完全向量化,是 Pandas 处理“宽表→长表→关联”类任务的标准范式,适用于任意多股票、多日期场景。










