0Pricing
Pandas & NumPy Academy · Lekcja

apply() z GroupBy

Przekaż funkcję działającą na wielu wierszach do groupby().apply(), aby obliczać złożone podsumowania grup, których nie da się wyrazić za pomocą agg().

apply() z GroupBy to bezpłatna lekcja Pandas & NumPy Academy na CoddyKit. To lekcja 2 z 4. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej Pandas & NumPy Academy, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs Pandas & NumPy Academy zawiera 4 lekcji w sumie.

Dlaczego GroupBy potrzebuje apply()

Wbudowana metoda agg() obsługuje proste agregacje, takie jak suma, średnia i liczność — zwracając jedną wartość skalarną dla każdej grupy. Niektóre obliczenia na poziomie grup wymagają jednak przeanalizowania całej ramki danych będącej podramką danej grupy, a nie tylko pojedynczej kolumny. groupby().apply(func) przekazuje do funkcji pełną ramkę danych grupy i zbiera wyniki, umożliwiając tworzenie złożonych podsumowań, których nie da się wyrazić za pomocą agg().

import pandas as pd
import numpy as np

df = pd.DataFrame({
    'region': ['North', 'North', 'South', 'South', 'North'],
    'product': ['A', 'B', 'A', 'A', 'C'],
    'revenue': [100, 250, 180, 90, 300]
})
print(df)

Zwracanie wartości skalarnej dla każdej grupy

Gdy funkcja przekazana do groupby().apply() zwraca wartość skalarną, wynikiem jest Series indeksowana kluczami grup — identyczna z wynikiem agg(). Ta forma jest przydatna, gdy obliczenie wartości skalarnej wymaga użycia wielu kolumn, na przykład obliczenia stosunku przychodu z najlepiej sprzedającego się produktu do całkowitego przychodu grupy, czego nie da się wyrazić w pojedynczej specyfikacji kolumny agg().

def top_product_share(group):
    top = group['revenue'].max()
    total = group['revenue'].sum()
    return top / total

share = df.groupby('region').apply(top_product_share)
print(share)

Zwracanie Series dla każdej grupy

Gdy funkcja zwraca pd.Series, wynik ma MultiIndex: poziom zewnętrzny zawiera klucz grupy, a poziom wewnętrzny — indeks Series. Jest to przydatne do obliczania wielu statystyk dla każdej grupy w jednym wywołaniu apply, co pozwala utworzyć tabelę podsumowania, w której każda grupa ma wiele wierszy z metrykami.

def group_stats(group):
    return pd.Series({
        'total': group['revenue'].sum(),
        'top_product': group.loc[group['revenue'].idxmax(), 'product'],
        'n_products': group['product'].nunique()
    })

result = df.groupby('region').apply(group_stats)
print(result)

Zwracanie DataFrame dla każdej grupy

Gdy funkcja zwraca pd.DataFrame, groupby().apply() łączy wszystkie podramki danych grup pionowo. To najbardziej wszechstronna forma: pozwala filtrować lub przekształcać wiersze w obrębie każdej grupy i zwracać zmodyfikowany podzbiór. Można na przykład zachować tylko 2 najlepiej sprzedające się produkty pod względem przychodu w każdym regionie.

def top2_per_region(group):
    return group.nlargest(2, 'revenue')

top2 = df.groupby('region').apply(top2_per_region)
print(top2.reset_index(drop=True))

Obliczanie wyników standaryzowanych Z w obrębie grup

Częstym zastosowaniem groupby().apply() jest standaryzacja w obrębie grup. Zamiast normalizować przychód względem wszystkich zamówień, co miesza regiony, należy obliczyć wynik Z przychodu osobno dla każdego regionu. Wynik Z równy 2 w regionie North oznacza „2 odchylenia standardowe powyżej średniej dla regionu North” — jest to bardziej miarodajny punkt odniesienia niż 2 odchylenia standardowe powyżej średniej globalnej.

def within_group_zscore(group):
    mean = group['revenue'].mean()
    std = group['revenue'].std()
    group = group.copy()
    group['revenue_z'] = (group['revenue'] - mean) / std
    return group

df_z = df.groupby('region').apply(within_group_zscore).reset_index(drop=True)
print(df_z)

Niestandardowa agregacja: średnia winsoryzowana

Średnia winsoryzowana ogranicza wpływ wartości skrajnych przed obliczeniem średniej, dzięki czemu jest odporniejsza niż zwykła średnia w przypadku rozkładów skośnych. Tej niestandardowej agregacji nie da się wyrazić za pomocą standardowych funkcji agg(), ale można ją łatwo wykonać za pomocą groupby().apply(): ograniczyć wartości do 5. i 95. percentyla w obrębie każdej grupy, a następnie obliczyć średnią dla tak przekształconych wartości.

def winsorised_mean(group, lower_pct=0.05, upper_pct=0.95):
    col = group['revenue']
    lo = col.quantile(lower_pct)
    hi = col.quantile(upper_pct)
    clipped = col.clip(lo, hi)
    return clipped.mean()

wins_mean = df.groupby('region').apply(winsorised_mean)
print('Winsorised mean by region:')
print(wins_mean)

Niestandardowe okno kroczące dla każdej grupy

Okna kroczące zastosowane do całej ramki danych ignorują granice grup. Jeśli obliczą Państwo 3-wierszową średnią kroczącą dla szeregu czasowego, w którym przeplatają się dane dwóch produktów, okno nieprawidłowo przekroczy granice produktów. Należy zastosować okno kroczące wewnątrz groupby().apply(), aby zapewnić wykonywanie każdego obliczenia wyłącznie w obrębie jego grupy — na przykład obliczyć 3-miesięczną kroczącą średnią przychodu dla każdego regionu.

def group_rolling_mean(group, window=3):
    group = group.sort_values('order_date').copy()
    group['rolling_revenue'] = group['revenue'].rolling(window, min_periods=1).mean()
    return group

# df_ts has order_date column
# df_rolled = df_ts.groupby('region').apply(group_rolling_mean).reset_index(drop=True)
print('Rolling window per group applied inside apply()')

Parametr include_groups (Pandas 2.2+)

W Pandas 2.2 i nowszych groupby().apply() zgłasza FutureWarning, jeśli klucze grupowania pojawiają się w ramce danych otrzymywanej przez funkcję. Należy przekazać include_groups=False, aby wykluczyć kolumny grupowania z podramki danych przekazywanej do funkcji. Pozwala to uniknąć zarówno ostrzeżenia, jak i przypadkowych operacji na kolumnach zawierających klucze wewnątrz ciała funkcji.

def revenue_only(group):
    # group does not include 'region' column when include_groups=False
    return group['revenue'].sum()

# result = df.groupby('region').apply(revenue_only, include_groups=False)
print('include_groups=False avoids FutureWarning in Pandas 2.2+')

Łączenie wyników apply() za pomocą reset_index

Gdy groupby().apply() zwraca DataFrame dla każdej grupy, wynik ma MultiIndex, którego zewnętrzny poziom zawiera klucz grupy. Należy użyć reset_index(drop=True), aby spłaszczyć indeks do zwykłego zakresu liczb całkowitych. Alternatywnie można użyć reset_index(level=0), aby przenieść klucz grupy do kolumny i wyraźnie uwzględnić go w wynikach.

result = df.groupby('region').apply(top2_per_region)
print('With MultiIndex:')
print(result.head())

print('\nAfter reset_index:')
print(result.reset_index(drop=True))

Kiedy zamiast apply() wybrać transform()

groupby().apply() służy do złożonych obliczeń na poziomie grup, które zwracają dane o innym kształcie niż dane wejściowe. groupby().transform() służy do obliczeń dodających nową kolumnę zgodną z oryginalnym indeksem — na przykład do rozpropagowania średniej grupy z powrotem do każdego wiersza w celu normalizacji. Należy użyć transform, gdy wynik ma mieć taki sam kształt jak oryginalna DataFrame, a apply, gdy kształt wyniku jest inny.

# transform: adds group mean back to each row
df['group_mean_revenue'] = df.groupby('region')['revenue'].transform('mean')

# apply: computes one scalar per group
group_totals = df.groupby('region')['revenue'].apply(sum)

print(df[['region', 'revenue', 'group_mean_revenue']])

Wskazówka dotycząca wydajności: unikanie apply() dla prostych agregacji

groupby().apply() jest znacznie wolniejsze niż groupby().agg() w przypadku prostych operacji, ponieważ apply() tworzy pełny obiekt Python dla każdej grupy. Dla sum, średnich i liczności należy zawsze używać agg(). Po apply() należy sięgać w sytuacjach, które rzeczywiście wymagają pełnej ramki danych grupy — przy warunkowej logice obejmującej wiele kolumn, niestandardowych statystykach lub filtrowaniu wewnątrz grup.

# SLOW: apply for simple sum
slow = df.groupby('region').apply(lambda g: g['revenue'].sum())

# FAST: native agg
fast = df.groupby('region')['revenue'].sum()

print('Both produce the same result:')
print(fast.equals(slow))

Szybkie sprawdzenie

Sprawdź swoją wiedzę na temat analizy danych z tej lekcji.

Podsumowanie lekcji

W tej lekcji nauczyli się Państwo: zwracać wartości skalarne, Series i DataFrame z użyciem groupby().apply(), obliczać wyniki Z w obrębie grup oraz niestandardowe odporne statystyki i wybierać między apply(), agg() a transform() do operacji na poziomie grup. Następnie omówimy map() i applymap() do operacji na poszczególnych elementach Series i DataFrame.

Często zadawane pytania

Czy lekcja „apply() z GroupBy” jest bezpłatna?

Tak — pełny tekst „apply() z GroupBy” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu Pandas & NumPy Academy, przejdź na CoddyKit PRO. Kurs Pandas & NumPy Academy zawiera 4 lekcji w sumie.

Co nauczysz się w „apply() z GroupBy”?

Przekaż funkcję działającą na wielu wierszach do groupby().apply(), aby obliczać złożone podsumowania grup, których nie da się wyrazić za pomocą agg(). Ćwiczysz Pandas & NumPy Academy z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.

Czy potrzebuję doświadczenia, aby zacząć Pandas & NumPy Academy?

Nie wymagamy żadnego doświadczenia. Pandas & NumPy Academy w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 2 z 4.

Ile czasu zajmuje lekcja „apply() z GroupBy”?

Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.

Czy mogę pisać i uruchamiać kod w tej lekcji Pandas & NumPy Academy?

Tak. Każda lekcja Pandas & NumPy Academy zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.

Wszystkie lekcje w tym kursie

  1. apply() dla kolumn i wierszy
  2. apply() z GroupBy
  3. map() i applymap() do operacji elementowych
  4. Łańcuchowe wywoływanie metod z pipe()
← Powrót do Pandas & NumPy Academy