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

如何在保留前两列不变的情况下堆叠DataFrame的多列(Python Pandas)

如何在保留前两列不变的情况下堆叠DataFrame的多列(Python Pandas)

问题描述

我用的是Python 3.11.5,现在手里有个DataFrame,结构如下:包含id编号、每个id共用的日期范围,还有一堆和每行id对应的数值列。

原始DataFrame:

iddate123
11/1/00200300
11/2/00100200300
11/3/00200300
21/1/00200300
21/2/00100200300
21/3/00200300
31/1/00200300
31/2/00100200300
31/3/00200300

我想把它转换成下面的样子:除了id和date列之外的所有列合并成一列,而且数值要和对应行的id匹配上。

目标DataFrame:

iddatevalue
11/1/00
11/2/00100
11/3/00
21/1/00200
21/2/00200
21/3/00200
31/1/00300
31/2/00300
31/3/00300

我试过用下面这行stack()代码处理,但没成功。感觉melt()可能可行,但不知道怎么处理这些带编号的列名(实际我的列数比示例多很多),求大神帮忙!

df = df.set_index(['homeid', 'date']).stack().reset_index()

解决方案

你的需求核心不是简单堆叠列,而是根据每行的id值,提取对应编号列的数值,这里给你两种实用的方法:

方法1:用lookup快速匹配(适合Pandas < 2.0版本)

lookup是专门用来根据行和列的对应关系提取值的工具,简直是为你的场景量身定做的:

import pandas as pd

# 假设你的原始数据已经加载到df里了
df['value'] = df.lookup(df.index, df['id'].astype(str))
# 只保留需要的三列
result = df[['id', 'date', 'value']]

简单解释:把id转成字符串后,刚好和你的列名"1"、"2"、"3"对应上,lookup会自动在每一行找到对应id列的数值,直接赋值给新的value列,最后筛选出目标列就行。

方法2:用melt+过滤(全Pandas版本通用)

如果你的Pandas是2.0+版本(lookup已被移除),可以用melt配合筛选来实现:

# 先把宽表转成窄表,保留id、date,其他列转成列名和对应值
melted_df = df.melt(id_vars=['id', 'date'], var_name='col_num', value_name='value')
# 只保留列名和当前行id匹配的记录
filtered_df = melted_df[melted_df['col_num'] == melted_df['id'].astype(str)]
# 按id和date排序,恢复原始顺序(可选)
result = filtered_df.sort_values(by=['id', 'date']).reset_index(drop=True)
# 删掉中间列col_num
result = result.drop('col_num', axis=1)

解释:先用melt把所有数值列拆成col_num(原列名)和value,然后筛选出col_num等于当前行id的记录,这样就拿到了每个id对应列的数值,最后整理成目标结构。

为啥你的stack()代码没生效?

你之前的代码有两个问题:一是把列名写错了(你的原始列是id不是homeid);二是stack()会把所有数值列都堆叠起来,导致每个(id, date)组合会生成多行记录,而不是只保留对应id列的那一行,所以不符合你的需求。

备注:内容来源于stack exchange,提问作者user25024572

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.14 15:00:29