Python 将多个函数应用于多个groupby列
演示如何使用以输出列名为键的dict一次在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
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