You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用Pandas高效将L2订单簿数据转为带层级列的DataFrame?

问题描述

我有形式为[[[key1,value1],[key2,value2],...,500],...,n]的L2订单簿数据(包含500个层级),想要将其转换为包含key_1至key_500、value_1至value_500列的DataFrame——也就是每个层级对应一组price和volume列(比如level_1_volume、level_2_volume……level_500_volume)。

目前我用df.iterrows()循环遍历现有DataFrame(该DataFrame仅将上述列表作为一列),把值提取到单独列表后再创建新DataFrame合并列,但这个方法效率远低于数据集上的其他操作。请问能不能用Pandas内置方法实现?

示例数据结构

List1 = [[key1.1,val1.1],[key2.1,val2.1],...]
List2 = [[key1.2,val1.2],[key2.2,val2.2],...]

# 转换后目标结构
         key1_column, val1_column, key2_column, val2_column
Row_List1 key1.1       val1.1           key2.1          val2.1
Row_List2 key1.2       val1.2           key2.2          val2.2

当前实现代码

(其中["bids"]和["asks"]列包含500个键值对的字典/JSON对象)

# 初始化价格和成交量的空列表
prices_bids = [[] for _ in range(500)]
volumes_bids = [[] for _ in range(500)]
prices_asks = [[] for _ in range(500)]
volumes_asks = [[] for _ in range(500)]

# 遍历每一行
for index, row in df.iterrows():

    attributes = row["bids"]
    result_bids = [[key,attributes[key]] for key in sorted(attributes.keys(), reverse=True)]

    attributes = row["asks"]
    result_asks = [[key,attributes[key]] for key in sorted(attributes.keys(), reverse=False)]
    
    for i in range(500):
        prices_bids[i].append(np.float64(result_bids[i][0]))
        volumes_bids[i].append(np.float64(result_bids[i][1]))
        prices_asks[i].append(np.float64(result_asks[i][0]))
        volumes_asks[i].append(np.float64(result_asks[i][1]))
        

# 从列表创建DataFrame列
for i in range(500):
    # 将价格转换为点差形式
    df[f"bid_level_{i}_price"] = pd.Series((df["mid_price"]/pd.Series(prices_bids[i],dtype='float64')-1)*10000,dtype="float64")
    df[f"bid_level_{i}_volume"] = pd.Series(volumes_bids[i],dtype='float64')
    df[f"ask_level_{i}_price"] = pd.Series((df["mid_price"]/pd.Series(prices_asks[i],dtype='float64')-1)*10000,dtype="float64")
    df[f"ask_level_{i}_volume"] = pd.Series(volumes_asks[i],dtype='float64')

优化方案

完全可以用Pandas的向量化操作替代循环,大幅提升效率。核心思路是利用apply结合pd.DataFrame批量解析每行的订单簿数据,再通过列重命名、拼接完成转换,最后统一计算价差:

步骤1:批量解析bids和asks列

import pandas as pd
import numpy as np

# 处理bids列:按价格降序排序键值对,转成结构化数据后堆叠,方便后续展开为列
def parse_bids(x):
    sorted_items = sorted(x.items(), key=lambda item: -float(item[0]))
    return pd.DataFrame(sorted_items, columns=['price', 'volume']).T.stack()

# 处理asks列:按价格升序排序键值对
def parse_asks(x):
    sorted_items = sorted(x.items(), key=lambda item: float(item[0]))
    return pd.DataFrame(sorted_items, columns=['price', 'volume']).T.stack()

# 生成解析后的结构化DataFrame
bids_df = df['bids'].apply(parse_bids).unstack()
asks_df = df['asks'].apply(parse_asks).unstack()

# 给解析后的列重命名,匹配需求的格式
bids_df.columns = [f"bid_level_{i}_{col}" for col in ['price', 'volume'] for i in range(500)]
asks_df.columns = [f"ask_level_{i}_{col}" for col in ['price', 'volume'] for i in range(500)]

步骤2:计算价差并合并到原DataFrame

# 把解析好的订单簿数据合并到原DataFrame
df = pd.concat([df, bids_df, asks_df], axis=1)

# 批量计算bid/ask的价差(替代原循环)
for i in range(500):
    df[f"bid_level_{i}_price"] = (df["mid_price"] / df[f"bid_level_{i}_price"].astype(np.float64) - 1) * 10000
    df[f"ask_level_{i}_price"] = (df["mid_price"] / df[f"ask_level_{i}_price"].astype(np.float64) - 1) * 10000

# 统一转换成交量列的数值类型
for i in range(500):
    df[f"bid_level_{i}_volume"] = df[f"bid_level_{i}_volume"].astype(np.float64)
    df[f"ask_level_{i}_volume"] = df[f"ask_level_{i}_volume"].astype(np.float64)

效率说明

  • 彻底避免了iterrows()和嵌套循环的低效操作,用Pandas内置的向量化逻辑处理,速度能提升数倍甚至一个数量级(取决于数据集大小)。
  • apply结合pd.DataFrame的方式,本质是把每行的字典批量转成结构化数据,再通过unstack展开成列,比手动维护列表更简洁可靠。

内容的提问来源于stack exchange,提问作者Dontwannausemynormalnick

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.26 21:37:50