如何将pandas MultiIndex转换为带缩进的单列Index?
问题:将MultiIndex DataFrame转换为带缩进的单层索引格式
我有一个带pandas.MultiIndex的DataFrame:
Vals Fruits Apples a Banana b Vegetables Tomato c Onion d Potato e Foobar LoreIpsum f
想要转换成单层索引的形式,要求:
- 基于第一层级索引插入新行
- 第二层级索引值添加4个字符的缩进
目标效果如下:
Vals Fruits Apples a Banana b Vegetables Tomato c Onion d Potato e Foobar LoreIpsum f
最小可复现代码:
#!/usr/bin/env python3 import pandas as pd midx = pd.MultiIndex.from_tuples([ ('Fruits', 'Apples'), ('Fruits', 'Banana'), ('Vegetables', 'Tomato'), ('Vegetables', 'Onion'), ('Vegetables', 'Potato'), ('Foobar', 'LoreIpsum') ]) df = pd.DataFrame({'Vals': list('abcdef')}, index=midx) print(df.to_markdown()) exp_idx = pd.Index([ 'Fruits', ' Apples', ' Banana', 'Vegetables', ' Tomato', ' Onion', ' Potato', 'Foobar', ' LoreIpsum', ]) exp_df = pd.DataFrame({'Vals': list(' ab cde f')}, index=exp_idx) print(exp_df.to_markdown())
解决方案
可以通过重置索引、构造层级行、合并排序的方式实现,全程用pandas内置方法,避免手动循环:
import pandas as pd # 原始数据 midx = pd.MultiIndex.from_tuples([ ('Fruits', 'Apples'), ('Fruits', 'Banana'), ('Vegetables', 'Tomato'), ('Vegetables', 'Onion'), ('Vegetables', 'Potato'), ('Foobar', 'LoreIpsum') ]) df = pd.DataFrame({'Vals': list('abcdef')}, index=midx) # 1. 拆分MultiIndex为普通列 df_reset = df.reset_index(names=['Level1', 'Level2']) # 2. 构造第一层级的标题行(子项为空,值为空字符串) level1_rows = df_reset[['Level1']].drop_duplicates().assign(Level2=pd.NA, Vals='') # 3. 合并标题行与原始数据行,排序确保标题行在子项上方 combined = pd.concat([level1_rows, df_reset]).sort_values( by=['Level1', 'Level2'], na_position='first' ) # 4. 生成最终索引:标题行用Level1值,子项添加4空格缩进 final_index = combined.apply( lambda row: row['Level1'] if pd.isna(row['Level2']) else f' {row["Level2"]}', axis=1 ) # 5. 生成目标DataFrame result_df = combined.set_index(final_index)[['Vals']] # 输出结果 print(result_df.to_markdown())
步骤说明:
- 重置索引将多层索引转为普通列,简化后续处理
- 提取第一层级唯一值构造标题行,保证每个分类都有独立的标题行
- 合并后排序,让标题行自动排在对应子项的最上方
- 按规则生成单层索引,实现标题无缩进、子项4空格缩进的格式
- 重新设置索引后得到符合要求的DataFrame
内容的提问来源于stack exchange,提问作者buhtz
相关产品推荐
相关产品推荐

