如何按唯一ID转置DataFrame行?Python Pandas数据重构求助
Pandas DataFrame重构问题解决方案
首先先还原你的原始DataFrame(方便后续测试):
import pandas as pd df = pd.DataFrame({ 'Name': ['John', 'John', 'John', 'Amanda', 'Amanda', 'Amanda'], 'ID': ['BE2', 'BE1', 'DE1', 'BE2', 'BE1', 'DE1'], 'Birth_date': ['18/05/2011 06:45', '18/05/2011 06:55', '18/05/2011 03:11', '18/05/2011 04:44', '18/05/2011 06:08', '18/05/2011 12:08'], 'Age': [22, 21, 42, 35, 25, 36] })
你想要的目标格式是把每个用户的生日和年龄分别占一行,ID作为列。之前用set_index('ID').T的方法会把所有字段都转置,所以才会出现重复的ID列,显然不是我们要的效果。
这里给你两种简单高效的实现方法:
方法一:拆分+合并法
这种方法逻辑很直观,先分别处理生日和年龄的宽表,再把它们堆叠起来:
# 1. 分别生成生日和年龄的宽表(ID转成列) birth_df = df.pivot(index='Name', columns='ID', values='Birth_date').reset_index() age_df = df.pivot(index='Name', columns='ID', values='Age').reset_index() # 2. 给两个表添加标识,区分是用户行还是年龄行 birth_df['row_label'] = birth_df['Name'] age_df['row_label'] = 'Age' # 3. 合并两个表,调整列顺序和索引 result = pd.concat([birth_df, age_df], ignore_index=True) # 重新设置列名和索引 result = result.set_index('row_label').rename_axis(None).reset_index() result.columns = ['Name'] + list(birth_df.columns[1:-1]) print(result)
运行后就能得到你想要的结果:
Name BE2 BE1 DE1 0 John 18/05/2011 06:45 18/05/2011 06:55 18/05/2011 03:11 1 Age 22 21 42 2 Amanda 18/05/2011 04:44 18/05/2011 06:08 18/05/2011 12:08 3 Age 35 25 36
方法二:长表转宽表法
如果数据更复杂,这种用melt+pivot_table的组合会更灵活:
# 1. 把原始数据转成"长格式",将Birth_date和Age合并成一个字段 df_melted = df.melt(id_vars=['Name', 'ID'], var_name='data_type', value_name='value') # 2. 转成宽格式,用Name和data_type作为行索引,ID作为列 pivot_result = df_melted.pivot_table( index=['Name', 'data_type'], columns='ID', values='value', aggfunc='first' ).reset_index() # 3. 调整第一列的显示,把Birth_date对应的行显示用户名,Age对应的行显示'Age' pivot_result['Name'] = pivot_result.apply( lambda x: x['Name'] if x['data_type'] == 'Birth_date' else 'Age', axis=1 ) # 去掉多余的data_type列,重置索引 final_result = pivot_result.drop('data_type', axis=1).reset_index(drop=True) print(final_result)
这个方法同样能得到和目标一致的输出,而且如果后续有更多类似Birth_date、Age的字段,只需要调整melt的参数就能轻松扩展。
内容的提问来源于stack exchange,提问作者Christian
相关产品推荐
相关产品推荐

