W docs pokazują, jak zastosować wiele funkcji w obiekcie GroupBy naraz przy użyciu dict z nazwami kolumn wyjście jako klucze:
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
Działa to jednak tylko na obiekcie Groupby według grup. Kiedy podobnie dyktafon jest przekazywany do grupy przez DataFrame, oczekuje, że kluczami będą nazwy kolumn, do których funkcja zostanie zastosowana.
Chcę zastosować wiele funkcji do kilku kolumn (ale niektóre kolumny będą obsługiwane wielokrotnie). Ponadto niektóre funkcje będą zależeć od innych kolumn w obiekcie grupowania (takich jak funkcje sumif). Moje obecne rozwiązanie polega na przechodzeniu kolumna po kolumnie i robieniu czegoś podobnego do powyższego kodu, używając lambdas dla funkcji zależnych od innych wierszy. Ale zajmuje to dużo czasu (myślę, że iteracja przez obiekt grupujący zajmuje dużo czasu). Będę musiał to zmienić, aby w jednym przebiegu iterować cały obiekt grupujący według jednego obiektu, ale zastanawiam się, czy w pandach nie ma wbudowanego sposobu, aby zrobić to nieco czysto.
Na przykład próbowałem czegoś takiego
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(), ...)
ale zgodnie z oczekiwaniami otrzymuję KeyError (ponieważ klucze muszą być kolumną, jeśli agg
są wywoływane z DataFrame).
Czy istnieje jakiś sposób na wykonanie tego, co chciałbym zrobić, lub możliwość dodania tej funkcji, czy też będę musiał po prostu ręcznie iterować w grupie?
Dzięki
Odpowiedzi:
Druga połowa obecnie akceptowanej odpowiedzi jest nieaktualna i ma dwie przestarzałe treści. Po pierwsze i najważniejsze, nie można już przekazać słownika słowników do
agg
metody grupowania. Po drugie, nigdy nie używaj.ix
.Jeśli chcesz pracować z dwiema osobnymi kolumnami jednocześnie, sugerowałbym użycie
apply
metody, która domyślnie przekazuje ramkę danych do zastosowanej funkcji. Użyjmy podobnej ramki danych jak ta z górySłownik odwzorowany z nazw kolumn na funkcje agregujące jest wciąż doskonałym sposobem na agregację.
Jeśli nie podoba ci się ta brzydka nazwa kolumny lambda, możesz użyć normalnej funkcji i podać niestandardową nazwę dla specjalnego
__name__
atrybutu, takiego jak ten:Używanie
apply
i zwracanie seriiTeraz, jeśli masz wiele kolumn, które musiały ze sobą współdziałać, nie możesz ich użyć
agg
, co niejawnie przekazuje Serię do funkcji agregującej. Gdy używaszapply
całej grupy jako DataFrame, zostaje ona przekazana do funkcji.Zalecam utworzenie pojedynczej funkcji niestandardowej, która zwraca serię wszystkich agregacji. Użyj indeksu serii jako etykiet dla nowych kolumn:
Jeśli jesteś zakochany w MultiIndexes, nadal możesz zwrócić serię taką jak ta:
źródło
a
w grupie,0
czy to nie powinno być0.418500 + 0.446069 = 0.864569
? To samo dotyczy innych komórek, liczby nie wydają się sumować. Czy w kolejnych przykładach może być nieco inna podstawowa ramka danych?W pierwszej części możesz przekazać dyktę nazw kolumn dla kluczy i listę funkcji dla wartości:
AKTUALIZACJA 1:
Ponieważ funkcja agregująca działa w Serii, odwołania do innych nazw kolumn są tracone. Aby obejść ten problem, możesz odwołać się do pełnej ramki danych i zindeksować ją za pomocą indeksów grupy w funkcji lambda.
Oto hacky obejście:
Tutaj powstała kolumna „D” składa się ze zsumowanych wartości „E”.
AKTUALIZACJA 2:
Oto metoda, która moim zdaniem zrobi wszystko, o co poprosisz. Najpierw utwórz niestandardową funkcję lambda. Poniżej g odnosi się do grupy. Podczas agregacji g będzie serią. Przejście
g.index
dodf.ix[]
wybiera bieżącą grupę z df. Następnie sprawdzam, czy kolumna C jest mniejsza niż 0,5. Zwracana seria boolowska jest przekazywana dog[]
której wybiera tylko te wiersze, które spełniają kryteria.źródło
{funcname: func}
jako wartości zamiast list, aby zachować moje niestandardowe nazwy. Ale w obu przypadkach nie mogę przejść,lambda
który używa innych kolumn (jaklambda x: x['D'][x['C'] < 3].sum()
wyżej: „KeyError: 'D” ”). Masz pomysł, jeśli to możliwe?KeyError: 'D'
df['A'].ix[g.index][df['C'] < 0].sum()
. Zaczyna się to jednak robić dość niechlujnie - myślę, że ze względu na czytelność bardziej pożądane może być ręczne zapętlenie, a ponadto nie jestem pewien, czy istnieje sposób, aby nadać mu moją preferowaną nazwę wagg
argumencie (zamiast<lambda>
). Będę miał nadzieję, że ktoś może poznać prostszy sposób ...{'D': {'my name':lambda function}}
a to spowoduje, że wewnętrzny dykta wprowadzi nazwę kolumny.Jako alternatywę (głównie w zakresie estetyki) do odpowiedzi Teda Petrou, uznałem, że wolę nieco bardziej zwartą listę. Proszę nie rozważać akceptacji, to po prostu bardziej szczegółowy komentarz do odpowiedzi Teda oraz kod / dane. Python / pandy nie jest moim pierwszym / najlepszym, ale znalazłem to, aby dobrze czytać:
Uważam, że bardziej przypomina
dplyr
rury idata.table
powiązane łańcuchy poleceń. Nie mówiąc już, że są lepsze, po prostu bardziej mi znane. (Z pewnością doceniam siłę i, dla wielu, preferencję używania bardziej sformalizowanychdef
funkcji dla tego typu operacji. Jest to po prostu alternatywa, niekoniecznie lepsza.)Wygenerowałem dane w taki sam sposób jak Ted, dodam ziarno dla odtwarzalności.
źródło
Pandas >= 0.25.0
, nazwane agregacjeOd wersji pandy
0.25.0
lub wyższej odchodzimy od agregacji i zmiany nazw opartych na słowniku i przechodzimy w kierunku nazwanych agregacji, które akceptują atuple
. Teraz możemy jednocześnie agregować + zmienić nazwę na bardziej pouczającą nazwę kolumny:Przykład :
Zastosuj
GroupBy.agg
z nazwaną agregacją:źródło
Nowości w wersji 0.25.0.
Aby wesprzeć agregację specyficzną dla kolumny z kontrolą nazw kolumn wyjściowych, pandy akceptują specjalną składnię w GroupBy.agg () , znaną jako „agregacja nazwana” , gdzie
pandas.NamedAgg jest tylko imieniem. Krotki zwykłe są również dozwolone.
Dodatkowe argumenty słów kluczowych nie są przekazywane do funkcji agregujących. Tylko pary (column, aggfunc) powinny być przekazywane jako ** kwargs. Jeśli funkcje agregujące wymagają dodatkowych argumentów, częściowo zastosuj je za pomocą funkcji funools.partial ().
Nazwana agregacja obowiązuje również w przypadku agregacji grupowych według serii. W tym przypadku nie ma wyboru kolumny, więc wartości są tylko funkcjami.
źródło
Odpowiedź Teda jest niesamowita. Skończyło się na użyciu mniejszej wersji tego na wypadek, gdyby ktoś był zainteresowany. Przydatne, gdy szukasz jednej agregacji, która zależy od wartości z wielu kolumn:
utwórz ramkę danych
grupowanie i agregowanie z zastosowaniem (za pomocą wielu kolumn)
grupowanie i agregowanie za pomocą agregacji (przy użyciu wielu kolumn)
Podoba mi się to podejście, ponieważ nadal mogę używać agregacji. Być może ludzie poinformują mnie, dlaczego zastosowanie jest konieczne, aby uzyskać dostęp do wielu kolumn podczas agregacji na grupach.
Teraz wydaje się to oczywiste, ale dopóki nie wybierzesz interesującej kolumny bezpośrednio po grupie , będziesz mieć dostęp do wszystkich kolumn ramki danych z poziomu funkcji agregacji.
tylko dostęp do wybranej kolumny
dostęp do wszystkich kolumn, ponieważ wybór jest przecież magią
lub podobnie
Mam nadzieję, że to pomoże.
źródło