我有这样的数据帧:
import pandas as pd df = pd.DataFrame({'id': [1,2,1,2],'min_max': ['max_val','max_val','min_val','min_val'],'value': [1,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%的信息(因为我对最大min_val和最小值不感兴趣) MIN_VAL).
有没有办法以更直接的方式做到这一点,例如将应该应用于组的函数直接传递给groupby调用?
编辑:
df.groupby('id')['value'].agg(['max','min'])
是不够的,因为可能存在一个组的min_val高于该组的所有max_val或max_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
解决方法
这是一个略显诙谐的解决方案:
>>> 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版本. (这也或多或少地为什么没有内置的方法来执行此操作:对于大多数数据,您不能假设您的值可以映射到有意义的函数,因此尝试确定没有意义基于值本身应用的函数.)