You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用Pandas高效实现多列动态的DataFrame重塑?

高效实现Pandas数据重塑(替代循环方案)

嘿,我明白你想摆脱逐行循环来高效完成数据重塑的需求——确实,原生Pandas的向量化方法比iterrows()循环快太多了,尤其是数据量大的时候。你提到的pivot思路方向有点偏,因为pivot是用来长表转宽表的,而你需要的是宽表转长表,所以应该用melt、wide_to_long这类专门的工具。下面给你几个可行的高效方案:

先看原始数据

首先我们再确认下输入的DataFrame:

import pandas as pd
df = pd.DataFrame({
    'level1':['a', 'a'], 
    'level2':['b', 'b'], 
    'level3':[100, 101], 
    'id1':[111,222],
    'id2':[333,444], 
    'foo_value':[0.1,0.2], 
    'bar_value':[0.3,0.4]
})

方案一:两步melt(最直观高效)

这个方法分两步把宽表转成目标长表,完全避免循环:

# 第一步:把id1、id2展开成单独的id列
id_melted = df.melt(
    id_vars=['level1', 'level2', 'level3', 'foo_value', 'bar_value'],
    value_vars=['id1', 'id2'],
    value_name='id'  # 指定新列名
).drop('variable', axis=1)  # 删掉不需要的中间列

# 第二步:把foo_value、bar_value展开成item和value列
final_df = id_melted.melt(
    id_vars=['level1', 'level2', 'level3', 'id'],
    value_vars=['foo_value', 'bar_value'],
    var_name='item',
    value_name='value'
)

# 最后清理item列的后缀
final_df['item'] = final_df['item'].str.replace('_value', '')

# 调整列顺序到你想要的格式
final_df = final_df[['id', 'item', 'value', 'level1', 'level2', 'level3']]

方案二:结合wide_to_long和melt

如果你习惯用wide_to_long处理带统一后缀的列,可以试试这个组合:

# 先处理value列,转成长表
value_long = pd.wide_to_long(
    df,
    stubnames=['foo', 'bar'],
    i=['level1', 'level2', 'level3', 'id1', 'id2'],
    j='item',
    suffix='_value'
).reset_index()

# 再处理id列,展开成单独的id列
final_df = value_long.melt(
    id_vars=['level1', 'level2', 'level3', 'item'],
    value_vars=['id1', 'id2'],
    value_name='id'
).drop('variable', axis=1)

# 调整列顺序
final_df = final_df[['id', 'item', 'value', 'level1', 'level2', 'level3']]

方案三:用stack实现

通过设置索引后堆叠列的方式,也能达到目标效果:

# 先把层级列设为索引
df_indexed = df.set_index(['level1', 'level2', 'level3'])

# 堆叠id列
id_stack = df_indexed[['id1', 'id2']].stack().reset_index(name='id')
id_stack = id_stack.drop('level_3', axis=1)

# 堆叠value列并清理item名称
value_stack = df_indexed[['foo_value', 'bar_value']].stack().reset_index(name='value')
value_stack['item'] = value_stack['level_3'].str.replace('_value', '')
value_stack = value_stack.drop('level_3', axis=1)

# 合并两个结果
final_df = pd.merge(id_stack, value_stack, on=['level1', 'level2', 'level3'])
final_df = final_df[['id', 'item', 'value', 'level1', 'level2', 'level3']]

为什么之前pivot没成功?

简单说:pivot是把长表转换成宽表的工具,而你的需求是把宽表转成长表,方向刚好相反。所以用melt这类宽转长的工具才是正确的选择。

以上方案都是Pandas的内置向量化操作,性能比逐行循环高几个数量级,尤其是当你的DataFrame有几万甚至几十万行的时候,差距会非常明显。

内容的提问来源于stack exchange,提问作者abisko

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.28 20:32:36