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

如何在groupby后向多级索引DataFrame正确添加平均价格列?

修复三级列索引DataFrame添加均值列的结构问题

1. 修复现有代码的问题

你当前代码的核心问题是直接修改了多级列索引的_levels属性——多级索引的levels是共享结构,修改后会篡改原有列的层级信息,导致结构混乱。正确的做法是重新构造均值列的三级索引,而非修改原索引的内部属性:

import pandas as pd
import numpy as np

df_f_avg = pd.DataFrame({
    ('a1c9', 'open',  'call'):    [3,      0.50,   3.0], 
    ('a1c9', 'close', 'call'):    [4,      0.35,   3.5], 
    ('a1c9', 'high',  'call'):    [1,      0.20,   1.5],
    ('a1c9', 'low',   'call'):    [2,      0.09,   2.5],
    ('a1p9', 'open',  'put'):     [5,      0.05,   4.0], 
    ('a1p9', 'close', 'put'):     [6,      0.10,   5.5], 
    ('a1p9', 'high',  'put'):     [7,      0.20,   6.0],
    ('a1p9', 'low',   'put'):     [8,      0.31,   7.0]})
df_f_avg.columns.names = ['Ticker', 'Price', 'Type']

# 按Ticker分组计算均值
avg_data = df_f_avg.groupby(level='Ticker', axis=1).mean()

# 为均值列构造正确的三级列索引
new_columns = []
for ticker in avg_data.columns:
    # 获取当前Ticker对应的期权类型(符合期权数据中一个Ticker对应单一Type的逻辑)
    ticker_type = df_f_avg.columns[df_f_avg.columns.get_level_values('Ticker') == ticker][0][2]
    new_columns.append( (ticker, 'avg', ticker_type) )

avg_data.columns = pd.MultiIndex.from_tuples(new_columns, names=['Ticker', 'Price', 'Type'])

# 合并并按索引排序,保证结构规整
df_f_avg = pd.concat([df_f_avg, avg_data], axis=1).sort_index(axis=1)
print(df_f_avg)

这段代码会生成符合预期的列结构,原有列的层级不会被破坏,同时新增的均值列会正确匹配('Ticker', 'avg', 'Type')的结构。

2. 更简洁高效的实现方式

利用pandas内置的多级索引操作和分组方法,可以大幅简化代码,同时保证性能和通用性:

方法一:结合stack/unstack的通用写法

import pandas as pd
import numpy as np

df_f_avg = pd.DataFrame({
    ('a1c9', 'open',  'call'):    [3,      0.50,   3.0], 
    ('a1c9', 'close', 'call'):    [4,      0.35,   3.5], 
    ('a1c9', 'high',  'call'):    [1,      0.20,   1.5],
    ('a1c9', 'low',   'call'):    [2,      0.09,   2.5],
    ('a1p9', 'open',  'put'):     [5,      0.05,   4.0], 
    ('a1p9', 'close', 'put'):     [6,      0.10,   5.5], 
    ('a1p9', 'high',  'put'):     [7,      0.20,   6.0],
    ('a1p9', 'low',   'put'):     [8,      0.31,   7.0]})
df_f_avg.columns.names = ['Ticker', 'Price', 'Type']

# 堆叠Price层级后分组计算均值,再重新展开为三级索引
avg_df = (df_f_avg.stack(['Price'])
          .groupby(['Ticker', 'Type'])
          .mean()
          .unstack(['Ticker', 'Type'])
          .rename(columns={'0': 'avg'})
          .swaplevel(0,1,axis=1)
          .swaplevel(1,2,axis=1))
avg_df.columns.names = ['Ticker', 'Price', 'Type']

# 合并并排序
df_f_avg = pd.concat([df_f_avg, avg_df], axis=1).sort_index(axis=1)
print(df_f_avg)

方法二:transform一行式实现

# 直接为每个Ticker计算均值并添加为新列
df_f_avg = df_f_avg.join(
    df_f_avg.groupby(level='Ticker', axis=1)
            .transform('mean')
            .rename(columns=lambda x: (x, 'avg', df_f_avg.columns[df_f_avg.columns.get_level_values('Ticker')==x][0][2]))
).sort_index(axis=1)

优势说明:

  • 可靠性:完全使用pandas官方API操作,避免修改索引内部属性导致的未知问题
  • 通用性:支持任意数量的Ticker,无需手动遍历或硬编码
  • 高效性:利用pandas内置的向量化操作,比手动构造DataFrame性能更高,适合大数据量场景

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.18 02:34:52