Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/360.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 将多个函数应用于多个groupby列_Python_Group By_Aggregate Functions_Pandas - Fatal编程技术网

Python 将多个函数应用于多个groupby列

Python 将多个函数应用于多个groupby列,python,group-by,aggregate-functions,pandas,Python,Group By,Aggregate Functions,Pandas,演示如何使用以输出列名为键的dict一次在groupby对象上应用多个函数: In [563]: grouped['D'].agg({'result1' : np.sum, .....: 'result2' : np.mean}) .....: Out[563]: result2 result1 A bar -0.579846 -1.739537 foo -0.280588 -1.402

演示如何使用以输出列名为键的dict一次在groupby对象上应用多个函数:

In [563]: grouped['D'].agg({'result1' : np.sum,
   .....:                   'result2' : np.mean})
   .....:
Out[563]: 
      result2   result1
A                      
bar -0.579846 -1.739537
foo -0.280588 -1.402938
但是,这仅适用于Series groupby对象。当dict类似地传递给groupby数据帧时,它希望键是将应用该函数的列名

我想做的是对几个列应用多个函数(但某些列将被多次操作)。此外,某些函数将依赖于groupby对象中的其他列(如sumif函数)。我当前的解决方案是逐列执行,并执行类似于上面代码的操作,对依赖于其他行的函数使用lambdas。但这需要很长时间(我认为遍历groupby对象需要很长时间)。我必须对其进行更改,以便在一次运行中遍历整个groupby对象,但我想知道pandas中是否有一种内置的方法可以干净地完成这项工作

例如,我试过类似的方法

grouped.agg({'C_sum' : lambda x: x['C'].sum(),
             'C_std': lambda x: x['C'].std(),
             'D_sum' : lambda x: x['D'].sum()},
             'D_sumifC3': lambda x: x['D'][x['C'] == 3].sum(), ...)
但正如预期的那样,我得到了一个keyrerror(因为如果从数据帧调用
agg
,则键必须是一列)

是否有任何内置的方式来完成我想做的事情,或者可能会添加此功能,或者我只需要手动迭代groupby


感谢在第一部分中,您可以传递键的列名和值的函数列表:

In [28]: df
Out[28]:
          A         B         C         D         E  GRP
0  0.395670  0.219560  0.600644  0.613445  0.242893    0
1  0.323911  0.464584  0.107215  0.204072  0.927325    0
2  0.321358  0.076037  0.166946  0.439661  0.914612    1
3  0.133466  0.447946  0.014815  0.130781  0.268290    1

In [26]: f = {'A':['sum','mean'], 'B':['prod']}

In [27]: df.groupby('GRP').agg(f)
Out[27]:
            A                   B
          sum      mean      prod
GRP
0    0.719580  0.359790  0.102004
1    0.454824  0.227412  0.034060
更新1:

由于聚合函数适用于系列,因此对其他列名的引用将丢失。为了解决这个问题,您可以引用完整的数据帧,并使用lambda函数中的组索引对其进行索引

这里有一个简单的解决方法:

In [67]: f = {'A':['sum','mean'], 'B':['prod'], 'D': lambda g: df.loc[g.index].E.sum()}

In [69]: df.groupby('GRP').agg(f)
Out[69]:
            A                   B         D
          sum      mean      prod  <lambda>
GRP
0    0.719580  0.359790  0.102004  1.170219
1    0.454824  0.227412  0.034060  1.182901

对于第一部分,您可以传递键的列名和值的函数列表:

In [28]: df
Out[28]:
          A         B         C         D         E  GRP
0  0.395670  0.219560  0.600644  0.613445  0.242893    0
1  0.323911  0.464584  0.107215  0.204072  0.927325    0
2  0.321358  0.076037  0.166946  0.439661  0.914612    1
3  0.133466  0.447946  0.014815  0.130781  0.268290    1

In [26]: f = {'A':['sum','mean'], 'B':['prod']}

In [27]: df.groupby('GRP').agg(f)
Out[27]:
            A                   B
          sum      mean      prod
GRP
0    0.719580  0.359790  0.102004
1    0.454824  0.227412  0.034060
更新1:

由于聚合函数适用于系列,因此对其他列名的引用将丢失。为了解决这个问题,您可以引用完整的数据帧,并使用lambda函数中的组索引对其进行索引

这里有一个简单的解决方法:

In [67]: f = {'A':['sum','mean'], 'B':['prod'], 'D': lambda g: df.loc[g.index].E.sum()}

In [69]: df.groupby('GRP').agg(f)
Out[69]:
            A                   B         D
          sum      mean      prod  <lambda>
GRP
0    0.719580  0.359790  0.102004  1.170219
1    0.454824  0.227412  0.034060  1.182901

目前被接受的答案的后半部分已经过时,并且有两个反对意见。首先也是最重要的一点,您不能再将字典字典传递给
agg
groupby方法。第二,永远不要使用
.ix

如果希望同时处理两个单独的列,我建议使用
apply
方法,该方法隐式地将数据帧传递给应用的函数。让我们使用与上面的数据帧类似的数据帧

df = pd.DataFrame(np.random.rand(4,4), columns=list('abcd'))
df['group'] = [0, 0, 1, 1]
df

          a         b         c         d  group
0  0.418500  0.030955  0.874869  0.145641      0
1  0.446069  0.901153  0.095052  0.487040      0
2  0.843026  0.936169  0.926090  0.041722      1
3  0.635846  0.439175  0.828787  0.714123      1
从列名映射到聚合函数的字典仍然是执行聚合的完美方式

df.groupby('group').agg({'a':['sum', 'max'], 
                         'b':'mean', 
                         'c':'sum', 
                         'd': lambda x: x.max() - x.min()})

              a                   b         c         d
            sum       max      mean       sum  <lambda>
group                                                  
0      0.864569  0.446069  0.466054  0.969921  0.341399
1      1.478872  0.843026  0.687672  1.754877  0.672401

使用
apply
并返回序列 现在,如果有多个列需要一起交互,那么就不能使用
agg
,它会隐式地将一个序列传递给聚合函数。使用
apply
时,将整个组作为数据帧传递到函数中

我建议创建一个自定义函数,返回一系列的所有聚合。将系列索引用作新列的标签:

def f(x):
    d = {}
    d['a_sum'] = x['a'].sum()
    d['a_max'] = x['a'].max()
    d['b_mean'] = x['b'].mean()
    d['c_d_prodsum'] = (x['c'] * x['d']).sum()
    return pd.Series(d, index=['a_sum', 'a_max', 'b_mean', 'c_d_prodsum'])

df.groupby('group').apply(f)

         a_sum     a_max    b_mean  c_d_prodsum
group                                           
0      0.864569  0.446069  0.466054     0.173711
1      1.478872  0.843026  0.687672     0.630494
如果您喜欢多索引,您仍然可以返回一个包含以下内容的系列:

def max_min(x):
    return x.max() - x.min()

max_min.__name__ = 'Max minus Min'

df.groupby('group').agg({'a':['sum', 'max'], 
                         'b':'mean', 
                         'c':'sum', 
                         'd': max_min})

              a                   b         c             d
            sum       max      mean       sum Max minus Min
group                                                      
0      0.864569  0.446069  0.466054  0.969921      0.341399
1      1.478872  0.843026  0.687672  1.754877      0.672401
    def f_mi(x):
        d = []
        d.append(x['a'].sum())
        d.append(x['a'].max())
        d.append(x['b'].mean())
        d.append((x['c'] * x['d']).sum())
        return pd.Series(d, index=[['a', 'a', 'b', 'c_d'], 
                                   ['sum', 'max', 'mean', 'prodsum']])

df.groupby('group').apply(f_mi)

              a                   b       c_d
            sum       max      mean   prodsum
group                                        
0      0.864569  0.446069  0.466054  0.173711
1      1.478872  0.843026  0.687672  0.630494

目前被接受的答案的后半部分已经过时,并且有两个反对意见。首先也是最重要的一点,您不能再将字典字典传递给
agg
groupby方法。第二,永远不要使用
.ix

如果希望同时处理两个单独的列,我建议使用
apply
方法,该方法隐式地将数据帧传递给应用的函数。让我们使用与上面的数据帧类似的数据帧

df = pd.DataFrame(np.random.rand(4,4), columns=list('abcd'))
df['group'] = [0, 0, 1, 1]
df

          a         b         c         d  group
0  0.418500  0.030955  0.874869  0.145641      0
1  0.446069  0.901153  0.095052  0.487040      0
2  0.843026  0.936169  0.926090  0.041722      1
3  0.635846  0.439175  0.828787  0.714123      1
从列名映射到聚合函数的字典仍然是执行聚合的完美方式

df.groupby('group').agg({'a':['sum', 'max'], 
                         'b':'mean', 
                         'c':'sum', 
                         'd': lambda x: x.max() - x.min()})

              a                   b         c         d
            sum       max      mean       sum  <lambda>
group                                                  
0      0.864569  0.446069  0.466054  0.969921  0.341399
1      1.478872  0.843026  0.687672  1.754877  0.672401

使用
apply
并返回序列 现在,如果有多个列需要一起交互,那么就不能使用
agg
,它会隐式地将一个序列传递给聚合函数。使用
apply
时,将整个组作为数据帧传递到函数中

我建议创建一个自定义函数,返回一系列的所有聚合。将系列索引用作新列的标签:

def f(x):
    d = {}
    d['a_sum'] = x['a'].sum()
    d['a_max'] = x['a'].max()
    d['b_mean'] = x['b'].mean()
    d['c_d_prodsum'] = (x['c'] * x['d']).sum()
    return pd.Series(d, index=['a_sum', 'a_max', 'b_mean', 'c_d_prodsum'])

df.groupby('group').apply(f)

         a_sum     a_max    b_mean  c_d_prodsum
group                                           
0      0.864569  0.446069  0.466054     0.173711
1      1.478872  0.843026  0.687672     0.630494
如果您喜欢多索引,您仍然可以返回一个包含以下内容的系列:

def max_min(x):
    return x.max() - x.min()

max_min.__name__ = 'Max minus Min'

df.groupby('group').agg({'a':['sum', 'max'], 
                         'b':'mean', 
                         'c':'sum', 
                         'd': max_min})

              a                   b         c             d
            sum       max      mean       sum Max minus Min
group                                                      
0      0.864569  0.446069  0.466054  0.969921      0.341399
1      1.478872  0.843026  0.687672  1.754877      0.672401
    def f_mi(x):
        d = []
        d.append(x['a'].sum())
        d.append(x['a'].max())
        d.append(x['b'].mean())
        d.append((x['c'] * x['d']).sum())
        return pd.Series(d, index=[['a', 'a', 'b', 'c_d'], 
                                   ['sum', 'max', 'mean', 'prodsum']])

df.groupby('group').apply(f_mi)

              a                   b       c_d
            sum       max      mean   prodsum
group                                        
0      0.864569  0.446069  0.466054  0.173711
1      1.478872  0.843026  0.687672  0.630494

泰德的回答令人惊讶。最后我用了一个更小的版本,以防有人感兴趣。查找一个依赖于多列值的聚合时非常有用:

创建一个数据帧 使用apply进行分组和聚合(使用多列) 使用聚合进行分组和聚合(使用多列) 我喜欢这种方法,因为我仍然可以使用聚合。也许人们会让我知道,在对组进行聚合时,为什么需要apply来获取多个列

现在看起来很明显,但只要不直接在groupby之后选择感兴趣的列,就可以从聚合函数中访问数据帧的所有列

仅访问选定列 访问所有列,因为选择毕竟是神奇的 或者类似地
我希望这能有所帮助。

特德的回答令人惊讶。最后我用了一个更小的版本,以防有人感兴趣。查找一个依赖于多列值的聚合时非常有用:

创建一个数据帧 使用apply进行分组和聚合(使用多列) 使用聚合进行分组和聚合(使用多列) 我喜欢这种方法,因为我仍然可以使用聚合。也许人们会让我知道,在对组进行聚合时,为什么需要apply来获取多个列

现在看起来很明显,但只要不直接选择感兴趣的列
import numpy as np
np.random.seed(42)
df = pd.DataFrame(np.random.rand(4,4), columns=list('abcd'))
df['group'] = [0, 0, 1, 1]
df

          a         b         c         d  group
0  0.374540  0.950714  0.731994  0.598658      0
1  0.156019  0.155995  0.058084  0.866176      0
2  0.601115  0.708073  0.020584  0.969910      1
3  0.832443  0.212339  0.181825  0.183405      1
df = pd.DataFrame(np.random.rand(4,4), columns=list('abcd'))
df['group'] = [0, 0, 1, 1]

          a         b         c         d  group
0  0.521279  0.914988  0.054057  0.125668      0
1  0.426058  0.828890  0.784093  0.446211      0
2  0.363136  0.843751  0.184967  0.467351      1
3  0.241012  0.470053  0.358018  0.525032      1
df.groupby('group').agg(
             a_sum=('a', 'sum'),
             a_mean=('a', 'mean'),
             b_mean=('b', 'mean'),
             c_sum=('c', 'sum'),
             d_range=('d', lambda x: x.max() - x.min())
)

          a_sum    a_mean    b_mean     c_sum   d_range
group                                                  
0      0.947337  0.473668  0.871939  0.838150  0.320543
1      0.604149  0.302074  0.656902  0.542985  0.057681
>>> animals = pd.DataFrame({
...     'kind': ['cat', 'dog', 'cat', 'dog'],
...     'height': [9.1, 6.0, 9.5, 34.0],
...     'weight': [7.9, 7.5, 9.9, 198.0]
... })

>>> print(animals)
  kind  height  weight
0  cat     9.1     7.9
1  dog     6.0     7.5
2  cat     9.5     9.9
3  dog    34.0   198.0

>>> print(
...     animals
...     .groupby('kind')
...     .agg(
...         min_height=pd.NamedAgg(column='height', aggfunc='min'),
...         max_height=pd.NamedAgg(column='height', aggfunc='max'),
...         average_weight=pd.NamedAgg(column='weight', aggfunc=np.mean),
...     )
... )
      min_height  max_height  average_weight
kind                                        
cat          9.1         9.5            8.90
dog          6.0        34.0          102.75
>>> print(
...     animals
...     .groupby('kind')
...     .agg(
...         min_height=('height', 'min'),
...         max_height=('height', 'max'),
...         average_weight=('weight', np.mean),
...     )
... )
      min_height  max_height  average_weight
kind                                        
cat          9.1         9.5            8.90
dog          6.0        34.0          102.75
>>> print(
...     animals
...     .groupby('kind')
...     .height
...     .agg(
...         min_height='min',
...         max_height='max',
...     )
... )
      min_height  max_height
kind                        
cat          9.1         9.5
dog          6.0        34.0
animals = pd.DataFrame({'kind': ['cat', 'dog', 'cat', 'dog'],
                         'height': [9.1, 6.0, 9.5, 34.0],
                         'weight': [7.9, 7.5, 9.9, 198.0]})
 
agg_dict = {
    "min_height": pd.NamedAgg(column='height', aggfunc='min'),
    "max_height": pd.NamedAgg(column='height', aggfunc='max'),
    "average_weight": pd.NamedAgg(column='weight', aggfunc=np.mean)
}

animals.groupby("kind").agg(**agg_dict)
      min_height  max_height  average_weight
kind                                        
cat          9.1         9.5            8.90
dog          6.0        34.0          102.75