如何用Pandas将长格式测试数据转为含对应测试日期的宽格式?
长格式测试数据转宽格式的高效实现方案
假设你的原始数据结构类似这样(需包含唯一标识列,比如样本ID,否则转宽后会丢失分组逻辑):
| 样本ID | 测试项 | 测试结果 | date_test |
|---|---|---|---|
| 1 | 血糖 | 5.6 | 2024-01-01 |
| 1 | 血压 | 120/80 | 2024-01-01 |
| 2 | 血糖 | 6.1 | 2024-01-02 |
| 2 | 血压 | 130/85 | 2024-01-02 |
目标是生成每个测试项对应的结果列和日期列,最终删除原date_test列。以下是几种高效实现方式:
方法1:优先用pivot(无重复分组时)
pivot比pivot_table更适合一对一的分组场景,不会默认执行聚合操作,能避免你之前可能遇到的输出不符合预期问题:
# 替换"样本ID"为你的数据中唯一标识每一行的字段 df_wide = df.pivot( index='样本ID', columns='测试项', values=['测试结果', 'date_test'] # 同时把结果和日期作为值列 ) # 把多层列索引合并为"测试项_字段名"的格式,比如"血糖_测试结果" df_wide.columns = ['_'.join(col[::-1]) for col in df_wide.columns] # 可选:把索引列(样本ID)转回普通列 df_wide = df_wide.reset_index() # 若原数据残留单独的date_test列,直接删除 df_wide = df_wide.drop(columns=['date_test'], errors='ignore')
方法2:用pivot_table(存在重复分组时)
如果你的数据中存在同一唯一标识+测试项的重复记录,需要指定聚合规则(比如取第一条、均值等):
df_wide = df.pivot_table( index='样本ID', columns='测试项', values=['测试结果', 'date_test'], aggfunc='first' # 按需求替换为'mean'/'max'等 ) # 同样处理列名 df_wide.columns = ['_'.join(col[::-1]) for col in df_wide.columns] df_wide = df_wide.reset_index().drop(columns=['date_test'], errors='ignore')
方法3:分组合并(自定义逻辑场景)
如果需要对不同测试项做个性化处理,可采用分组遍历合并的方式(效率略低于前两种,适合小数据集):
# 初始化宽表,保留唯一标识列 df_wide = df[['样本ID']].drop_duplicates().reset_index(drop=True) # 遍历每个测试项,生成对应列并合并 for test_item in df['测试项'].unique(): subset = df[df['测试项'] == test_item][['样本ID', '测试结果', 'date_test']] # 重命名列 subset = subset.rename( columns={ '测试结果': f'{test_item}_测试结果', 'date_test': f'{test_item}_date_test' } ) # 合并到宽表 df_wide = df_wide.merge(subset, on='样本ID', how='left') # 删除原date_test列 df_wide = df_wide.drop(columns=['date_test'], errors='ignore')
关键说明
- 不需要用lambda函数处理列名,列表推导式更简洁高效;
- 若之前用
pivot_table输出异常,大概率是因为默认聚合规则(均值)不符合你的预期,改用pivot或指定aggfunc即可解决; - 必须保证存在唯一标识列(如样本ID),否则转宽后数据会混乱。
内容的提问来源于stack exchange,提问作者Javier Alejandro Rendon Carril
相关产品推荐
相关产品推荐

