【问题标题】:How to apply different functions to a groupby object?如何将不同的功能应用于 groupby 对象?
【发布时间】:2026-02-03 14:15:02
【问题描述】:

我有一个这样的数据框:

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

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

目前我实现如下:

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']

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

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

编辑:

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

是不够的,因为可能存在一个组的min_val 高于该组的所有max_val 或低于所有min_valmax_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

【问题讨论】:

  • 是的,你走的很好。寻找简单解决方案的答案。
  • 您可以将一个函数传递给 groupby(或者更确切地说,作为对 groupby 的 agg 调用),但您仍然可以获得每个组的最大值和最小值。没有办法根据组的内容指定不同的功能,这似乎是您想要的。您可以指定一个更复杂的 agg 函数,在检查组后返回最大值或最小值,但这是否“更直接”是一个见仁见智的问题。
  • 给定组的min_value 是否可能高于所有max_values(或最大值低于所有分钟)?如果是这样,您可能应该更新您的示例数据以包含这种情况。没有这种可能性,选择最大值max_value 和只选择整体最大值(同样适用于最小值)之间没有区别,因此可以更简单地完成,就像量子思维的答案一样。
  • @BrenBarn:是的,这是可能的,这就是为什么我认为一个人也必须基于min_max 进行分组。好点子。我将编辑我的问题。
  • @Cleb:不要只说“它适用于这个例子,但一般不适用”。您应该更改您的示例数据,以便给定的解决方案不再有效,这样您的示例数据才能真正证明您的问题。

标签: python pandas dataframe group-by


【解决方案1】:

这是一个有点半开玩笑的解决方案:

>>> 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”之间没有如此简单的关系,显然这不会那么简单。它可以通过将列值映射到要应用的函数来概括,如下所示:

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 版本。 (这或多或少也是为什么没有内置方法可以做到这一点的原因:对于大多数数据,您不能先验地假设您的值可以映射到有意义的函数,因此尝试确定是没有意义的根据值本身应用的函数。)

【讨论】:

  • 好吧,这让我笑了。 :-)
  • 工作正常,谢谢!您能否在包含此类字典的地方更新您的答案?
  • 非常好的解决方案,我以前从未见过 ;) +1
  • getattr(g, g.name[1][:3])() - 这很聪明 :)
【解决方案2】:

一种选择是使用groupby.apply 进行自定义聚合,因为它不适合内置聚合场景:

(df.groupby('id')
 .apply(lambda g: pd.Series({'max': g.value[g.min_max == "max_val"].max(), 
                             'min': g.value[g.min_max == "min_val"].min()})))

#    max    min
#id     
# 1    3     10
# 2   20    -10

【讨论】:

  • 工作正常,谢谢!我暂时投赞成票,稍后根据其他答案的质量接受。
【解决方案3】:

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

【讨论】:

  • 工作正常,谢谢!我暂时投赞成票,稍后根据其他答案的质量接受它
  • 我也在考虑一种 pivot_table 方法,但是 OP 似乎被不需要的计算所困扰。我怀疑他试图避免它的时间比他节省的时间要长,所以 +1。
  • 这与 OP 的解决方案基本相同,它“丢弃”了“不必要的”计算。但我同意,首先进行“不必要的”计算并没有什么问题。
  • @BrenBarn - 是的,你是对的,有必要用丢失的数据计算最小值和最大值。感谢您的支持。