如何将按年份分多列的Pandas DataFrame转换为含年份列与值列的单列结构?
最优方法转换宽格式DataFrame为长格式
看起来你可能在表述期望输出时有点小混淆——重复的列名(a、b、c、d重复两次)在Pandas DataFrame里是不推荐的,而且结合你提到的年份列和值列的需求,你真正想要的应该是一个长格式的DataFrame,每行对应一个「类别(a/b/c/d)-年份」的组合,包含年份、类别、值三个列。
先明确你的输入DataFrame结构,应该是这样的:
import pandas as pd # 输入的宽格式DataFrame df_wide = pd.DataFrame({ '年份': [2015, 2016], 'a': [1, 5], 'b': [2, 6], 'c': [3, 7], 'd': [4, 8] })
下面两种方法都是比for循环高效得多的矢量化操作,完全满足你的需求:
方法1:用melt函数(直观易读)
melt是Pandas专门为宽转长设计的函数,只需要指定作为标识符的列(这里是年份),然后把其他列转成「变量-值」对:
df_long = df_wide.melt( id_vars='年份', # 保留作为标识符的列 var_name='类别', # 原列名(a/b/c/d)对应的新列名 value_name='值' # 原列值对应的新列名 ) # 按年份排序,匹配你要的输出顺序(2015的a-d在前,2016在后) df_long = df_long.sort_values('年份').reset_index(drop=True)
最终输出的df_long就是:
| 年份 | 类别 | 值 | |
|---|---|---|---|
| 0 | 2015 | a | 1 |
| 1 | 2015 | b | 2 |
| 2 | 2015 | c | 3 |
| 3 | 2015 | d | 4 |
| 4 | 2016 | a | 5 |
| 5 | 2016 | b | 6 |
| 6 | 2016 | c | 7 |
| 7 | 2016 | d | 8 |
方法2:用stack方法(性能更优)
如果把年份设为索引,stack可以快速把列转成行,适合处理大数据集:
# 先将年份设为索引 df_indexed = df_wide.set_index('年份') # stack转长格式,然后重置索引并命名列 df_long = df_indexed.stack().reset_index() df_long.columns = ['年份', '类别', '值'] # 同样按年份排序 df_long = df_long.sort_values('年份').reset_index(drop=True)
为什么这两种方法比for循环好?
- 性能更高:Pandas的
melt和stack都是底层用C实现的矢量化操作,避免了Python层面的循环开销,数据量越大,优势越明显。 - 代码更简洁:一行/几行代码就能完成转换,可读性和可维护性远高于for循环。
- 更符合Pandas idiom:这是Pandas处理宽转长场景的标准做法,团队里其他熟悉Pandas的开发者一眼就能看懂。
如果你之前用melt没得到预期结果,大概率是没正确设置参数或者没做排序调整,按上面的代码应该就能解决问题。
内容的提问来源于stack exchange,提问作者Enrique Ortiz de Zárate
相关产品推荐
相关产品推荐

