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

Python中优雅高效转换多属性宽格式DataFrame为长格式的最优方法

如何将成对属性列的宽格式DataFrame转换为长格式(Python)

这是个非常典型的宽表转长表需求,针对你这种成对出现的属性列(attribute_X_name + attribute_X_rating),我首推用pandas的pd.wide_to_long方法——它不仅代码简洁优雅,而且是专门为这类场景优化的,处理大量行数据时效率也很高,完全适配你属性编号到13的场景。

先还原你的示例数据

首先我们先把你给出的示例转换成可运行的DataFrame:

import pandas as pd

df_wide = pd.DataFrame({
    'id': [1, 3],
    'name': ['Linda', 'Brian'],
    'last': ['Smith', 'Lin'],
    'attribute_1_name': ['Age', 'Hair'],
    'attribute_1_rating': [23, 'Black'],
    'attribute_2_name': ['Hair', 'Job'],
    'attribute_2_rating': ['Brown', 'Barista']
})

用wide_to_long实现转换

这个方法的核心是通过列名的模式匹配,自动识别成对的属性列,不用手动列举所有13组属性:

df_long = pd.wide_to_long(
    df_wide,
    stubnames=['attribute_name', 'attribute_rating'],  # 列名的前缀部分(去掉数字后缀的部分)
    i=['id', 'name', 'last'],  # 转换后保持不变的标识符列
    j='attribute_num',  # 临时生成的属性编号列(可以后续删除)
    sep='_',  # 列名中分隔前缀和数字的符号
    suffix=r'\d+'  # 匹配数字后缀(支持1到13甚至更多)
).reset_index()

# 如果你不需要attribute_num这列,直接删掉就行
df_long = df_long.drop(columns='attribute_num')

转换后的结果完全符合你的要求:

id    name   last attribute_name attribute_rating
0   1   Linda  Smith            Age               23
1   1   Linda  Smith           Hair             Brown
2   3   Brian    Lin           Hair             Black
3   3   Brian    Lin            Job           Barista

为什么这个方法最优?

  • 优雅性:不用手动写循环生成1到13的列名,只要指定前缀和匹配规则,不管属性数量多少都能自动适配
  • 高效性:wide_to_long是pandas底层优化过的方法,处理百万级以上的行数据时,性能远优于手动循环或者多次melt再合并的方案

备选方案:用melt实现(不推荐)

如果你一定要用melt,也能实现,但代码会繁琐很多,而且效率更低:

# 分别处理name和rating列
melt_name = df_wide.melt(
    id_vars=['id', 'name', 'last'],
    value_vars=[f'attribute_{i}_name' for i in range(1, 14)],
    var_name='attribute_num',
    value_name='attribute_name'
)

melt_rating = df_wide.melt(
    id_vars=['id', 'name', 'last'],
    value_vars=[f'attribute_{i}_rating' for i in range(1, 14)],
    var_name='attribute_num',
    value_name='attribute_rating'
)

# 合并两个结果并清理
df_long_melt = pd.merge(melt_name, melt_rating, on=['id', 'name', 'last', 'attribute_num'])
df_long_melt = df_long_melt.drop(columns='attribute_num').dropna()

这种方法需要手动生成所有属性列名,而且合并操作会带来额外的性能开销,所以只作为备选。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.30 18:59:07