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

如何调整Pandas DataFrame至指定行列结构?求解决方案

问题描述

我尝试将嵌套字典转换为特定格式的Pandas DataFrame,但输出不符合预期。

原始字典:

from decimal import Decimal
import pandas as pd

options_pnl={'BTC': {'Pnl(since 6pm)': Decimal('7831.52228528'),
  'Pnl(4 hr)': Decimal('2930.47450133'),
  'Pnl(1 hr)': Decimal('1416.81306308'),
  'Volume(since 6pm)': Decimal('24509290.62181862'),
  'Volume(4 hr)': Decimal('4504202.83422724'),
  'Volume(1 hr)': Decimal('1067850.01837278')},
 'ETH': {'Pnl(since 6pm)': Decimal('387.87564823'),
  'Pnl(4 hr)': Decimal('-349.14871930'),
  'Pnl(1 hr)': Decimal('656.74824550'),
  'Volume(since 6pm)': Decimal('10700784.53262117'),
  'Volume(4 hr)': Decimal('1968872.36761706'),
  'Volume(1 hr)': Decimal('778937.22275036')}} 

最初的代码生成了宽表格式,但我需要转换为如下长表结构(同时调整时间区间的显示文本):

PNL    Volume
BTC since 6pm       7831       24509290
BTC since last 4 hr 2930       4504202
BTC last 1 hr       1416       1067850
ETH since 6pm       387        10700784
ETH since last 4 hr -349       1968872  
ETH last 1 hr       656        778937

我尝试了循环处理字典,但结果不符合预期,请求帮助。


解决方案1:使用Pandas内置函数(推荐)

通过stack()、正则提取、pivot_table()等方法快速转换格式,同时处理时间区间文本:

from decimal import Decimal
import pandas as pd

# 原始字典
options_pnl={'BTC': {'Pnl(since 6pm)': Decimal('7831.52228528'),
  'Pnl(4 hr)': Decimal('2930.47450133'),
  'Pnl(1 hr)': Decimal('1416.81306308'),
  'Volume(since 6pm)': Decimal('24509290.62181862'),
  'Volume(4 hr)': Decimal('4504202.83422724'),
  'Volume(1 hr)': Decimal('1067850.01837278')},
 'ETH': {'Pnl(since 6pm)': Decimal('387.87564823'),
  'Pnl(4 hr)': Decimal('-349.14871930'),
  'Pnl(1 hr)': Decimal('656.74824550'),
  'Volume(since 6pm)': Decimal('10700784.53262117'),
  'Volume(4 hr)': Decimal('1968872.36761706'),
  'Volume(1 hr)': Decimal('778937.22275036')}} 

# 1. 转换为DataFrame并转置
df = pd.DataFrame.from_dict(options_pnl).T

# 2. 拆分列名,提取指标类型和时间区间
df = df.stack().reset_index()
df.columns = ['Asset', 'Metric', 'Value']
df[['MetricType', 'Interval']] = df['Metric'].str.extract(r'(\w+)\((.*)\)')

# 3. 格式化时间区间文本
def format_interval(interval):
    if interval == '4 hr':
        return 'since last 4 hr'
    elif interval == '1 hr':
        return 'last 1 hr'
    return interval

df['Interval'] = df['Interval'].apply(format_interval)

# 4. 重塑为目标格式并转换为整数类型
result = df.pivot_table(index=['Asset', 'Interval'], columns='MetricType', values='Value', aggfunc='first')
result = result.astype('int64').rename(columns={'Pnl': 'PNL'})

# 合并索引生成目标行标签
result.index = result.index.map(lambda x: f"{x[0]} {x[1]}")

print(result)

输出结果:

PNL    Volume
BTC since 6pm          7831  24509290
BTC since last 4 hr    2930   4504202
BTC last 1 hr          1416   1067850
ETH since 6pm           387  10700784
ETH since last 4 hr    -349   1968872
ETH last 1 hr           656    778937

解决方案2:修正循环逻辑

原循环代码的问题是将Pnl和Volume拆分为单独行,导致同一时间区间的两个值分散。可以先按时间区间分组,再合并指标值:

from decimal import Decimal
import pandas as pd

options_pnl={'BTC': {'Pnl(since 6pm)': Decimal('7831.52228528'),
  'Pnl(4 hr)': Decimal('2930.47450133'),
  'Pnl(1 hr)': Decimal('1416.81306308'),
  'Volume(since 6pm)': Decimal('24509290.62181862'),
  'Volume(4 hr)': Decimal('4504202.83422724'),
  'Volume(1 hr)': Decimal('1067850.01837278')},
 'ETH': {'Pnl(since 6pm)': Decimal('387.87564823'),
  'Pnl(4 hr)': Decimal('-349.14871930'),
  'Pnl(1 hr)': Decimal('656.74824550'),
  'Volume(since 6pm)': Decimal('10700784.53262117'),
  'Volume(4 hr)': Decimal('1968872.36761706'),
  'Volume(1 hr)': Decimal('778937.22275036')}} 

data = []

for asset, values in options_pnl.items():
    # 按时间区间分组存储Pnl和Volume
    interval_data = {}
    for metric, value in values.items():
        metric_type, interval = metric.split('(')
        interval = interval.rstrip(')')
        # 格式化时间区间文本
        if interval == '4 hr':
            interval = 'since last 4 hr'
        elif interval == '1 hr':
            interval = 'last 1 hr'
        # 存入对应区间的字典
        if interval not in interval_data:
            interval_data[interval] = {'PNL': 0, 'Volume': 0}
        interval_data[interval][metric_type] = int(value)
    # 转换为目标行格式
    for interval, metrics in interval_data.items():
        data.append([f"{asset} {interval}", metrics['PNL'], metrics['Volume']])

# 生成DataFrame并设置索引
options_pnl_df = pd.DataFrame(data, columns=['', 'PNL', 'Volume']).set_index('')

print(options_pnl_df)

输出结果与方案1一致。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.05 16:09:51