В чем разница между функцией pandas agg и apply?

Я не могу понять разницу между .aggregate 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

Ответ 1

apply применяет функцию к каждой группе (ваши Species). Ваша функция возвращает 1, поэтому вы получаете 1 значение для каждой из 3 групп.

agg объединяет каждый столбец (функцию) для каждой группы, поэтому вы agg одно значение для каждого столбца на группу.

groupby документы groupby, они очень полезны. Есть также куча учебников, плавающих вокруг Интернета.

Ответ 2

(Примечание. Эти сравнения актуальны для объектов DataframeGroupby)

Некоторые вероятные преимущества использования .agg() по сравнению с .apply(), для объектов DataFrame GroupBy :

  1. .agg() обеспечивает гибкость одновременного применения нескольких функций или передачи списка функций в каждый столбец.

  2. Кроме того, одновременно применяя разные функции к различным столбцам информационного кадра.

Это означает, что вы можете контролировать каждый столбец с каждой операцией.

Вот ссылка для более подробной информации: http://pandas.pydata.org/pandas-docs/version/0.13.1/groupby.html


Однако функция apply может быть ограничена применением одной функции к каждому столбцу кадра данных за раз. Поэтому вам, возможно, придется несколько раз вызывать функцию apply для вызова различных операций в одном и том же столбце.

Вот несколько примеров сравнений для .apply() и .agg() для объектов DataframeGroupBy:

С учетом следующего кадра данных:

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(). Но если вы обрабатываете только чистые объекты фрейма данных, а не объекты DataFrameGroupBy, то apply() может быть очень полезным, так как apply() может применять функцию вдоль любой оси фрейма данных.

(Например, axis = 0 подразумевает посимвольную работу с .apply(),, который является режимом по умолчанию, а axis = 1 подразумевает построчную работу при работе с объектами с чистыми данными).

Ответ 3

При использовании apply to groupby я обнаружил, что .apply возвращает сгруппированные столбцы. В документации есть примечание (pandas.pydata.org/pandas-docs/stable/groupby.html):

"... Таким образом, сгруппированные столбцы могут быть включены в вывод, а также установить индексы."

.aggregate не вернет сгруппированные столбцы.