groupby().transform() în pandas

Grupare și agregare pandas 1.0+

Calculează o valoare pe grup (suma, media) și o pune înapoi pe fiecare rând, ca să o poți folosi ca o coloană nouă.

Sintaxă
df.groupby(chei)[coloana].transform(func, *args, **kwargs)

Ce face groupby().transform()

agg() reduce fiecare grup la un singur rând. transform() calculează același lucru, dar returnează un rezultat de aceeași lungime ca tabelul inițial: fiecare rând primește valoarea grupului lui. De aceea rezultatul se poate pune direct într-o coloană nouă.

Folosiri obișnuite: procentul pe care îl are fiecare vânzare din totalul orașului, diferența dintre nota unui elev și media clasei, sau completarea valorilor lipsă cu media grupului.

Funcția poate fi un nume ("sum", "mean", "count", "max") sau o funcție care primește o serie și întoarce o serie de aceeași lungime ori o singură valoare.

Parametri

Parametru Descriere
func Funcția aplicată fiecărui grup: un șir ("sum", "mean", "rank", "cumsum") sau o funcție Python.
*args, **kwargs Argumente transmise mai departe funcției.

Ce returnează

O Series (sau un DataFrame) cu același index ca datele inițiale, deci se aliniază rând cu rând cu tabelul.

Exemple

Exemplul 1: Procentul fiecărei vânzări din totalul orașului

transform("sum") pune totalul orașului pe fiecare rând. Împărțind suma la el obții procentul. În Iași, 1200 din 1950 lei înseamnă 61,5%.

import pandas as pd

df = pd.DataFrame({
    "oras": ["Iași", "Cluj", "Iași", "Cluj", "Iași"],
    "vanzator": ["Ana", "Mihai", "Ioana", "Elena", "Radu"],
    "suma": [1200, 800, 450, 1200, 300],
})

df["total_oras"] = df.groupby("oras")["suma"].transform("sum")
df["procent"] = (df["suma"] / df["total_oras"] * 100).round(1)
print(df)

Rezultat

   oras vanzator  suma  total_oras  procent
0  Iași      Ana  1200        1950     61.5
1  Cluj    Mihai   800        2000     40.0
2  Iași    Ioana   450        1950     23.1
3  Cluj    Elena  1200        2000     60.0
4  Iași     Radu   300        1950     15.4

Exemplul 2: Diferența față de media clasei

Media clasei 9A este 8, iar a clasei 9B este 7. Scăzând media grupului vezi cine e peste sau sub media clasei lui.

import pandas as pd

df = pd.DataFrame({
    "elev": ["Ana", "Mihai", "Ioana", "Radu", "Elena", "Dan"],
    "clasa": ["9A", "9A", "9A", "9B", "9B", "9B"],
    "nota": [9, 7, 8, 6, 8, 7],
})

media = df.groupby("clasa")["nota"].transform("mean")
df["fata_de_medie"] = df["nota"] - media
print(df)

Rezultat

    elev clasa  nota  fata_de_medie
0    Ana    9A     9            1.0
1  Mihai    9A     7           -1.0
2  Ioana    9A     8            0.0
3   Radu    9B     6           -1.0
4  Elena    9B     8            1.0
5    Dan    9B     7            0.0

Exemplul 3: Completarea notelor lipsă cu media clasei

Rezultatul lui transform are aceeași lungime ca tabelul, deci poate fi dat lui fillna(): fiecare valoare lipsă primește media clasei ei.

import pandas as pd

df = pd.DataFrame({
    "elev": ["Ana", "Mihai", "Ioana", "Radu", "Elena"],
    "clasa": ["9A", "9A", "9B", "9B", "9B"],
    "nota": [9.0, None, 6.0, None, 8.0],
})

media_clasei = df.groupby("clasa")["nota"].transform("mean")
df["nota"] = df["nota"].fillna(media_clasei)
print(df)

Rezultat

    elev clasa  nota
0    Ana    9A   9.0
1  Mihai    9A   9.0
2  Ioana    9B   6.0
3   Radu    9B   7.0
4  Elena    9B   8.0

Greșeli frecvente

  • Folosești agg("sum") și încerci să-l pui ca o coloană nouă: rezultatul are un rând pe grup, nu pe rând, iar coloana iese plină de NaN. Pentru o valoare pe fiecare rând ai nevoie de transform.
  • Dai lui transform o funcție care întoarce o serie de altă lungime (de exemplu filtrează valori). Funcția trebuie să întoarcă o valoare sau o serie de aceeași lungime ca grupul.
  • Aplici transform pe tot grupul (df.groupby("clasa").transform("mean")) când ai și coloane de text: media pe text dă eroare. Alege întâi coloana: ["nota"].

Comenzi înrudite

  • DataFrame.groupby(): Împarte tabelul în grupuri după una sau mai multe coloane, ca să calculezi totaluri, medii sau numărări pentru fiecare grup.
  • agg() / aggregate(): Aplică mai multe funcții de agregare deodată, diferite pe coloane, cu nume alese de tine pentru coloanele rezultatului.
  • fillna() / ffill() / bfill(): Completează valorile lipsă cu o valoare fixă, cu valori diferite pe coloane, cu media sau cu valoarea anterioară ori următoare.
  • DataFrame.assign() și coloane noi: Adaugă coloane calculate: df[„col”] = … modifică tabelul, iar assign() returnează un tabel nou și acceptă funcții lambda.