如何将含季度层级列的Pandas MultiIndex DataFrame转长格式?
解决Pandas MultiIndex宽表转长表(季度列转行)问题
这问题我熟!要把这种带MultiIndex列的宽格式DataFrame转成季度在行里的长格式,用Pandas的stack或者melt+pivot都能搞定,咱们先从你的示例数据入手一步步演示。
第一步:先还原你的示例数据
首先把你提供的代码调整一下(修正转义字符让显示更正常):
import pandas as pd # 构建MultiIndex列 cols = pd.MultiIndex(levels=[['Center_Details', '2017-18:Q2', '2017-18:Q1'], ['State', 'District', 'Center', 'Offices', 'Deposit', 'Credit']], codes=[[0, 0, 0, 1, 1, 1, 2, 2, 2], [0, 1, 2, 3, 4, 5, 3, 4, 5]]) # 修正数据里的转义字符 data = [['JAMMU & KASHMIR', 'KUPWARA', 'Drug Mulla (CT)', '3', '500', '600', '4', '500', '600'], ['JAMMU & KASHMIR', 'LEH LADAKH', 'Chuglamsar (CT)', '3', '500', '600', '4', '500', '600'], ['PUNJAB', 'PATHANKOT', 'Mamun (CT)', '3', '500', '600', '4', '500', '600'], ['PUNJAB', 'GURDASPUR', 'TIBRI', '3', '500', '600', '4', '500', '600']] df = pd.DataFrame(data=data, columns=cols)
运行后原始DataFrame的结构是这样的:
Center_Details 2017-18:Q2 2017-18:Q1 State District Center Offices Deposit Credit Offices Deposit Credit 0 JAMMU & KASHMIR KUPWARA Drug Mulla (CT) 3 500 600 4 500 600 1 JAMMU & KASHMIR LEH LADAKH Chuglamsar (CT) 3 500 600 4 500 600 2 PUNJAB PATHANKOT Mamun (CT) 3 500 600 4 500 600 3 PUNJAB GURDASPUR TIBRI 3 500 600 4 500 600
方法一:用stack(推荐,更简洁)
这个方法专门适配MultiIndex结构,步骤少逻辑清晰:
# 1. 把固定的中心信息列设置为索引 index_cols = [('Center_Details', 'State'), ('Center_Details', 'District'), ('Center_Details', 'Center')] df_indexed = df.set_index(index_cols) # 2. 把第一层级的季度列转成行(stack level=0) stacked_df = df_indexed.stack(level=0) # 3. 重置索引为普通列,并调整列名让它更直观 result = stacked_df.reset_index() result.columns = ['State', 'District', 'Center', 'Quarter', 'Offices', 'Deposit', 'Credit'] # 查看最终结果 print(result)
输出的长格式DataFrame就是你想要的:
State District Center Quarter Offices Deposit Credit 0 JAMMU & KASHMIR KUPWARA Drug Mulla (CT) 2017-18:Q2 3 500 600 1 JAMMU & KASHMIR KUPWARA Drug Mulla (CT) 2017-18:Q1 4 500 600 2 JAMMU & KASHMIR LEH LADAKH Chuglamsar (CT) 2017-18:Q2 3 500 600 3 JAMMU & KASHMIR LEH LADAKH Chuglamsar (CT) 2017-18:Q1 4 500 600 4 PUNJAB PATHANKOT Mamun (CT) 2017-18:Q2 3 500 600 5 PUNJAB PATHANKOT Mamun (CT) 2017-18:Q1 4 500 600 6 PUNJAB GURDASPUR TIBRI 2017-18:Q2 3 500 600 7 PUNJAB GURDASPUR TIBRI 2017-18:Q1 4 500 600
步骤解释:
set_index(index_cols):把不会变化的中心信息(State/District/Center)设为索引,后续只处理季度相关的列。stack(level=0):针对列的第一层级(季度名称)进行堆叠,把每个季度从列维度转成行维度,同时保留该季度对应的三个指标列。reset_index():把之前的索引还原成普通列,最后重命名列名让结构更清晰。
方法二:用melt+pivot(适合不熟悉stack/unstack的场景)
如果你对stack不太熟悉,也可以用扁平化列名+melt+pivot的组合:
# 1. 把MultiIndex列转换成普通字符串列名,用下划线连接两个层级 df.columns = ['_'.join(col) for col in df.columns] # 2. 用melt把所有季度相关的列转成长格式 id_vars = [col for col in df.columns if col.startswith('Center_Details_')] melted_df = df.melt(id_vars=id_vars, var_name='Quarter_Metric', value_name='Value') # 3. 拆分Quarter_Metric列,分离出季度和指标名称 melted_df[['Quarter', 'Metric']] = melted_df['Quarter_Metric'].str.split('_', n=1, expand=True) # 4. 用pivot把指标转回列,得到最终格式 result = melted_df.pivot(index=['Center_Details_State', 'Center_Details_District', 'Center_Details_Center', 'Quarter'], columns='Metric', values='Value').reset_index() # 重命名列 result.columns = ['State', 'District', 'Center', 'Quarter', 'Offices', 'Deposit', 'Credit'] print(result)
这个方法的思路是先把MultiIndex列扁平化,再把所有季度指标转成单行,拆分出季度和指标后,再把指标转回列维度,最终效果和方法一完全一致。
补充说明
这两种方法都能自动适配更多季度或更多指标的情况,不需要修改核心逻辑,直接套用即可。
内容的提问来源于stack exchange,提问作者mudassirkhan19
相关产品推荐
相关产品推荐

