Pandas的agg和apply函数有什么区别?

66
我搞不清楚Pandas的.aggregate和.apply函数之间的区别。 以以下为例:我加载一个数据集,进行groupby操作,定义一个简单的函数, 然后使用.agg或.apply函数。
正如你所看到的,我函数内的打印语句在使用.agg和.apply后产生相同的输出。 然而,结果却不同。为什么会这样呢?
import pandas
import pandas as pd
iris = pd.read_csv('iris.csv')
by_species = iris.groupby('Species')
def f(x):
    ...:     print type(x)
    ...:     print x.head(3)
    ...:     return 1

使用apply
by_species.apply(f)
#<class 'pandas.core.frame.DataFrame'>
#   Sepal.Length  Sepal.Width  Petal.Length  Petal.Width Species
#0           5.1          3.5           1.4          0.2  setosa
#1           4.9          3.0           1.4          0.2  setosa
#2           4.7          3.2           1.3          0.2  setosa
#<class 'pandas.core.frame.DataFrame'>
#   Sepal.Length  Sepal.Width  Petal.Length  Petal.Width Species
#0           5.1          3.5           1.4          0.2  setosa
#1           4.9          3.0           1.4          0.2  setosa
#2           4.7          3.2           1.3          0.2  setosa
#<class 'pandas.core.frame.DataFrame'>
#    Sepal.Length  Sepal.Width  Petal.Length  Petal.Width     Species
#50           7.0          3.2           4.7          1.4  versicolor
#51           6.4          3.2           4.5          1.5  versicolor
#52           6.9          3.1           4.9          1.5  versicolor
#<class 'pandas.core.frame.DataFrame'>
#     Sepal.Length  Sepal.Width  Petal.Length  Petal.Width    Species
#100           6.3          3.3           6.0          2.5  virginica
#101           5.8          2.7           5.1          1.9  virginica
#102           7.1          3.0           5.9          2.1  virginica
#Out[33]: 
#Species
#setosa        1
#versicolor    1
#virginica     1
#dtype: int64

使用agg
by_species.agg(f)
#<class 'pandas.core.frame.DataFrame'>
#   Sepal.Length  Sepal.Width  Petal.Length  Petal.Width Species
#0           5.1          3.5           1.4          0.2  setosa
#1           4.9          3.0           1.4          0.2  setosa
#2           4.7          3.2           1.3          0.2  setosa
#<class 'pandas.core.frame.DataFrame'>
#    Sepal.Length  Sepal.Width  Petal.Length  Petal.Width     Species
#50           7.0          3.2           4.7          1.4  versicolor
#51           6.4          3.2           4.5          1.5  versicolor
#52           6.9          3.1           4.9          1.5  versicolor
#<class 'pandas.core.frame.DataFrame'>
#     Sepal.Length  Sepal.Width  Petal.Length  Petal.Width    Species
#100           6.3          3.3           6.0          2.5  virginica
#101           5.8          2.7           5.1          1.9  virginica
#102           7.1          3.0           5.9          2.1  virginica
#Out[34]: 
#           Sepal.Length  Sepal.Width  Petal.Length  Petal.Width
#Species                                                         
#setosa                 1            1             1            1
#versicolor             1            1             1            1
#virginica              1            1             1            1

2
尝试输入 help(by_species.agg) 然后输入 help(by_species.apply),看看它们的说明。 - Steve Barnes
6个回答

63

apply 函数对每个组(即你的 Species)应用函数。你的函数返回 1,因此你最终会得到每个组的一个值。

agg 函数对每个组的每一列(特征)进行聚合计算,因此你最终会得到每个组的每一列的一个值。

请务必阅读groupby文档,它们非常有帮助。网上也有许多教程可供参考。


8
因此,如果我想在整个组中使用我的 func,我应该选择 apply,如果针对每个组的单个 column,则 agg 是更好的选择。 - QM.py
但是似乎 by_species.apply(sum) 仍然会返回每个组的列的总和,而不是每个组中子数据帧的总和。 - undefined

38

(注意: 这些比较是与DataframeGroupby对象相关的)

使用.agg()相对于.apply(),对于DataFrame GroupBy 对象,有一些可行的优点

  1. .agg()提供了在一次操作中应用多个函数的灵活性,或将函数列表传递给每列。

  2. 另外,可以同时对数据帧的不同列应用不同的函数。

这意味着您可以通过每个操作来控制每个列。

以下是更多详细信息的链接:http://pandas.pydata.org/pandas-docs/version/0.13.1/groupby.html


然而,apply函数可能会被限制为一次仅对数据帧的每列应用一个函数。因此,您可能需要反复调用该函数来调用对同一列的不同操作。

以下是针对DataframeGroupBy对象的.apply() vs .agg()的一些示例比较:

给定以下数据框:

In [261]: df = pd.DataFrame({"name":["Foo", "Baar", "Foo", "Baar"], "score_1":[5,10,15,10], "score_2" :[10,15,10,25], "score_3" : [10,20,30,40]})

In [262]: df
Out[262]: 
   name  score_1  score_2  score_3
0   Foo        5       10       10
1  Baar       10       15       20
2   Foo       15       10       30
3  Baar       10       25       40

首先让我们看一下使用.apply()的操作:

In [263]: df.groupby(["name", "score_1"])["score_2"].apply(lambda x : x.sum())
Out[263]: 
name  score_1
Baar  10         40
Foo   5          10
      15         10
Name: score_2, dtype: int64

In [264]: df.groupby(["name", "score_1"])["score_2"].apply(lambda x : x.min())
Out[264]: 
name  score_1
Baar  10         15
Foo   5          10
      15         10
Name: score_2, dtype: int64

In [265]: df.groupby(["name", "score_1"])["score_2"].apply(lambda x : x.mean())
Out[265]: 
name  score_1
Baar  10         20.0
Foo   5          10.0
      15         10.0
Name: score_2, dtype: float64

现在,轻松使用 .agg() 进行相同的操作:

In [276]: df.groupby(["name", "score_1"]).agg({"score_3" :[np.sum, np.min, np.mean, np.max], "score_2":lambda x : x.mean()})
Out[276]: 
              score_2 score_3               
             <lambda>     sum amin mean amax
name score_1                                
Baar 10            20      60   20   30   40
Foo  5             10      10   10   10   10
     15            10      30   30   30   30

.agg()在处理DataFrameGroupBy对象时非常有用,相比之下,.apply()则更适合处理纯DataFrame对象。但是,如果您只处理纯DataFrame对象而不是DataFrameGroupBy对象,则apply()非常有用,因为apply()可以沿着数据框的任何轴应用函数。

(例如:axis = 0表示使用.apply()进行列操作,这是默认模式,而axis = 1会在处理纯DataFrame对象时表示进行行操作)。


1
另外,如果您需要一个函数同时访问多列数据,您可以使用apply函数。 - Allen Wang
1
请注意,agg() 也允许您选择一个轴。但是,OP 可能意味着 apply() 在选择一个或多个轴时提供更多的灵活性和控制。 - Federico Dorato

4
申请 (apply) 和聚合 (aggregate) 的主要区别是:
apply()- 
    cannot be applied to multiple groups together 
    For apply() - We have to get_group()
    ERROR : -iris.groupby('Species').apply({'Sepal.Length':['min','max'],'Sepal.Width':['mean','min']})# It will throw error
    Work Fine:-iris.groupby('Species').get_group('Setosa').apply({'Sepal.Length':['min','max'],'Sepal.Width':['mean','min']})# It will throw error
        #because functions are applied to one data frame

agg()- 
    can be applied to multiple groups together
    For apply() - We do not have to get_group() 
    iris.groupby('Species').agg({'Sepal.Length':['min','max'],'Sepal.Width':['mean','min']})
    iris.groupby('Species').get_group('versicolor').agg({'Sepal.Length':['min','max'],'Sepal.Width':['mean','min']})        

1
请参考此处。以下是同一声明的重新引述:

有些分组数据的操作可能不适合聚合或转换类别。或者,您可能只想让GroupBy推断如何组合结果。对于这些情况,请使用apply函数,它可以替代许多标准用例中的聚合和转换。但是,apply可以处理一些特殊的用例,例如:

有关示例的更多详细信息,请参见pandas文档(上面提供的链接)。

请参考@ted Petrou和@Eric O Lebigot的这篇优秀文章。我们可以重新应用他们使用的逻辑来研究Apply和Agg之间的差异。

然后,请参阅此链接以了解轴的工作原理。

这三个链接应该有助于更好地理解它们的区别。


0
使用apply对分组进行操作时,我发现.apply将返回分组列。文档(pandas.pydata.org/pandas-docs/stable/groupby.html)中有一个注释:

"...因此,分组的列也可以包含在输出中,并设置索引。"

而.aggregate则不会返回分组列。

0
除了其他提到的所有内容之外,我认为还没有人强调的另一个区别是apply可以用于将函数应用于一组列。Agg仅将函数分别应用于一列。例如:
让我们使用其他示例相同的示例:
d = pd.DataFrame({"name":["Foo", "Baar", "Foo", "Baar"], "score_1":[5,10,15,10], "score_2" :[10,15,10,25], "score_3" : [10,20,30,40]})
在这里,apply使用一个函数,将一组列的所有值相加。
d.groupby(["name", "score_1"]).apply(lambda x: x.values.sum())

目前你的回答不够清晰,请编辑并添加更多细节,以帮助其他人理解它如何回答问题。你可以在帮助中心找到有关如何撰写好答案的更多信息。 - Community

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接