Pandas -通过划分EAV格式数据为组创建新属性和值

rsaldnfx  于 2023-01-19  发布在  其他
关注(0)|答案(4)|浏览(103)

假设我有这样一个 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)

| 商店|日期|付款方式|属性|价值|
| - ------|- ------|- ------|- ------|- ------|
| 小行星5123|2021年01月01日00时00分|现金|销售额|一百零五|
| 小行星5123|2021年01月01日00时00分|现金|项目|二十个|
| 小行星5123|2021年01月01日00时00分|卡片|销售额|三五五|
| 小行星5123|2021年01月01日00时00分|卡片|项目|五十|
| 小行星5123|2021年1月2日00时00分|现金|销售额|钠氮|
| 小行星5123|2021年1月2日00时00分|现金|项目|钠氮|
| 小行星5123|2021年1月2日00时00分|卡片|销售额|一百七十|
| 小行星5123|2021年1月2日00时00分|卡片|项目|三十五|
我想创建一个新的属性,称为"平均项目价格",它是通过,对于每个商店/日期/支付方式,销售额除以项目(例如,对于商店5123,2021 - 01 - 01,现金,我想创建一个新的行,属性称为"平均项目价格,"值等于5. 25).
我意识到我可以将这些数据透视出来,用一列表示销售额,一列表示商品,然后将这两列分开,然后重新堆叠,但是有没有更好的方法可以在不使用透视的情况下做到这一点呢?
| 商店|日期|付款方式|属性|价值|
| - ------|- ------|- ------|- ------|- ------|
| 小行星5123|2021年01月01日00时00分|现金|销售额|一百零五|
| 小行星5123|2021年01月01日00时00分|现金|项目|二十个|
| 小行星5123|2021年01月01日00时00分|现金|平均项目价格|五点二五|
| 小行星5123|2021年01月01日00时00分|卡片|销售额|三五五|
| 小行星5123|2021年01月01日00时00分|卡片|项目|五十|
| 小行星5123|2021年01月01日00时00分|卡片|平均项目价格|七、十|
| 小行星5123|2021年1月2日00时00分|现金|销售额|钠氮|
| 小行星5123|2021年1月2日00时00分|现金|项目|钠氮|
| 小行星5123|2021年1月2日00时00分|现金|平均项目价格|钠氮|
| 小行星5123|2021年1月2日00时00分|卡片|销售额|一百七十|
| 小行星5123|2021年1月2日00时00分|卡片|项目|三十五|
| 小行星5123|2021年1月2日00时00分|卡片|平均项目价格|四点八六|

wr98u20j

wr98u20j1#

您可以使用pivot_table来获得每组的销售额/项目的总和,然后使用原始数据计算平均值和merge

s = (df.pivot_table(index=['Store', 'Date', 'Payment Method'],
                    columns='Attribute', values='Value', aggfunc='sum')
       .assign(avg=lambda d: d['sales$']/d['items'])
       ['avg']
     )

df.merge(s, left_on=['Store', 'Date', 'Payment Method'], right_index=True)

输出:

Store                 Date Payment Method Attribute  Value       avg
0   5123  2021-01-01 00:00:00           cash    sales$  105.0  5.250000
1   5123  2021-01-01 00:00:00           cash     items   20.0  5.250000
2   5123  2021-01-01 00:00:00           card    sales$  355.0  7.100000
3   5123  2021-01-01 00:00:00           card     items   50.0  7.100000
4   5123  2021-01-02 00:00:00           cash    sales$    NaN       NaN
5   5123  2021-01-02 00:00:00           cash     items    NaN       NaN
6   5123  2021-01-02 00:00:00           card    sales$  170.0  4.857143
7   5123  2021-01-02 00:00:00           card     items   35.0  4.857143
连续
df2 = (df.pivot_table(index=['Store', 'Date', 'Payment Method'],
                      columns='Attribute', values='Value', aggfunc='sum')
         .assign(Attribute='average item price',
                 Value=lambda d: d['sales$']/d['items'],
                 )
         .reset_index()
       )

(pd.concat([df,df2])
   .sort_values(by=columns)
   [columns]
 )

输出:

Store                 Date Payment Method           Attribute       Value
0   5123  2021-01-01 00:00:00           card  average item price    7.100000
3   5123  2021-01-01 00:00:00           card               items   50.000000
2   5123  2021-01-01 00:00:00           card              sales$  355.000000
1   5123  2021-01-01 00:00:00           cash  average item price    5.250000
1   5123  2021-01-01 00:00:00           cash               items   20.000000
0   5123  2021-01-01 00:00:00           cash              sales$
snvhrwxg

snvhrwxg2#

pivot,然后在根据需要分配“属性”后append

pivoted = df.pivot(["Store", "Date", "Payment Method"], "Attribute", "Value")
output = (df.append(pivoted["sales$"].div(pivoted["items"])
                    .rename("Value").reset_index()
                    .assign(Attribute="average item price"), ignore_index=True)
          .sort_values(["Store", "Date", "Payment Method"])
          .reset_index(drop=True)
          )

>>> output
    Store                 Date Payment Method           Attribute       Value
0    5123  2021-01-01 00:00:00           card              sales$  355.000000
1    5123  2021-01-01 00:00:00           card               items   50.000000
2    5123  2021-01-01 00:00:00           card  average item price    7.100000
3    5123  2021-01-01 00:00:00           cash              sales$  105.000000
4    5123  2021-01-01 00:00:00           cash               items   20.000000
5    5123  2021-01-01 00:00:00           cash  average item price    5.250000
6    5123  2021-01-02 00:00:00           card              sales$  170.000000
7    5123  2021-01-02 00:00:00           card               items   35.000000
8    5123  2021-01-02 00:00:00           card  average item price    4.857143
9    5123  2021-01-02 00:00:00           cash              sales$         NaN
10   5123  2021-01-02 00:00:00           cash               items         NaN
11   5123  2021-01-02 00:00:00           cash  average item price         NaN
zfycwa2u

zfycwa2u3#

一种选择是设置索引,进行计算,然后使用分类值来获得与您的输出相匹配的排序输出:

cols = df.columns[:-1].tolist()
temp = df.set_index(cols)
# computation
summary = temp.xs('sales$', level='Attribute').div(temp.xs('items', level='Attribute'))
# add attribute to index, with a name:
summary = summary.set_index([['average item price'] * len(summary)], 
                            append = True)
summary.index = summary.index.set_names('Attribute', level = -1)
output = pd.concat([temp, summary]).reset_index()
# create categoricals and sort:
dtype = pd.CategoricalDtype(['sales$', 'items', 'average item price'], ordered = True)
output.Attribute = output.Attribute.astype(dtype)
dtype = pd.CategoricalDtype(['cash', 'card'], ordered = True)
output['Payment Method'] = output['Payment Method'].astype(dtype)
output.sort_values(cols)

    Store                 Date Payment Method           Attribute       Value
0    5123  2021-01-01 00:00:00           cash              sales$  105.000000
1    5123  2021-01-01 00:00:00           cash               items   20.000000
8    5123  2021-01-01 00:00:00           cash  average item price    5.250000
2    5123  2021-01-01 00:00:00           card              sales$  355.000000
3    5123  2021-01-01 00:00:00           card               items   50.000000
9    5123  2021-01-01 00:00:00           card  average item price    7.100000
4    5123  2021-01-02 00:00:00           cash              sales$         NaN
5    5123  2021-01-02 00:00:00           cash               items         NaN
10   5123  2021-01-02 00:00:00           cash  average item price         NaN
6    5123  2021-01-02 00:00:00           card              sales$  170.000000
7    5123  2021-01-02 00:00:00           card               items   35.000000
11   5123  2021-01-02 00:00:00           card  average item price    4.857143
wpx232ag

wpx232ag4#

溶液1:

def function1(dd:pd.DataFrame):
        dd1=dd.assign(Value=lambda dd:dd.Value/dd.Value.shift(-1)).head(1).assign(Attribute='average item price')
        return pd.concat([dd,dd1])

df.groupby(['Store','Date','Payment Method'],sort=False).apply(function1).reset_index(drop=True).pipe(print)

输出:

Store                 Date Payment Method           Attribute       Value
0    5123  2021-01-01 00:00:00           cash              sales$  105.000000
1    5123  2021-01-01 00:00:00           cash               items   20.000000
2    5123  2021-01-01 00:00:00           cash  average item price    5.250000
3    5123  2021-01-01 00:00:00           card              sales$  355.000000
4    5123  2021-01-01 00:00:00           card               items   50.000000
5    5123  2021-01-01 00:00:00           card  average item price    7.100000
6    5123  2021-01-02 00:00:00           cash              sales$         NaN
7    5123  2021-01-02 00:00:00           cash               items         NaN
8    5123  2021-01-02 00:00:00           cash  average item price         NaN
9    5123  2021-01-02 00:00:00           card              sales$  170.000000
10   5123  2021-01-02 00:00:00           card               items   35.000000
11   5123  2021-01-02 00:00:00           card  average item price    4.857143

也可以使用pandasql:

def function1(dd:pd.DataFrame):
        return dd.sql("""
        select * from self union all select tb1.Store,tb1.Date,tb1.[Payment Method],'average item price' Attribute,round(tb1.Value/tb2.value,2) as value from (select * from self where Attribute='sales$') tb1 join (select * from self where Attribute='items') tb2
        """)

df.groupby(['Store','Date','Payment Method']).apply(function1).reset_index(drop=True)

相关问题