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

Pandas处理EAV格式分组数据 无需透视新增商品平均单价属性实现方法

Pandas EAV长表新增计算属性的无透视实现方案

已知条件

假设拥有如下结构的Pandas DataFrame:

import pandas as pd
import numpy as np

data = [[5123, '2021-01-01 00:00:00', 'cash','sales$', 105],
        [5123, '2021-01-01 00:00:00', 'cash','items', 20],
        [5123, '2021-01-01 00:00:00', 'card','sales$', 355],
        [5123, '2021-01-01 00:00:00', 'card','items', 50],
        [5123, '2021-01-02 00:00:00', 'cash','sales$', np.nan],
        [5123, '2021-01-02 00:00:00', 'cash','items', np.nan],
        [5123, '2021-01-02 00:00:00', 'card','sales$', 170],
        [5123, '2021-01-02 00:00:00', 'card','items', 35]]

columns = ['Store', 'Date', 'Payment Method', 'Attribute', 'Value']

df = pd.DataFrame(data = data, columns = columns)

原始数据样例:

StoreDatePayment MethodAttributeValue
51232021-01-01 00:00:00cashsales$105
51232021-01-01 00:00:00cashitems20
51232021-01-01 00:00:00cardsales$355
51232021-01-01 00:00:00carditems50
51232021-01-02 00:00:00cashsales$NaN
51232021-01-02 00:00:00cashitemsNaN
51232021-01-02 00:00:00cardsales$170
51232021-01-02 00:00:00carditems35

需求说明

  • 按【Store/Date/Payment Method】三个维度分组
  • 每个分组新增属性average item price,值为该分组下sales$值除以items值,保留两位小数
  • 最终输出仍为EAV格式长表,预期结果如下:
StoreDatePayment MethodAttributeValue
51232021-01-01 00:00:00cashsales$105
51232021-01-01 00:00:00cashitems20
51232021-01-01 00:00:00cashaverage item price5.25
51232021-01-01 00:00:00cardsales$355
51232021-01-01 00:00:00carditems50
51232021-01-01 00:00:00cardaverage item price7.10
51232021-01-02 00:00:00cashsales$NaN
51232021-01-02 00:00:00cashitemsNaN
51232021-01-02 00:00:00cashaverage item priceNaN
51232021-01-02 00:00:00cardsales$170
51232021-01-02 00:00:00carditems35
51232021-01-02 00:00:00cardaverage item price4.86

无需透视的实现方案

核心思路:直接按分组维度对原长表做分组计算,每组内提取对应属性值计算后,构造新行拼接回原分组即可,无需做透视/逆透视的结构转换。

实现代码

def calc_avg_price(group):
    # 提取当前分组的销售额、销售件数
    sales = group.loc[group['Attribute'] == 'sales$', 'Value'].iloc[0]
    items = group.loc[group['Attribute'] == 'items', 'Value'].iloc[0]
    # 异常判断:空值、除数为0时返回NaN
    avg_price = sales / items if pd.notna(sales) and pd.notna(items) and items != 0 else np.nan
    # 构造新属性行
    new_row = group.iloc[0].copy()
    new_row['Attribute'] = 'average item price'
    new_row['Value'] = round(avg_price, 2)
    # 拼接原行和新行返回
    return pd.concat([group, new_row.to_frame().T], ignore_index=True)

# 分组计算得到最终结果
result = df.groupby(['Store', 'Date', 'Payment Method'], group_keys=False).apply(calc_avg_price).reset_index(drop=True)

方案优势

  • 避免了两次表结构转换的开销,处理大体积数据时性能优于透视方案
  • 逻辑直观,直接基于原始EAV结构操作,不需要维护中间转换状态

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.24 09:45:03