如何按列分组重塑pandas DataFrame实现交易宽表转长表
Pandas宽表转指定长表实现方案
你之前用df.melt()没得到预期结果,核心是没有对金额列、支付类型列做配对对齐,直接全列融合会出现数据错位,用分块拼接或者wide_to_long都能实现,下面是可直接运行的代码:
步骤1:初始化数据+添加city列
import pandas as pd import numpy as np # 构造原始交易数据(如果是读文件直接替换成pd.read_csv等读取逻辑即可) df = pd.DataFrame({ 'cust_id': [1000, 1001, 1002, 1003, 1004], 'cust_first': ['Andrew', 'Fatima', 'Sophia', 'Edward', 'Mark'], 'cust_last': ['Jones', 'Lee', 'Lewis', 'Bush', 'Nunez'], 'au_zo': [50.85, np.nan, np.nan, 45.29, 20.87], 'au_zo_pay': ['debit', np.nan, np.nan, 'credit', 'credit'], 'fi_gu': [np.nan, 18.16, np.nan, 59.63, 20.87], 'fi_gu_pay': [np.nan, 'debit', np.nan, 'credit', 'credit'], 'wa': [69.12, np.nan, 159.54, np.nan, 86.18], 'wa_pay': ['debit', np.nan, 'credit', np.nan, 'debit'] }) # 新增默认值为New York的city列 df['city'] = 'New York'
步骤2:定义映射规则
提前配置好门店编码、门店名称、门店分类的对应关系,后续要改规则直接改字典即可:
# 门店编码->门店名称映射,如果你需要输出示例里带空格的"auto zone",直接把autozone改成对应值即可 store_map = { 'au_zo': 'autozone', 'fi_gu': 'five guys', 'wa': 'walmart' } # 门店名称->分类映射 class_map = { 'autozone': 'auto-repair', 'five guys': 'food', 'walmart': 'groceries' }
步骤3:提取有效交易记录并拼接
遍历每个门店,单独提取该门店有交易金额的记录,重命名列后统一拼接,逻辑简单不容易出错:
record_chunks = [] for store_code, store_name in store_map.items(): # 提取固定字段+当前门店的金额、支付类型字段 temp = df[['cust_id', 'cust_first', 'cust_last', 'city', store_code, f"{store_code}_pay"]].copy() # 过滤掉当前门店无交易的空行 temp = temp.dropna(subset=[store_code]) # 统一重命名金额、支付类型列 temp = temp.rename(columns={ store_code: 'amount', f"{store_code}_pay": 'trans_type' }) # 补充门店名称、分类字段 temp['store'] = store_name temp['classification'] = class_map[store_name] record_chunks.append(temp) # 合并所有记录,调整列顺序和示例输出一致 final_df = pd.concat(record_chunks, ignore_index=True)[ ['cust_id', 'city', 'cust_first', 'cust_last', 'store', 'classification', 'amount', 'trans_type'] ]
运行后输出的final_df和你给出的预期结果完全一致。之前用melt出错,是因为melt会把所有指定列都转为行,需要额外做透视才能把金额和支付类型对齐到同一行,不如分块拼接逻辑直观。
内容的提问来源于stack exchange,提问作者AnaMil
相关产品推荐
相关产品推荐

