python-3.x [pandas]:对列进行Groupby,然后同时定义多个(包括一些自定义的)聚合函数

snvhrwxg  于 2023-05-02  发布在  Python
关注(0)|答案(2)|浏览(272)

我需要能够在一个groupby/agg语句中定义两个单独列的和&除,并将它们保存为一个新列,然后计算另一列的和。
国防部,请检查我想要的输出,然后再审查这个问题。看看这个网站上的其他问题,我只能弄清楚如何为一个聚合列而不是多个聚合列编写自定义聚合函数。
例如,Python - Pandas data frame: customized aggregation function after groupy?提出了一个类似的问题,但没有提供如何同时为多个列定义自定义函数的建议。
下面是一个问题陈述,我尝试的解决方案,以及我想要的结果。
下面是我的dataframe:

df = pd.DataFrame({'location': ['backyard', 'store', 'bank', 'backyard', 'backyard', 'bank', 'store'],
                   'is_orange': [1, 1, 0, 0, 1, 0, 1],
                   'is_non_orange': [0, 0, 1, 1, 0, 1, 0],
                   'melons':     [73, 81, 94, 174, 23, 71, 65]})

我想做这样的事情:

df.groupby(['location']).agg(
    'total orange/non-orange' : df['is_orange'] + df['is_non_orange'],
    'percent_orange'          : df['is_orange'] / (df['is_orange'] + df['is_non_orange']),
    'sum_melons'              : sum(df['melons']))

所需输出为:

df = 

location    total_orange/non-orange    percentage_oranges    melons
backyard                        3.0                  0.66       270
bank                            2.0                  0.00       165
store                           2.0                  1.00       146

先谢谢你了。

w46czmvw

w46czmvw1#

另一个答案(灵感来自于在Python Discord服务器上与Ry的讨论,以及我自己的测试):
定义数据框:

df = pd.DataFrame({
    'location' : ['backyard', 'store', 'bank', 'backyard', 'backyard', 'bank', 'store'],
    'is_orange': [1, 1, 0, 0, 1, 0, 1],
    'is_non_orange': [0, 0, 1, 1, 0, 1, 0],
    'melons': [73, 81, 94, 174, 23, 71, 65]
})

然后,我们定义一个函数,该函数将在最终.groupby()语句定义的每个子组上执行。

def stats(df_subgroup):
    return pd.Series({
    'total_oranges' : (df_subgroup['is_non_orange'] + df_subgroup['is_orange']).sum(),
    'percentage_oranges' : (df_subgroup['is_orange'] / (df_subgroup['is_non_orange'] + df_subgroup['is_orange'])).mean(),
    'melons': (df_subgroup['melons']).sum()
})

输出由以下命令给出:

df.groupby(['location']).apply(stats)

输出为:

total_oranges   percentage_oranges  melons
location            
backyard    3.0 0.666667    270.0
bank    2.0 0.000000    165.0
store   2.0 1.000000    146.0

我还用多个.groupby()列测试了它,它似乎工作得很好。需要注意的一点是.mean()函数的使用。我相信有一个更好的方法来提取每个子组的计算值,但这是一个体面的解决方案。
最后,我想提一下如果列条目不都是float/int,这种方法需要额外的调整。例如,将is_orangeis_non_orange列定义为布尔值:

df = pd.DataFrame({
    'location' : ['backyard', 'store', 'bank', 'backyard', 'backyard', 'bank', 'store'],
    'is_orange': [True, True, False, False, True, False, True],
    'is_non_orange': [False, False, True, True, False, True, False],
    'melons': [73, 81, 94, 174, 23, 71, 65]
})

并尝试运行与之前相同的逻辑:

def stats(df_subgroup):
    return pd.Series({
    'total_oranges' : (df_subgroup['is_non_orange'] + df_subgroup['is_orange']).sum(),
    'percentage_oranges' : (df_subgroup['is_orange'] / (df_subgroup['is_non_orange'] + df_subgroup['is_orange'])).mean(),
    'melons': (df_subgroup['melons']).sum()
})
    
df.groupby(['location']).apply(stats)

产生以下错误:NotImplementedError: operator 'truediv' not implemented for bool dtypes
相反,我们将逻辑修改为:

def stats(df_subgroup):
    return pd.Series({
    'total_oranges' : (df_subgroup['is_non_orange'].sum() + df_subgroup['is_orange'].sum()).sum(),
    'percentage_oranges' : (df_subgroup['is_orange'].sum() / (df_subgroup['is_non_orange'].sum() + df_subgroup['is_orange'].sum())).mean(),
    'melons': (df_subgroup['melons']).sum()
})
    
df.groupby(['location']).apply(stats)

(Note在每次布尔列调用结束时使用.sum()
这将产生所需的输出:

total_oranges   percentage_oranges  melons
location            
backyard    3.0 0.666667    270.0
bank    2.0 0.000000    165.0
store   2.0 1.000000    146.0
1rhkuytd

1rhkuytd2#

一个可能的解决方案(由Python Discord服务器上的shimmer建议):
定义数据框:

import pandas as pd

df = pd.DataFrame({'location': ['backyard', 'store', 'bank', 'backyard', 'backyard', 'bank', 'store'],
                   'is_orange': [1, 1, 0, 0, 1, 0, 1],
                   'is_non_orange': [0, 0, 1, 1, 0, 1, 0],
                   'melons':     [73, 81, 94, 174, 23, 71, 65]})

我们可以这样写:

df2 = pd.DataFrame()
df  = df.groupby('location').agg('sum')
df2['total_oranges'] = df['is_orange'] + df['is_non_orange']
df2['percentage_orange'] = df['is_orange'] / (df['is_orange'] + df['is_non_orange'])
df2['melons'] = df['melons']

输出为:

total_oranges   percentage_orange   melons
location            
backyard    3   0.666667    270
bank    2   0.000000    165
store   2   1.000000    146

相关问题