如何高效将股票Level2 Pandas DataFrame按价格递增转为单行多列?
高效转换股票Level2 Pandas DataFrame为单行多列格式(实时快照适配)
需求说明
将包含买卖盘(bid/ask)的股票Level2数据从多行格式,按价格递增规则转换为单行多列格式:
- 以索引9(bid类型)和10(ask类型)为起始,生成
price_bid_1、price_ask_1、volume_bid_1、volume_ask_1列 - 依次遍历剩余行,生成
price_bid_2、price_ask_2等对应列,直至所有行处理完成 - 要求处理速度快,适配实时快照的低延迟场景
原始数据
import pandas as pd df = pd.DataFrame({ 'price': {0: 1.0012, 1: 1.00115, 2: 1.0011, 3: 1.00105, 4: 1.001, 5: 1.00095, 6: 1.0009, 7: 1.00085, 8: 1.0008, 9: 1.00075, 10: 1.0007, 11: 1.00065, 12: 1.0006, 13: 1.00055, 14: 1.0005, 15: 1.00045, 16: 1.0004, 17: 1.00035, 18: 1.0003, 19: 1.00025}, 'volume': {0: 45.0, 1: 38.0, 2: 50.0, 3: 42.0, 4: 51.0, 5: 55.0, 6: 28.0, 7: 28.0, 8: 16.0, 9: 2.0, 10: 13.0, 11: 24.0, 12: 41.0, 13: 18.0, 14: 32.0, 15: 38.0, 16: 36.0, 17: 29.0, 18: 78.0, 19: 29.0}, 'type': {0: 'bid', 1: 'bid', 2: 'bid', 3: 'bid', 4: 'bid', 5: 'bid', 6: 'bid', 7: 'bid', 8: 'bid', 9: 'bid', 10: 'ask', 11: 'ask', 12: 'ask', 13: 'ask', 14: 'ask', 15: 'ask', 16: 'ask', 17: 'ask', 18: 'ask', 19: 'ask'} })
解决方案
方法一:Numpy向量化实现(最优性能,适配实时场景)
完全基于Numpy的向量化操作,避免Python循环,处理速度比纯Pandas循环快数十倍,适合低延迟的实时快照场景。
import numpy as np # 提取按价格递增排序的bid和ask数据 # bid从索引9到0(价格从低到高),ask从索引10到19 bid_data = df.loc[9::-1, ['price', 'volume']].values ask_data = df.loc[10:, ['price', 'volume']].values # 生成目标列名 n_levels = len(bid_data) columns = [] for i in range(1, n_levels + 1): columns.extend([ f'price_bid_{i}', f'price_ask_{i}', f'volume_bid_{i}', f'volume_ask_{i}' ]) # 拼接并展平数据,生成单行结果 flattened_data = np.column_stack([bid_data, ask_data]).flatten() result = pd.DataFrame([flattened_data], columns=columns) # 查看结果 print(result)
方法二:Pandas pivot拼接实现(代码简洁)
用Pandas的pivot功能转换宽表,代码可读性强,性能虽略逊于Numpy,但仍能满足大部分场景需求。
# 给bid/ask添加层级编号,bid按价格递增排序(反转原顺序) bid_df = df[df['type'] == 'bid'].iloc[::-1].reset_index(drop=True) bid_df['level'] = bid_df.index + 1 ask_df = df[df['type'] == 'ask'].reset_index(drop=True) ask_df['level'] = ask_df.index + 1 # 转换为宽表并调整列结构 bid_wide = bid_df.pivot(columns='level', values=['price', 'volume']).swaplevel(0, 1, axis=1).sort_index(axis=1) ask_wide = ask_df.pivot(columns='level', values=['price', 'volume']).swaplevel(0, 1, axis=1).sort_index(axis=1) # 重命名列 bid_wide.columns = [f'{col[1]}_{col[0]}_bid' for col in bid_wide.columns] ask_wide.columns = [f'{col[1]}_{col[0]}_ask' for col in ask_wide.columns] # 按目标列顺序合并结果 result = pd.concat([bid_wide, ask_wide], axis=1).reindex(columns=columns) # 查看结果 print(result)
性能说明
- Numpy向量化方法:所有操作在C语言层面执行,无Python循环,延迟极低,是实时场景的首选方案
- Pandas pivot方法:代码更易维护,但涉及Pandas内部的对象操作,性能略低于Numpy方案
内容的提问来源于stack exchange,提问作者Emerson Pedroso
相关产品推荐
相关产品推荐

