如何重塑Pandas DataFrame,将多列转换为以time为列的宽表?
解决思路与代码实现
看起来你需要的是先将宽表转成长表,再将长表 pivot 成指定的宽表格式——你的尝试方向是对的,但melt的参数设置有误,导致没能得到预期结果。我们一步步来解决:
1. 先明确数据结构
首先,先把你的原始数据构建成可复现的DataFrame:
import pandas as pd data = [ [2960, 32863, 2086, 'CFA Ahmedabad', 29903, 1, 90], [2960, 32863, 2087, 'CFA Ahmedabad', 29903, 1, 90], [8090, 71453, 2086, 'CFA Bangalore', 79543, 2, 90], [8090, 71453, 2087, 'CFA Bangalore', 79543, 2, 90] ] df = pd.DataFrame(data, columns=['Error', 'Fore', 'time', 'loc', 'qty', 'con', 'FA'])
2. 第一步:用melt转成长表
你之前的错误是只把loc作为id_vars,但**time也是需要保留的分组维度**,应该把它和loc一起放进id_vars里,同时把其他需要转成变量的列(Error、Fore、qty等)作为转换对象:
# 将除loc、time外的所有列转为「变量-值」对 melted_df = df.melt(id_vars=['loc', 'time'], var_name='var', value_name='value')
这时候得到的长表结构是:
| loc | time | var | value |
|---|---|---|---|
| CFA Ahmedabad | 2086 | Error | 2960 |
| CFA Ahmedabad | 2087 | Error | 2960 |
| CFA Ahmedabad | 2086 | Fore | 32863 |
| ... | ... | ... | ... |
3. 第二步:用pivot转成目标格式
接下来,我们把time转成列,loc和var作为行索引,最后重置索引并调整格式:
# pivot:将time转为列,loc+var作为行,value填充对应单元格 result = melted_df.pivot(index=['loc', 'var'], columns='time', values='value').reset_index() # 去掉列索引的默认名称(我们不需要显示'time') result.columns.name = None
4. 可选:调整变量顺序匹配目标
如果需要让var的顺序和你给出的示例完全一致(qty→Fore→Error→con→FA),可以手动指定排序顺序:
# 定义想要的变量顺序 var_order = ['qty', 'Fore', 'Error', 'con', 'FA'] # 将var转为分类类型,指定顺序后排序 result['var'] = pd.Categorical(result['var'], categories=var_order, ordered=True) result = result.sort_values(['loc', 'var']).reset_index(drop=True)
最终得到的结果就完全符合你的需求了:
| loc | var | 2086 | 20877 |
|---|---|---|---|
| CFA Ahmedabad | qty | 29903 | 29903 |
| CFA Ahmedabad | Fore | 32863 | 32863 |
| CFA Ahmedabad | Error | 2960 | 2960 |
| CFA Ahmedabad | con | 1 | 1 |
| CFA Ahmedabad | FA | 90 | 90 |
| CFA Bangalore | qty | 79543 | 79543 |
| ... | ... | ... | ... |
为什么你的原代码没生效?
你之前的代码df = pd.melt(df, id_vars='loc', value_vars=var, value_name='time')有两个核心问题:
- 没有把
time加入id_vars,导致丢失了时间维度与其他字段的关联; - 把
value_name设为time,完全搞反了逻辑——time是原数据中的一个维度列,应该作为分组依据,而不是值的名称。
内容的提问来源于stack exchange,提问作者nick
相关产品推荐
相关产品推荐

