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

如何将宽格式的Pandas DataFrame转换为长格式

如何将宽格式的Pandas DataFrame转换为长格式

嗨,我来帮你搞定这个格式转换的问题~你的DataFrame列名其实有很清晰的规律:f_proba_*和p_proba_*的后缀数字就是学生ID,这种场景下用Pandas的wide_to_long函数会比你尝试的普通melt更直接高效,而且能一步得到你想要的结果。

先说说你之前的melt为什么没成功:普通melt是把所有指定的value_vars转成一列值,但你试图把value_name设为两个列,这不符合它的使用逻辑,所以会出错。而我们的需求是两组变量(f_proba和p_proba)对应同一个分组键(Student_ID),wide_to_long就是专门为这种带前缀-后缀的宽表设计的工具。

解决方案代码

直接上可以运行的完整代码:

import pandas as pd

# 你的原始宽表
df = pd.DataFrame({'Class_ID': {0: 432, 1: 493, 2: 32},
                   'f_proba_1': {0: 3, 1: 8, 2: 6},
                   'f_proba_2': {0: 4, 1: 9, 2: 9},
                   'f_proba_3': {0: 2, 1: 4, 2: 1},
                   'p_proba_1': {0: 3, 1: 82, 2: 36},
                   'p_proba_2': {0: 2, 1: 92, 2: 96},
                   'p_proba_3': {0: 8, 1: 41, 2: 18},
                   'Meeting_ID': {0: 27, 1: 23, 2: 21}})

# 使用wide_to_long转换为长表
long_df = pd.wide_to_long(
    df,
    stubnames=['f_proba', 'p_proba'],  # 列名的前缀部分
    i=['Class_ID', 'Meeting_ID'],      # 不需要转换的标识列
    j='Student_ID',                    # 后缀对应的新列名
    sep='_',                           # 前缀和后缀的分隔符
    suffix=r'\d+'                      # 匹配数字后缀的正则
)

# 重置索引,把Student_ID从索引移到普通列
long_df = long_df.reset_index()

print(long_df)

转换后的结果

运行后会得到你期望的长格式DataFrame:

Class_ID  Meeting_ID  Student_ID  f_proba  p_proba
0       432          27           1        3        3
1       432          27           2        4        2
2       432          27           3        2        8
3       493          23           1        8       82
4       493          23           2        9       92
5       493          23           3        4       41
6        32          21           1        6       36
7        32          21           2        9       96
8        32          21           3        1       18

参数简单解释

  • stubnames:指定要转换的列的公共前缀,这里就是f_proba和p_proba,后面跟着的是作为分组键的后缀。
  • i:设置转换过程中保持不变的标识列,也就是每个长表行的所属分组。
  • j:给后缀部分指定一个新列名,这里就是学生ID。
  • sep:列名中分隔前缀和后缀的字符,我们的列名用下划线_分隔,所以填'_'。
  • suffix:用正则匹配后缀的格式,r'\d+'表示匹配一个或多个数字,正好对应我们的1、2、3。

如果你一定要用melt的话(可选)

如果你想坚持用melt实现,也可以分两步处理f和p的列,再合并,不过会麻烦一些:

# 处理f_proba列
f_melt = df.melt(
    id_vars=['Class_ID', 'Meeting_ID'],
    value_vars=['f_proba_1', 'f_proba_2', 'f_proba_3'],
    var_name='Student_ID',
    value_name='f_proba'
)
f_melt['Student_ID'] = f_melt['Student_ID'].str.extract(r'(\d+)').astype(int)

# 处理p_proba列
p_melt = df.melt(
    id_vars=['Class_ID', 'Meeting_ID'],
    value_vars=['p_proba_1', 'p_proba_2', 'p_proba_3'],
    var_name='Student_ID',
    value_name='p_proba'
)
p_melt['Student_ID'] = p_melt['Student_ID'].str.extract(r'(\d+)').astype(int)

# 合并两个结果
long_df = pd.merge(f_melt, p_melt, on=['Class_ID', 'Meeting_ID', 'Student_ID'])

不过显然wide_to_long更适配你的场景,代码更简洁高效~

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.14 15:37:59