Python pandas如何按ID将多行数据转换为单行多列宽表
问题说明
现有按ID维度存储的动态格式DataFrame,样例数据集df1结构如下:
df1: ID |Start Date|End date |claim_no|claim_type|Admission_date|Discharge_date|Claim_amt|Approved_amt 10 |01-Apr-20 |31-Mar-21| 1123 |CSHLESS | 23-Aug-2020 | 25-Aug-2020 | 25406 | 19351 10 |01-Apr-20 |31-Mar-21| 1212 |POSTHOSP | 30-Aug-2020 | 01-Sep-2020 | 4209 | 3964 10 |01-Apr-20 |31-Mar-21| 1680 |CSHLESS | 18-Mar-2021 | 23-Mar-2021 | 18002 | 0 11 |12-Dec-20 |11-Dec-21| 1503 |CSHLESS | 12-Jan-2021 | 15-Jan-2021 | 76137 | 50286 11 |12-Dec-20 |11-Dec-21| 1505 |CSHLESS | 05-Jan-2021 | 07-Jan-2021 | 30000 | 0
字段属性说明:
- 静态列(每个ID取值固定):
ID、Start Date、End date - 动态列(每个ID对应多条记录):
claim_no、claim_type、Admission_date、Discharge_date、Claim_amt、Approved_amt
需求为基于ID列将所有动态字段转换为静态格式,实现每个ID仅对应单行数据,预期输出格式如下:
ID |Start Date|End date |claim_no_1|claim_type_1|Admission_date_1|Discharge_date_1|Claim_amt_1|Approved_amt_1|claim_no_2|claim_type_2|Admission_date_2|Discharge_date_2|Claim_amt_2|Approved_amt_2|claim_no_3|claim_type_3|Admission_date_3|Discharge_date_3|Claim_amt_3|Approved_amt_3 10 |01-Apr-20 |31-Mar-21| 1123 |CSHLESS | 23-Aug-2020 | 25-Aug-2020 | 25406 | 19351 | 1212 |POSTHOSP | 30-Aug-2020 | 01-Sep-2020 | 4209 | 3964 | 1680 |CSHLESS | 18-Mar-2021 | 23-Mar-2021 | 18002 | 0 11 |12-Dec-20 |11-Dec-21| 1503 |CSHLESS | 12-Jan-2021 | 15-Jan-2021 | 76137 | 50286 | 1505 |CSHLESS |05-Jan-2021 |07-Jan-2021 |30000 |0
此前尝试使用如下代码实现:
df1_updated = pd.get_dummies(df1,columns = ['claim_no','claim_type','Admission_date','Discharge_date','Claim_amt','Approved_amt'])
该方案的问题是会生成数量极多的独热编码列,数据可读性极差,无法满足预期输出要求。
实现方案
pd.get_dummies的作用是生成独热编码列,完全不适配当前行转列的需求,正确实现步骤如下:
- 按ID分组,为每个ID下的多条动态记录生成从1开始的递增序号,作为后续展开列的后缀
import pandas as pd # 生成组内记录序号 df1['seq'] = df1.groupby('ID').cumcount() + 1 - 提取静态列数据,每个ID仅保留1条去重后的记录
static_cols = ['ID', 'Start Date', 'End date'] df_static = df1[static_cols].drop_duplicates(subset='ID') - 以ID为行维度、序号为列维度,将所有动态列展开为宽表,并重命名列名匹配
原列名_序号的格式dynamic_cols = ['claim_no','claim_type','Admission_date','Discharge_date','Claim_amt','Approved_amt'] df_dynamic = df1.pivot(index='ID', columns='seq', values=dynamic_cols) # 重命名列 df_dynamic.columns = [f'{col}_{seq}' for col, seq in df_dynamic.columns] df_dynamic = df_dynamic.reset_index() - 将静态表和展开后的动态表按ID关联,即可得到每个ID对应单行的目标结果
df_result = pd.merge(df_static, df_dynamic, on='ID', how='left')
说明:如果不同ID对应的动态记录条数不一致,展开后缺失的记录位置会自动填充空值,列数由全量数据中单个ID对应的最多动态记录数决定,不会生成冗余列,可读性完全符合要求。
内容的提问来源于stack exchange,提问作者tamil selvi
相关产品推荐
相关产品推荐

