pandas.melt() 是宽转长最直接方法,需明确指定 id_vars 和 value_vars,显式命名 var_name/value_name;多级列用 stack() 更稳妥;大宽表慎用 melt(),注意空值与重复索引问题。

用 pandas.melt() 处理基础宽转长
宽表转长表最直接的方式就是 pandas.melt(),它适合字段明确、标识列(如 id、date)和变量列(如 Jan、Feb)界限清晰的场景。
常见错误是漏设 id_vars 或误把所有列当变量处理,导致结果多出一列冗余 variable 值,或丢失关键标识信息。
-
id_vars必须指定不变的标识列,比如['country', 'year'];不填会默认把除value_vars外所有列都当作id_vars,容易出错 -
value_vars显式列出要“融化”的列(如['Q1', 'Q2', 'Q3', 'Q4']),不指定则默认取其余所有列,但列顺序可能打乱 -
var_name和value_name推荐显式命名,避免默认的variable/value造成后续处理歧义
示例:
df_long = df.melt(id_vars=['region'], value_vars=['2021', '2022', '2023'], var_name='year', value_name='sales')
遇到多级列名时用 stack() 更稳妥
当宽表有 MultiIndex 列(比如分产品线+季度的嵌套列),melt() 无法直接处理,强行 flatten 列名易出错或丢失层级语义。
立即学习“Python免费学习笔记(深入)”;
此时 stack() 是更自然的选择:它按层级折叠列,自动保留索引结构,且返回 Series 后可轻松转回 DataFrame。
- 先用
set_index()把标识列设为索引,再stack(),否则层级会被压扁成字符串 -
stack()默认只压一层,多级列需传入level参数,比如stack([0, 1])表示压平前两级 - 结果带
MultiIndex,调用reset_index(name='value')可还原为规整长表,name指定新值列名
示例:
df_long = df.set_index(['product']).stack([0, 1]).reset_index(name='amount')
性能敏感场景慎用 melt() 大宽表
对列数超 500 的宽表(比如传感器每秒采样存一列),melt() 内部会构造大量中间对象,内存占用陡增,速度明显变慢。
这不是 bug,而是其设计基于通用性而非极端宽度优化。实际中更推荐分块处理或改用 numpy 手动 reshape + pd.DataFrame 构造。
- 列太多时,先用
df.columns.tolist()确认哪些列真要融,避免无谓膨胀 - 若仅需部分年份/指标,用
value_vars显式限定范围,比全量 melt 后再query()高效得多 - 极端情况(千万级列)应考虑是否数据建模本身有问题——宽表本就不该这么宽
别忽略空值和重复索引带来的副作用
melt() 和 stack() 都不会主动 drop 空值,但长表里出现大量 NaN 会让下游聚合或绘图异常;更隐蔽的是,原始宽表若存在重复索引,stack() 后会保留重复,而 melt() 不受影响。
- 转换后建议立刻检查
df_long['value'].isna().sum(),决定是否dropna() - 若原始表有重复
index,用stack()前先df = df.reset_index(drop=True)或去重 -
melt()对索引无感,但若你依赖索引做后续 merge,记得转换后重设有意义的索引
真正麻烦的不是语法,而是宽表本身常混杂业务逻辑(比如某些列为计算字段、某些列仅部分行有效),这些必须在 melt 前人工厘清,工具不会替你判断哪列该融、哪列该删。


















