如何为Pandas多层索引DataFrame新增表头层级并调整GM表头位置
Pandas多层索引表头调整问题
初始问题
我有如下Pandas DataFrame:
from collections import defaultdict import pandas as pd dic = {'US':{'Quality':{'points':"-2 n", 'difference':'equal', 'stat': 'same'}, 'Prices':{'points':"-7 n", 'difference':'negative', 'stat': 'below'}, 'Satisfaction':{'points':"3 n", 'difference':'positive', 'stat': 'below'}}, 'UK': {'Quality':{'points':"3 n", 'difference':'equal', 'stat': 'above'}, 'Prices':{'points':"-13 n", 'difference':'negative', 'stat': 'below'}, 'Satisfaction':{'points':"2 n", 'difference':'negative', 'stat': 'same'}}} d1 = defaultdict(dict) for k, v in dic.items(): for k1, v1 in v.items(): for k2, v2 in v1.items(): d1[(k, k2)].update({k1: v2}) df = pd.DataFrame(d1) df.columns = df.columns.rename("Skateboard", level=0) df.columns = df.columns.rename("Q3", level=1) df.insert(loc=0, column=('', 'Mode'), value="Website")
当前DataFrame样式:列层级为(Skateboard, Q3),首列是('', 'Mode'),内容为"Website",后续列按US、UK下的points/difference/stat展开。
需求:为多层索引DataFrame新增一层表头,使GM作为顶层表头对应points列,其余列对应空顶层表头,且GM表头位于US、UK列组的最前方(每个国家列组的第一部分是GM对应的points列,之后是其余指标列)。
更新后的尝试
我尝试了以下代码:
from collections import defaultdict import pandas as pd dic = {'US':{'Quality':{'points':"-2 n", 'difference':'equal', 'stat': 'same'}, 'Prices':{'points':"-7 n", 'difference':'negative', 'stat': 'below'}, 'Satisfaction':{'points':"3 n", 'difference':'positive', 'stat': 'below'}}, 'UK': {'Quality':{'points':"3 n", 'difference':'equal', 'stat': 'above'}, 'Prices':{'points':"-13 n", 'difference':'negative', 'stat': 'below'}, 'Satisfaction':{'points':"2 n", 'difference':'negative', 'stat': 'same'}}} d1 = defaultdict(dict) for k, v in dic.items(): for k1, v1 in v.items(): for k2, v2 in v1.items(): d1[(k, k2)].update({k1: v2}) df = pd.DataFrame(d1) df.columns = df.columns.rename("Skateboard", level=0) df.columns = df.columns.rename("Metric", level=1) df1 = df.xs('points', axis=1, level=1, drop_level=False) df2 = df.drop('points', axis=1, level=1) df3 = (pd.concat([df1, df2], keys=['GM', ''], axis=1) .swaplevel(0, 1, axis=1) .sort_index(axis=1)) df3.columns = df3.columns.rename("Q3", level=1) df3.insert(loc=0, column=('','', 'Mode'), value="Website") df3
当前DataFrame样式:顶层表头GM和空值被分散在各国家列组中,而非每个国家列组的最前方。
问题:如何将GM表头移动到US和UK列组的最前面,达到目标样式?
解决方案
方法1:调整排序层级优先级
在生成拼接后的DataFrame时,修改排序逻辑,让国家(Skateboard)优先,再按顶层表头(GM优先)排序,最后按指标列排序:
# 重新生成df3并调整排序 df3 = (pd.concat([df1, df2], keys=['GM', ''], axis=1) .swaplevel(0, 1, axis=1) # 指定排序层级顺序:先国家,再顶层表头(GM在前),最后指标 .sort_index(axis=1, level=['Skateboard', 0, 'Metric'])) # 重命名列层级 df3.columns = df3.columns.rename(["Skateboard", "TopHeader", "Metric"]) # 插入Mode列 df3.insert(loc=0, column=('', '', 'Mode'), value="Website")
方法2:按国家分组重组列
手动为每个国家组拼接GM列和其余列,确保GM列在每个国家组的最前方:
# 按国家分组处理列 country_groups = [] for country in ['US', 'UK']: # 提取当前国家的GM对应列(points) gm_cols = df.xs((country, 'points'), axis=1, level=[0,1], drop_level=False) # 提取当前国家的非GM列 other_cols = df.xs(country, axis=1, level=0).drop('points', axis=1) # 为GM列添加顶层表头标识,其余列添加空表头 gm_cols.columns = pd.MultiIndex.from_tuples([('GM', country, 'points')], names=['TopHeader', 'Skateboard', 'Metric']) other_cols.columns = pd.MultiIndex.from_tuples([('', country, col) for col in other_cols.columns], names=['TopHeader', 'Skateboard', 'Metric']) # 拼接当前国家的GM列和其余列 country_groups.append(pd.concat([gm_cols, other_cols], axis=1)) # 拼接所有国家组,插入Mode列 df_final = pd.concat(country_groups, axis=1) df_final.insert(loc=0, column=('', '', 'Mode'), value="Website")
两种方法都能实现每个国家列组最前方展示GM对应的points列,后续排列其余指标列的目标样式。
内容的提问来源于stack exchange,提问作者M J
相关产品推荐
相关产品推荐

