如何在Pandas DataFrame中拆分多组男女年度列对为长格式
解决Pandas宽格式转长格式的问题
需求回顾
你有一个包含id、company name、company type列,以及Year 1 Males Total、Year 1 Females Total、Year 2 Males Total、Year 2 Females Total等列的DataFrame,需要将其转换为长格式:
- 保留
id、company name、company type和各年份列(如Year 1、Year 2) - 新增
Gender列,原数据每行拆分为两行(分别对应男性、女性)
原代码问题分析
你之前的代码用pd.concat(axis=1)拼接原数据和melt结果,核心问题是:melt后的数据行数是原数据的2倍(每行拆成男女两行),但原df_copy的行数和原数据一致,拼接后行数不匹配,导致大量NaN值。同时循环处理每个年份的方式会让数据结构混乱,效率也低。
正确实现方法
这里推荐两种简洁的实现方式:
方法一:先melt再拆分+ pivot
import pandas as pd # 假设原始DataFrame名为df # 1. 将所有年份性别列转为长格式 df_melted = df.melt( id_vars=['id', 'company name', 'company type'], var_name='Year_Gender', value_name='Total' ) # 2. 拆分Year_Gender列,提取年份和性别 df_melted[['Year', 'Gender', '_']] = df_melted['Year_Gender'].str.split(' ', n=2, expand=True) # 移除不需要的列 df_melted.drop(columns=['Year_Gender', '_'], inplace=True) # 3. 将年份转为列,恢复宽格式的年份列,同时保留Gender列 df_final = df_melted.pivot_table( index=['id', 'company name', 'company type', 'Gender'], columns='Year', values='Total', aggfunc='first' ).reset_index()
方法二:使用pd.wide_to_long
import pandas as pd # 1. 重命名列,适配wide_to_long的格式要求 df_renamed = df.rename( columns=lambda x: x.replace(' Year ', '_') .replace(' Males Total', '_Males') .replace(' Females Total', '_Females') ) # 2. 使用wide_to_long拆分数据 df_long = pd.wide_to_long( df_renamed, stubnames=['Year_'], i=['id', 'company name', 'company type'], j=['Year', 'Gender'], sep='_', suffix=r'\d+' ).reset_index() # 3. 调整年份列格式,并转成需求的结构 df_long['Year'] = 'Year ' + df_long['Year'].astype(str) df_final = df_long.pivot( index=['id', 'company name', 'company type', 'Gender'], columns='Year', values='Year_' ).reset_index()
两种方法最终都会得到符合需求的DataFrame:每行对应一个公司+性别组合,保留所有年份列的数值,新增Gender列标记男/女。
内容的提问来源于stack exchange,提问作者Chris White
相关产品推荐
相关产品推荐

