Fungsi agregasi bawaan seperti sum(), mean(), dan count() menutup sebagian besar kebutuhan laporan, tetapi statistik bisnis sering berada di luarnya: rentang nilai terbesar–terkecil, koefisien variasi sebagai ukuran keragaman, atau kuantil 75% sebagai ambang harga premium. Chapter ini mengajarkan cara menulis fungsi agregasi sendiri, memasangkannya pada groupby().agg(), meneruskan argumen tambahan ke fungsi tersebut, dan memahami kontrak yang membuat pandas menerima atau menolak fungsi kita. Dataset transaksi 12 baris (tiga kota, nilai dalam ribu rupiah) dipakai di seluruh contoh.

Kontrak Fungsi Agregasi #

Aturan mainnya pendek: fungsi agregasi menerima satu Series berisi nilai satu kelompok dan wajib mengembalikan satu nilai skalar. pandas memanggil fungsi kita sekali per kelompok, mengumpulkan hasilnya, lalu menyusunnya menjadi satu baris per kelompok. Bila fungsi mengembalikan sesuatu yang bukan skalar, pandas menolaknya seperti terlihat pada blok terakhir script: ValueError: Must produce aggregated value. Kebutuhan “satu fungsi, banyak hasil” tetap mungkin — kembalikan beberapa nilai lewat beberapa fungsi, bukan satu fungsi yang mengembalikan Series. Untuk pola keluaran per-baris, transform() pada section Transformasi Data dan chapter transform() pada GroupBy adalah alat yang tepat, bukan agg().

Script berikut mendefinisikan tiga fungsi kustom, lalu memasangkannya dalam beberapa varian pemanggilan.

python
import pandas as pd
from functools import partial

transaksi = pd.DataFrame({
    "kota": ["Jakarta", "Jakarta", "Jakarta", "Jakarta",
             "Bandung", "Bandung", "Bandung",
             "Surabaya", "Surabaya", "Surabaya", "Surabaya", "Surabaya"],
    "produk": ["Kopi Gayo", "Teh Melati", "Minyak Goreng", "Beras Premium",
               "Kopi Gayo", "Gula Aren", "Beras Premium",
               "Kopi Gayo", "Teh Melati", "Minyak Goreng", "Gula Aren",
               "Beras Premium"],
    "nilai": [54, 24, 36, 68, 90, 21, 68, 45, 32, 27, 18, 73],
})

def rentang(s):
    """Selisih nilai maksimum dan minimum."""
    return s.max() - s.min()

def koef_variasi(s):
    """Simpangan baku dibagi rata-rata: ukuran keragaman relatif."""
    return s.std() / s.mean()

def kuantil(s, q):
    """Nilai pada kuantil q dari satu kelompok."""
    return s.quantile(q)

# satu fungsi kustom: nama Series hasil mengikuti kolom sumber
print(transaksi.groupby("kota")["nilai"].agg(rentang))
print()

# dua fungsi kustom dalam list: nama kolom diambil dari __name__
print(transaksi.groupby("kota")["nilai"].agg([rentang, koef_variasi]).round(4))
print()

# fungsi kustom menerima argumen tambahan langsung dari agg
print(transaksi.groupby("kota")["nilai"].agg(kuantil, q=0.75))
print()

# alternatif: bungkus argumen dengan functools.partial
print(transaksi.groupby("kota")["nilai"].agg(partial(kuantil, q=0.75)))
print()

# campuran fungsi bawaan dan kustom dalam named aggregation
laporan = transaksi.groupby("kota").agg(
    omzet=("nilai", "sum"),
    transaksi=("produk", "count"),
    keragaman=("nilai", koef_variasi),
)
print(laporan.round(4))
print()

# kontrak agregasi: fungsi wajib mengembalikan satu nilai
def ringkas(s):
    return pd.Series({"min": s.min(), "maks": s.max()})

try:
    transaksi.groupby("kota")["nilai"].agg(ringkas)
except ValueError as e:
    print("ValueError:", e)

Output yang Dihasilkan:

text
kota
Bandung     69
Jakarta     44
Surabaya    55
Name: nilai, dtype: int64

          rentang  koef_variasi
kota                           
Bandung        69        0.5907
Jakarta        44        0.4267
Surabaya       55        0.5478

kota
Bandung     79.0
Jakarta     57.5
Surabaya    45.0
Name: nilai, dtype: float64

kota
Bandung     79.0
Jakarta     57.5
Surabaya    45.0
Name: nilai, dtype: float64

          omzet  transaksi  keragaman
kota                                 
Bandung     179          3     0.5907
Jakarta     182          4     0.4267
Surabaya    195          5     0.5478

ValueError: Must produce aggregated value

Mari kita bedah bagian pentingnya:

  1. Baris 15-25 (definisi): setiap fungsi menerima parameter s (Series satu kelompok) dan mengembalikan satu angka; docstring pendek menjelaskan maksudnya bagi pembaca kode.
  2. Baris 28 (agg(rentang)): satu fungsi kustom pada SeriesGroupBy menghasilkan Series hasil; nama kolomnya tetap nilai karena hanya ada satu fungsi.
  3. Baris 32 (list dua fungsi): saat beberapa fungsi dipakai bersama, pandas menamai kolom hasil dari atribut __name__ masing-masing fungsi, yaitu rentang dan koef_variasi; label <lambda_0> tidak muncul karena kita memakai fungsi bernama.
  4. Baris 36 dan 40 (kwargs dan partial): agg(kuantil, q=0.75) meneruskan argumen kata kunci langsung ke fungsi, dan partial(kuantil, q=0.75) menjadi alternatif setara yang mengikat argumennya lebih dulu.

Membaca Angka Hasilnya #

Angka-angka pada output mudah dicek manual, kebiasaan yang sehat untuk menguji pemahaman. Kelompok Bandung berisi 90, 21, 68, sehingga rentangnya 90 − 21 = 69 dan kuantil 75%-nya 79. Koefisien variasi Jakarta (0.4267) paling kecil karena nilai transaksinya paling homogen; Bandung (0.5907) paling beragam. Nilai kuantil mengikuti interpolasi linear bawaan quantile(), sehingga hasilnya tidak selalu sama dengan salah satu nilai data asli.

Menggabungkan dengan Named Aggregation #

Blok kelima menunjukkan pola yang paling sering kita pakai di proyek nyata: fungsi bawaan dan kustom hidup berdampingan dalam satu agg() berbasis kata kunci (baris 44-48 pada script). Pola named aggregation ini sudah diperkenalkan pada chapter Named Aggregation di section GroupBy dan Agregasi; kontribusi chapter ini adalah kebebasan menempatkan fungsi sendiri di posisi fungsi, seperti keragaman=("nilai", koef_variasi). Hasilnya laporan tiga kolom — omzet, jumlah transaksi, dan keragaman — tanpa nama kolom sisa seperti <lambda_0>.

Fungsi kustom menutup perangkat agregasi kita; pertanyaan berikutnya bergeser dari “berapa ringkasannya?” ke “bagaimana trennya dari waktu ke waktu?”. Chapter berikutnya mengulas window functions — rolling(), expanding(), dan ewm() — secara utuh, termasuk memasang fungsi kustom kita di dalam jendela.

Referensi resmi untuk chapter ini: pandas.DataFrame.agg , user guide groupby , dan pandas.NamedAgg .