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

pandas按指定顺序访问MultiIndex列时出现列结构异常问题

Pandas MultiIndex列筛选后层级结构错乱问题

问题复现

首先构建带MultiIndex列的测试DataFrame:

import pandas as pd
import numpy as np

df = pd.DataFrame(np.random.randint(0,1000, (5,6)), \
                  columns = pd.MultiIndex.from_product([['CPC', 'Conversions'], ['April', 'June', 'May']])).rename_axis(index = {None : 'idx'})

df

DataFrame原始输出如下:

CPC                 Conversions          
      April June  May     April June  May
idx                                      
0     663  964  971      663   76  927
1     405  217  754      370  306   34
2     474  229  664      354   66  885
3      73  538  139      417  876  855
4     619  618  618      455  134  805

需求是按April、May、June的正确月份顺序排列二级列,执行如下筛选代码:

df.loc[:, (slice(None), ['April', 'May', 'June'])]

返回结果列排布异常,同月份下的CPC、Conversions列被拆分,未保留原有的第一层级分组结构,输出如下:

CPC Conversions   CPC Conversions   CPC Conversions
      April       April   May         May  June        June
idx                                                     
0      806         202   963         975   110          55
1      263         884   442         563   216         694
2      462         361   780         412   858         670
3      742         756   525          33   477         826
4      579         332    91         802   829         231

但如果仅选择2个月份执行相同逻辑,返回的列结构完全正常:

df.loc[:, (slice(None), ['April', 'May'])]

输出:

CPC      Conversions     
       April  May       April  May
idx                            
0       856  619         180  593
1        64  403         929   80
2       973  285         803  967
3       769  405         701  267
4       940  368         863  717

问题成因

这不是pandas的功能bug,是多级索引使用列表传入筛选条件时的固有匹配逻辑:当传入的二级筛选列表长度≥3、且顺序和原MultiIndex中二级值的存储顺序不一致时,pandas会直接按传入的列表值顺序逐一生成(一级索引值, 二级索引值)的索引对做匹配,不会优先保留原有一级索引的分组结构;而传入长度为2的列表时,会触发pandas内置的短列表匹配优化,自动保留原有层级顺序,才会出现选2个月正常、选3个月结构错乱的反差。

通用解决方法

不需要手动硬编码重建整个MultiIndex,以下两种方案都可以自动适配后续列层级的变动:

  • 方案1:筛选后按索引层级自定义排序
    先完成筛选,再给二级月份设置自定义有序类别,按一级索引、二级索引的优先级重排列即可:
    # 执行筛选
    res = df.loc[:, (slice(None), ['April', 'May', 'June'])]
    # 定义月份的正确顺序
    month_sort = pd.CategoricalDtype(categories=['April', 'May', 'June'], ordered=True)
    # 给二级列设置有序类别
    res.columns = res.columns.set_levels(
        [res.columns.levels[0], res.columns.levels[1].astype(month_sort)],
        level=[0, 1]
    )
    # 按层级优先级重排列
    res = res.sort_index(axis=1, level=[0, 1])
    
  • 方案2:用目标多级索引做列重索引
    直接基于原有列的一级索引值,和需要的二级顺序生成目标列结构,用reindex对齐即可,后续一级列新增、删除字段都不需要修改代码:
    # 生成保留原有一级分组、按指定顺序排列二级值的目标列
    target_cols = pd.MultiIndex.from_product([df.columns.levels[0], ['April', 'May', 'June']])
    res = df.reindex(columns=target_cols)
    

两种方案返回的结果都会保留原有的「一级指标分组在前,二级月份按自定义顺序排列」的结构,不需要硬编码全量列名,适配性更强。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 10:24:22