Кілька агрегацій одного і того ж стовпця за допомогою pandas GroupBy.agg ()


127

Чи існує вбудований спосіб панд застосувати дві різні функції агрегування f1, f2до одного стовпця df["returns"], не потребуючи виклику agg()кілька разів?

Приклад фрейму даних:

import pandas as pd
import datetime as dt

pd.np.random.seed(0)
df = pd.DataFrame({
         "date"    :  [dt.date(2012, x, 1) for x in range(1, 11)], 
         "returns" :  0.05 * np.random.randn(10), 
         "dummy"   :  np.repeat(1, 10)
}) 

Синтаксично неправильний, але інтуїтивно правильний спосіб це зробити:

# Assume `f1` and `f2` are defined for aggregating.
df.groupby("dummy").agg({"returns": f1, "returns": f2})

Очевидно, Python не дозволяє повторювати ключі. Чи є якийсь інший спосіб висловлення вводу agg()? Можливо, список кортежів [(column, function)]буде працювати краще, щоб дозволити кілька функцій, застосованих до одного стовпця? Але agg()здається, що він приймає лише словник.

Чи існує вирішення цього питання, крім визначення допоміжної функції, яка просто застосовує обидві функції всередині неї? (Як це все-таки працюватиме з агрегуванням?)



2
З 0,25 і надалі панди надають більш інтуїтивний синтаксис для декількох агрегацій, а також перейменування вихідних стовпців. Дивіться документацію щодо названих агрегацій .
cs95

FYI це запитання було задано зворотним шляхом на пандах 0.8.x в 9/2012
smci

1
FYI прийнята відповідь також застаріла - не передайте agg () диктату диктів.
cs95

@ cs95: Я знаю, що це застаріло, я кажу, що SO стає засміченим старими устареними рішеннями від старих версій. Так що немає іншого способу маркування - крім коментарів.
smci

Відповіді:


159

Ви можете просто передати функції як список:

In [20]: df.groupby("dummy").agg({"returns": [np.mean, np.sum]})
Out[20]:         
           mean       sum
dummy                    
1      0.036901  0.369012

або як словник:

In [21]: df.groupby('dummy').agg({'returns':
                                  {'Mean': np.mean, 'Sum': np.sum}})
Out[21]: 
        returns          
           Mean       Sum
dummy                    
1      0.036901  0.369012

4
Чи є спосіб вказати назви стовпців результатів?
Бен

3
@Ben Я думаю, ви повинні використовувати перейменування після цього. приклад Тома Огшпургера (див. клітинку 25)
Стюбака

1
@Ben: Я додав приклад
bmu

10
@sparc_spread Передача декількох функцій у вигляді списку добре описана в документації на панди . Перейменування та передача декількох функцій у словник буде застарілою у майбутній версії панд. Деталі знаходяться в журналі змін 0,20 , який я також узагальнив в іншому місці про SO .
joelostblom

3
Про це вже говорилося, але використання словників для перейменування вихідних стовпців із віку застаріло. Ви можете замість цього вказати список кортежів. Дивіться цю відповідь.
cs95

101

TLDR; Pandas groupby.aggмає новий, простіший синтаксис для визначення (1) агрегації на декілька стовпців та (2) множинних агрегацій на стовпчику. Отже, щоб зробити це для панд> = 0,25 , використовуйте

df.groupby('dummy').agg(Mean=('returns', 'mean'), Sum=('returns', 'sum'))

           Mean       Sum
dummy                    
1      0.036901  0.369012

АБО

df.groupby('dummy')['returns'].agg(Mean='mean', Sum='sum')

           Mean       Sum
dummy                    
1      0.036901  0.369012

Панди> = 0,25: Названа агрегація

Pandas змінив поведінку GroupBy.aggна користь більш інтуїтивного синтаксису для визначення названих агрегацій. Дивіться розділ 0,25 Документів про вдосконалення , а також відповідні випуски GitHub GH18366 та GH26512 .

З документації,

Щоб підтримувати специфічну для стовпців агрегацію з керуванням вихідними іменами стовпців, панди приймає спеціальний синтаксис в GroupBy.agg(), відомий як "названа агрегація", де

  • Ключові слова - це вихідні назви стовпців
  • Значення - кортежі, першим елементом яких є стовпець для вибору, а другий елемент - це агрегація, що застосовується до цього стовпця. Pandas надає pandas.NamedAgg з именемtuple полями ['стовпець', 'aggfunc'], щоб зрозуміти, що таке аргументи. Як зазвичай, агрегація може бути псевдонімом, який можна називати або рядком.

Тепер ви можете передавати кортеж за допомогою аргументів ключових слів. Кортежі відповідають формату (<colName>, <aggFunc>).

import pandas as pd

pd.__version__                                                                                                                            
# '0.25.0.dev0+840.g989f912ee'

# Setup
df = 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]
})

df.groupby('kind').agg(
    max_height=('height', 'max'), min_weight=('weight', 'min'),)

      max_height  min_weight
kind                        
cat          9.5         7.9
dog         34.0         7.5

Крім того, ви можете використовувати pd.NamedAgg(по суті, nametuple), що робить речі більш явними.

df.groupby('kind').agg(
    max_height=pd.NamedAgg(column='height', aggfunc='max'), 
    min_weight=pd.NamedAgg(column='weight', aggfunc='min')
)

      max_height  min_weight
kind                        
cat          9.5         7.9
dog         34.0         7.5

Це ще простіше для Series, просто передайте aggfunc аргументу ключового слова.

df.groupby('kind')['height'].agg(max_height='max', min_height='min')    

      max_height  min_height
kind                        
cat          9.5         9.1
dog         34.0         6.0       

Нарешті, якщо назви стовпців не є дійсними ідентифікаторами пітона, використовуйте словник з розпакуванням:

df.groupby('kind')['height'].agg(**{'max height': 'max', ...})

Панди <0,25

У останніх версіях панд, що ведуть до 0,24, якщо ви використовуєте словник для визначення назв стовпців для виведення агрегації, ви отримаєте FutureWarning:

df.groupby('dummy').agg({'returns': {'Mean': 'mean', 'Sum': 'sum'}})
# FutureWarning: using a dict with renaming is deprecated and will be removed 
# in a future version

Використання словника для перейменування стовпців застаріло в v0.20. У останніх версіях панд це можна визначити простіше, передавши список кортежів. Якщо вказати функції таким чином, всі функції для цього стовпця потрібно вказати як кортежі пар (ім'я, функція).

df.groupby("dummy").agg({'returns': [('op1', 'sum'), ('op2', 'mean')]})

        returns          
            op1       op2
dummy                    
1      0.328953  0.032895

Або,

df.groupby("dummy")['returns'].agg([('op1', 'sum'), ('op2', 'mean')])

            op1       op2
dummy                    
1      0.328953  0.032895

4
Це має бути головною відповіддю через використання більш чіткого та чистого рішення з використанням нової версії інтерфейсу.
NKSHELL

Приклади, які використовуються для іменованої агрегації, не вирішують початкової проблеми використання декількох агрегацій в одному стовпчику. Наприклад, чи можете ви об'єднати як мінімум, так і макс для висоти без першого підмноження df.groupby('kind')['height']?
переможець

1
@victor Я додав TLDR у верхній частині відповіді, яка безпосередньо стосується питання. І відповідь на ваше друге запитання - так, будь ласка, подивіться на редагування моєї відповіді.
cs95

Більш загальний код останнього прикладу вашої відповіді> = 0,25 для обробки агрегування кількох стовпців, як це було б чудово. df.groupby("kind").agg(**{ 'max height': pd.NamedAgg(column='height', aggfunc=max), 'min weight': pd.NamedAgg(column='weight', aggfunc=min) })
Онур Еце

6

Чи хотілося б щось подібне:

In [7]: df.groupby('dummy').returns.agg({'func1' : lambda x: x.sum(), 'func2' : lambda x: x.prod()})
Out[7]: 
              func2     func1
dummy                        
1     -4.263768e-16 -0.188565

2
Ні, це не працює. Якщо ви подивитеся на рядок doc, aggregateвін прямо говорить про те, що при dictпередачі a , ключі повинні бути назви стовпців. Отже, або ваш приклад - це те, що ви ввели, не перевіряючи на цю помилку, або в іншому випадку Pandas розбиває тут свої власні документи.
ely

Додаткові дзвінки returnsтуди не переглядали. Так це серія версія агрегату? Я хочу зробити версію агрегату DataFrame, і я хочу застосувати декілька різних агрегацій до кожного стовпця одночасно.
ely

1
Спробуйте це: df.groupby ('манекен'). Agg ({'return': {'func1': lambda x: x.sum (), 'func2': lambda x: x.mean ()}})
Chang Вона

Це дає помилку твердження без повідомлення. З вигляду коду (pandas.core.internals.py, рядки 406-408, версія 0.7.3) схоже, він робить перевірку в кінці, щоб переконатися, що він не повертає більше стовпців, ніж є ключі в першому шар словника агрегації.
ely

Добре працює на майстра. Ви хочете спробувати оновити?
Chang She
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.