
当拼接具有相同层级名称但顺序不同的 MultiIndex DataFrame 时,pandas 默认会丢失部分索引名称;需先统一索引层级顺序(如用 reorder_levels),再执行 pd.concat,才能保留完整、一致的多级索引结构。
当拼接具有相同层级名称但顺序不同的 multiindex dataframe 时,pandas 默认会丢失部分索引名称;需先统一索引层级顺序(如用 `reorder_levels`),再执行 `pd.concat`,才能保留完整、一致的多级索引结构。
在使用 pd.concat() 合并多个多级索引(MultiIndex)DataFrame 时,一个常见陷阱是:即使各 DataFrame 的索引层级名称(names)完全相同,若层级顺序不一致,pandas 将无法自动对齐,导致拼接后索引名称丢失(显示为 None),甚至引发意外的数据错位或层级塌缩。
例如,df 的索引层级为 ['a', 'b', 'c'],而 df2 的索引层级为 ['a', 'c', 'b'] —— 表面看只是 'b' 和 'c' 位置互换,但 pd.concat([df, df2]) 会将结果索引降级为仅保留首个层级名 'a',其余两级变为 None,最终得到 FrozenList(['a', None, None])。这是因为 pandas 在拼接时严格按层级位置(level position)而非层级名称(level name)进行对齐;名称相同但顺序不同,即视为“结构不兼容”。
✅ 正确做法是:在拼接前,显式将所有待合并 DataFrame 的索引层级重排为与基准 DataFrame 一致的顺序。推荐以第一个 DataFrame 的 index.names 为标准模板:
import pandas as pd # 构造示例数据 idx1 = pd.MultiIndex.from_product([['A1','A2','A3'], ['B1','B2','B3'], ['C1','C2','C3']], names=['a','b','c']) df = pd.DataFrame(1, idx1, columns=['2010', '2020']) idx2 = pd.MultiIndex.from_product([['A1','A2','A3'], ['C1','C2','C3'], ['B1','B2','B3']], names=['a','c','b']) df2 = pd.DataFrame(2, idx2, columns=['2010', '2020']) # ✅ 关键步骤:重排 df2 的索引层级,使其与 df 一致 result = pd.concat([df, df2.reorder_levels(df.index.names)]) print(result.index.names) # 输出:FrozenList(['a', 'b', 'c'])
对于多个 DataFrame(如 df, df2, df3, df4),可采用列表推导式批量标准化:
dfs = [df, df2, df3, df4] standard_names = dfs[0].index.names aligned_dfs = [d.reorder_levels(standard_names) for d in dfs] result = pd.concat(aligned_dfs)
⚠️ 注意事项:
- reorder_levels() 不修改原 DataFrame,返回新对象,因此需显式赋值或链式调用;
- 若某 DataFrame 缺失某个层级名(如 names=[None, 'b', 'c']),需先用 rename_axis() 补全,否则 reorder_levels 可能报错;
- 拼接后建议校验索引完整性:result.index.is_monotonic_increasing(可选)及 result.index.names 是否符合预期;
- 如需后续按层级分组或透视,统一的层级顺序是前提,否则 groupby(level='b') 等操作可能失效。
通过主动对齐索引层级顺序,而非依赖 pandas 自动推断,可确保多级索引语义清晰、结构稳定,是处理复杂层级数据拼接的稳健实践。

















