本文介绍在使用 pd.concat 合并多个 MultiIndex DataFrame 时,如何确保结果中列的第一级索引(如 'y1', 'y2', 'y11')严格按原始定义顺序排列,而非默认的字典序,从而避免因字符串排序导致的逻辑错位。
本文介绍在使用 `pd.concat` 合并多个 multiindex dataframe 时,如何确保结果中列的第一级索引(如 'y1', 'y2', 'y11')严格按原始定义顺序排列,而非默认的字典序,从而避免因字符串排序导致的逻辑错位。
在处理具有多级列索引(MultiIndex columns)的 pandas DataFrame 时,直接使用 pd.concat(..., axis=1).sort_index(axis=1) 往往会触发全层级字典序排序——这会导致第一级列名(如 'y1', 'y2', 'y11')被错误地重排为 'y1', 'y11', 'y2'(因为 'y11' < 'y2' 字符串比较成立),破坏业务语义中的逻辑顺序(例如按指标出现顺序或实验组编号排列)。
正确做法是:先按第一级索引(level=0)局部排序,再依据原始顺序(或自然序)重排列位置。以下是推荐的三种实现方式:
✅ 方法一:复用原始 DataFrame 的列一级顺序(最简洁、推荐)
out = (
pd.concat([df1, df2], axis=1)
.sort_index(axis=1, level=0) # 先按 level-0 分组内排序(保证 y1 下的 (0),(1) 相邻)
[df1.columns.get_level_values(0)] # 再按 df1 中第一级出现顺序重排所有列
)该方法假设 df1 的列顺序即为目标顺序,无需额外依赖,性能好且语义清晰。
✅ 方法二:强制自然排序(适用于无参考 DataFrame 场景)
当无法依赖 df1 的原始顺序(如需全局自定义顺序),可借助 natsort 实现数字感知的自然排序:
from natsort import natsorted
first_level = df1.columns.get_level_values(0)
out = (
pd.concat([df1, df2], axis=1)
.sort_index(axis=1, level=0)
[natsorted(first_level)]
)natsorted(['y1', 'y11', 'y2']) 返回 ['y1', 'y2', 'y11'],符合数值直觉。
✅ 方法三:基于索引的自然排序(更灵活的链式写法)
from natsort import index_natsorted out = pd.concat([df1, df2], axis=1) out = out.iloc[:, index_natsorted(out.columns, key=lambda x: x.get_level_values(0))]
此写法直接对拼接后的完整列 MultiIndex 进行自然序索引,兼容任意复杂层级结构。
⚠️ 注意事项:
- 避免仅用 .sort_index(axis=1) —— 它会对所有层级联合字典排序,导致 ('y11','0') 排在 ('y2','0') 前;
- sort_index(..., level=0) 仅按第一级分组,组内列顺序由输入顺序保留(df1 在前则 (col, '0') 在 (col, '1') 前);
- 若 df1 和 df2 第一级列名不完全一致,建议先对齐(如用 reindex 或 intersection)再拼接,防止列缺失或错位。
最终输出将严格遵循 y1 → y2 → y11 的第一级顺序,且每组内自动按第二级(如 '0', '1')升序排列,完美匹配预期结构。

















