在Python Pandas中为groupby聚合函数应用过滤器

ev7lccsx  于 2023-03-11  发布在  Python
关注(0)|答案(4)|浏览(129)

如何在Pandas中为groupby聚合函数应用filter?
我有数据框

data = {'Fruit':['apple', 'apple', 'apple', 'kivi', 'kivi', 'kivi'],
              'Y_or_N': ['Y', 'N', 'Y', 'N', 'N', 'Y'], 
              'A_or_B': ['A', 'A', 'B', 'A', 'B', 'A'],
              'Number': [3, 5, 6, 7, 2, 4]}

df = pd.DataFrame.from_dict(data)

我想为每个水果组总和数值在3列:(1)所有值,(2)其中“Y_或_N”==“Y”,(3)其中“A_或_B”==“A”。
我尝试了以下方法:

new_df = df.groupby(['Fruit']).apply(lambda x: x[x['Y_or_N'] == 'Y' ].agg(sum_Y=('Number', 'sum')))

这是可行的,但只适用于1列。有没有更有效的方法对不同的列和聚合函数应用不同的过滤器?而不需要制作3个df然后将它们合并在一起。
预期输出:
| 水果|总和|总和_Y|总和_A|
| - ------|- ------|- ------|- ------|
| 苹果|十四|九|八个|
| 基维|十三|四个|十一|

tp5buhyn

tp5buhyn1#

我将首先修改列,然后进行聚合:

(df.assign(sum_Y=lambda d: d['Number'].where(d['Y_or_N'].eq('Y')),
           sum_A=lambda d: d['Number'].where(d['A_or_B'].eq('A')),
          )
   .rename(columns={'Number': 'sum_all'})
   .groupby('Fruit', as_index=False)[['sum_all', 'sum_Y', 'sum_A']].sum()
)

输出:

Fruit  sum_all  sum_Y  sum_A
0  apple       14    9.0    8.0
1   kivi       13    4.0   11.0
0md85ypi

0md85ypi2#

import pandas as pd

data = {'Fruit':['apple', 'apple', 'apple', 'kivi', 'kivi', 'kivi'],
              'Y_or_N': ['Y', 'N', 'Y', 'N', 'N', 'Y'], 
              'A_or_B': ['A', 'A', 'B', 'A', 'B', 'A'],
              'Number': [3, 5, 6, 7, 2, 4]}

df = pd.DataFrame.from_dict(data)

r1 = df.groupby(['Fruit'])['Number'].sum()
r2 = df.groupby(['Fruit']).apply(lambda d: d[d['Y_or_N'].eq('Y')]['Number'].sum())
r3 = df.groupby(['Fruit']).apply(lambda d: d[d['A_or_B'].eq('A')]['Number'].sum())

r = pd.concat([r1, r2, r3], axis=1).set_axis(['Sum_All', 'Sum_Y', 'Sum_A'], axis='columns')

print(r)
Sum_All  Sum_Y  Sum_A
Fruit                       
apple       14      9      8
kivi        13      4     11
rkkpypqq

rkkpypqq3#

pd.pivot的另一个选项:

res_df = df.pivot(index='Fruit', columns=['Y_or_N', 'A_or_B'], values='Number')
res_df = pd.concat([res_df.sum(1).to_frame('sum_all'),
                    res_df.xs('Y', axis=1).sum(1).to_frame('sum_Y'),
                    res_df.xs('A', level=1, axis=1).sum(1).to_frame('sum_A')], axis=1).reset_index()
Fruit  sum_all  sum_Y  sum_A
0  apple     14.0    9.0    8.0
1   kivi     13.0    4.0   11.0
v7pvogib

v7pvogib4#

以下是您可以做到这一点的三种方法:

第一种方式:

res = ( df
    .Number.pipe(lambda s: pd.DataFrame({
        'Fruit':df.Fruit, 
        'sum_all':s, 
        'sum_Y':s[df.Y_or_N.eq('Y')], 
        'sum_A':s[df.A_or_B.eq('A')]}))
    .groupby('Fruit', as_index=False).sum().convert_dtypes() )

第二条路:

res = pd.DataFrame({
    'sum_all':df.groupby('Fruit').Number.sum(),
    'sum_Y':df[df.Y_or_N.eq('Y')].groupby('Fruit').Number.sum(),
    'sum_A':df[df.A_or_B.eq('A')].groupby('Fruit').Number.sum()}).reset_index()

方法#3:这是@mozway给出的最佳答案的变体,并进行了以下调整:

  • 将公共的Number列访问分解为Series,我们将其管道化为lambda
  • 使用convert_dtypes返回int,以获取筛选列的总和,其中NaN导致向上转换浮动
res = (df.Number.pipe(lambda s: df
    .assign(sum_Y=lambda d: s[d.Y_or_N.eq('Y')], sum_A=lambda d: s[d.A_or_B.eq('A')]))
    .rename(columns={'Number': 'sum_all'})
    .groupby('Fruit', as_index=False).sum().convert_dtypes()
)

输出:

Fruit  sum_all  sum_Y  sum_A
0  apple       14      9      8
1   kivi       13      4     11

相关问题