如何将不同的函数应用于groupby对象?

时间:2017-03-12 17:52:59

标签: python pandas dataframe group-by

我有一个这样的数据框:

import pandas as pd

df = pd.DataFrame({'id': [1, 2, 1, 1, 2, 1, 2, 2],
               'min_max': ['max_val', 'max_val', 'min_val', 'min_val', 'max_val', 'max_val', 'min_val', 'min_val'],
               'value': [1, 20, 20, 10, 12, 3, -10, -5 ]})

   id  min_max  value
0   1  max_val      1
1   2  max_val     20
2   1  min_val     20
3   1  min_val     10
4   2  max_val     12
5   1  max_val      3
6   2  min_val    -10
7   2  min_val     -5

每个id都有几个与之关联的最大值和最小值。我的期望输出如下所示:

    max  min
id          
1     3   10
2    20  -10

它包含每个max_val的最大min_val和最小id

目前我按如下方式实施:

gdf = df.groupby(by=['id', 'min_max'])['value']

max_max = gdf.max().loc[:, 'max_val']
min_min = gdf.min().loc[:, 'min_val']

final_df = pd.concat([max_max, min_min], axis=1)
final_df.columns = ['max', 'min']

我不喜欢的是,我必须在分组数据框.max()上拨打.min()gdf,我会分别丢弃50%的信息(因为我是对最大min_val和最小min_val不感兴趣。

有没有办法以更直接的方式做到这一点,例如:将应该应用于组的函数直接传递给groupby调用?

编辑:

df.groupby('id')['value'].agg(['max','min'])

是不够的,因为可能存在一个组的min_val高于该组的所有max_valmax_val低于所有min_val的情况}}。因此,还必须根据列min_max进行分组。

的结果
df.groupby('id')['value'].agg(['max','min'])

    max  min
id          
1    20    1
2    20  -10

上述代码的结果:

    max  min
id          
1     3   10
2    20  -10

3 个答案:

答案 0 :(得分:6)

这是一个略显诙谐的解决方案:

>>> df.groupby(['id', 'min_max'])['value'].apply(lambda g: getattr(g, g.name[1][:3])()).unstack()
min_max  max_val  min_val
id                       
1              3       10
2             20      -10

这将应用一个函数,该函数从组密钥中获取要应用的实数函数的名称。

显然,如果字符串" max_val"之间没有这么简单的关系,那么这就不会那么简单。和函数名称" max"。它可以通过将dict映射列值映射到要应用的函数来推广,如下所示:

func_map = {'min_val': min, 'max_val': max}
df.groupby(['id', 'min_max'])['value'].apply(lambda g: func_map[g.name[1]](g)).unstack()

请注意,这比上面的版本效率稍低,因为它调用普通的Python max / min而不是优化的pandas版本。但是如果你想要一个更通用的解决方案,那就是你必须做的事情,因为没有优化所有的pandas版本。 (这也或多或少地为什么没有内置的方法来做到这一点:对于大多数数据,你不能假设你的值可以映射到有意义的函数,所以它没有&#39 ; t有意义尝试根据值本身确定要应用的函数。)

答案 1 :(得分:3)

一个选项是使用Place.select(:city, :updated_at).in_state("IL").group(:city, :updated_at).order(:city).distinct 进行自定义聚合,因为它不适合内置聚合方案:

groupby.apply

答案 2 :(得分:2)

pivot_table的解决方案:

df1 = df.pivot_table(index='id', columns='min_max', values='value', aggfunc=[np.min,np.max])
df1 = df1.loc[:, [('amin','min_val'), ('amax','max_val')]]
df1.columns = df1.columns.droplevel(1)
print (df1)
    amin  amax
id            
1     10     3
2    -10    20