Pertanyaan analisis di dunia kerja jarang berhenti pada satu angka keseluruhan. Manajer toko lebih tertarik pada omzet per kota, transaksi per kategori, atau rata-rata nilai belanja per wilayah daripada satu total besar. Menjawabnya secara manual berarti menyalin data berulang-ulang dan membuka peluang salah hitung. Groupby pada pandas dirancang khusus untuk pola pekerjaan ini, dan polanya memiliki nama resmi: split-apply-combine. Pada Chapter ini kita membedah ketiga tahap tersebut secara manual agar mekanismenya terlihat jelas, sebelum dipangkas menjadi satu method pada chapter berikutnya.

Dataset Transaksi untuk Sepanjang Section #

Seluruh chapter pada Section ini memakai satu dataset yang sama: catatan 12 transaksi sebuah toko sembako yang memiliki cabang di tiga kota. Setiap baris merekam satu penjualan dengan enam kolom yang tercantum pada tabel berikut. Dataset ini sengaja dibuat kecil agar kita bisa memverifikasi setiap angka output dengan hitungan tangan. Kebiasaan menghitung ulang hasil agregasi seperti ini tetap berguna ketika data sungguhan berisi ratusan ribu baris.

KolomIsiContoh nilai
kotacabang toko tempat transaksi terjadiJakarta, Bandung, Surabaya
kategorijenis barang yang dijualMinuman, Makanan, Sembako
produknama barang yang terjualKopi Gayo, Beras Premium
jumlahbanyak unit yang terjual3, 10
hargaharga satuan dalam rupiah18000, 3500
totalnilai transaksi (jumlah dikali harga)54000, 204000

Tiga Tahap Split, Apply, dan Combine #

Istilah split-apply-combine dipopulerkan oleh statistikawan Hadley Wickham dalam papernya tahun 2011 tentang strategi analisis data. Strategi ini membagi pekerjaan agregasi menjadi tiga langkah yang berurutan. Tahap split memecah DataFrame menjadi beberapa kelompok berdasarkan nilai sebuah kolom kunci, misalnya semua baris dengan kota bernilai Bandung. Tahap apply menerapkan satu fungsi pada setiap kelompok secara terpisah, misalnya sum() untuk menjumlahkan kolom total. Tahap combine menggabungkan hasil per kelompok menjadi satu objek baru, biasanya Series atau DataFrame dengan satu baris per kelompok.

Diagram di atas memperlihatkan alur data pada dataset transaksi kita. Satu DataFrame berisi 12 baris masuk ke tahap split dan keluar sebagai tiga kelompok kecil, setiap kelompok diproses fungsi sum() pada tahap apply, lalu hasilnya disatukan kembali menjadi satu Series berisi tiga angka pada tahap combine. Pengurangan detail seperti ini memang inti dari agregasi: kita menukar isi baris demi baris dengan ringkasan yang bisa dijadikan dasar keputusan. Pola yang sama dirangkum resmi oleh pandas pada halaman Group by: split-apply-combine .

Membedah Ketiga Tahap dengan Kode #

Agar ketiga tahap tidak berhenti sebagai teori, script berikut mengimplementasikannya secara manual dengan loop Python biasa. Script mencetak ukuran setiap kelompok, hasil sum() per kelompok, lalu menggabungkannya menjadi Series. Di bagian akhir, groupby() dipanggil dalam satu baris untuk membuktikan hasilnya identik.

python
import pandas as pd

transaksi = pd.DataFrame({
    "kota": ["Jakarta", "Jakarta", "Jakarta", "Jakarta",
             "Bandung", "Bandung", "Bandung", "Bandung",
             "Surabaya", "Surabaya", "Surabaya", "Surabaya"],
    "kategori": ["Minuman", "Minuman", "Makanan", "Sembako",
                 "Minuman", "Makanan", "Sembako", "Makanan",
                 "Minuman", "Sembako", "Makanan", "Minuman"],
    "produk": ["Kopi Gayo", "Teh Melati", "Roti Tawar", "Beras Premium",
               "Kopi Gayo", "Roti Tawar", "Beras Premium", "Mie Instan",
               "Teh Melati", "Beras Premium", "Mie Instan", "Kopi Gayo"],
    "jumlah": [3, 2, 4, 1, 5, 2, 3, 10, 6, 2, 8, 1],
    "harga": [18000, 12000, 15000, 68000, 18000, 15000, 68000, 3500,
              12000, 68000, 3500, 18000],
    "total": [54000, 24000, 60000, 68000, 90000, 30000, 204000, 35000,
              72000, 136000, 28000, 18000],
})

print("Dataset transaksi:")
print(transaksi)
print()

print("== Tahap 1: SPLIT ==")
kelompok = {}
for kota in sorted(transaksi["kota"].unique()):
    kelompok[kota] = transaksi[transaksi["kota"] == kota]
    print(f"{kota}: {len(kelompok[kota])} baris")
print()

print("== Tahap 2: APPLY ==")
hasil = {}
for kota, baris in kelompok.items():
    hasil[kota] = baris["total"].sum()
    print(f"sum(total) kota {kota} = {hasil[kota]}")
print()

print("== Tahap 3: COMBINE ==")
ringkasan = pd.Series(hasil, name="total")
ringkasan.index.name = "kota"
print(ringkasan)
print()

print("Satu baris groupby memberi hasil yang sama:")
print(transaksi.groupby("kota")["total"].sum())

Output yang Dihasilkan:

text
Dataset transaksi:
        kota kategori         produk  jumlah  harga   total
0    Jakarta  Minuman      Kopi Gayo       3  18000   54000
1    Jakarta  Minuman     Teh Melati       2  12000   24000
2    Jakarta  Makanan     Roti Tawar       4  15000   60000
3    Jakarta  Sembako  Beras Premium       1  68000   68000
4    Bandung  Minuman      Kopi Gayo       5  18000   90000
5    Bandung  Makanan     Roti Tawar       2  15000   30000
6    Bandung  Sembako  Beras Premium       3  68000  204000
7    Bandung  Makanan     Mie Instan      10   3500   35000
8   Surabaya  Minuman     Teh Melati       6  12000   72000
9   Surabaya  Sembako  Beras Premium       2  68000  136000
10  Surabaya  Makanan     Mie Instan       8   3500   28000
11  Surabaya  Minuman      Kopi Gayo       1  18000   18000

== Tahap 1: SPLIT ==
Bandung: 4 baris
Jakarta: 4 baris
Surabaya: 4 baris

== Tahap 2: APPLY ==
sum(total) kota Bandung = 359000
sum(total) kota Jakarta = 206000
sum(total) kota Surabaya = 254000

== Tahap 3: COMBINE ==
kota
Bandung     359000
Jakarta     206000
Surabaya    254000
Name: total, dtype: int64

Satu baris groupby memberi hasil yang sama:
kota
Bandung     359000
Jakarta     206000
Surabaya    254000
Name: total, dtype: int64

Mari kita bedah baris-baris penting script di atas:

  1. Baris 20-21: print(transaksi) menampilkan dataset lengkap; 12 baris inilah bahan baku seluruh proses.
  2. Baris 24-28 (tahap split): sorted(transaksi["kota"].unique()) mengambil daftar kota unik, dan filter Boolean transaksi["kota"] == kota memecah dataset menjadi tiga sub-DataFrame yang disimpan di dictionary kelompok.
  3. Baris 31-35 (tahap apply): loop kedua memanggil baris["total"].sum() pada setiap sub-DataFrame; sum() adalah fungsi agregasi karena mengembalikan satu angka untuk satu kelompok.
  4. Baris 38-41 (tahap combine): dictionary hasil diubah menjadi Series lewat pd.Series(hasil, name="total"), dan ringkasan.index.name = "kota" menamai indexnya.
  5. Baris 44-45: transaksi.groupby("kota")["total"].sum() menghasilkan Series yang nilai dan urutannya sama persis dengan hasil manual kita.

Urutan Kelompok dan Parameter sort #

Loop manual pada script sengaja memakai sorted(), dan alasannya bukan sekadar gaya penulisan. Method unique() mengembalikan nilai sesuai urutan kemunculan pertama (Jakarta, Bandung, Surabaya), sedangkan groupby() mengurutkan kunci kelompok secara alfabetis karena parameter sort bernilai True secara default. Tanpa sorted(), dua output pada script tadi akan berisi nilai yang sama tetapi urutan barisnya berbeda. Bila urutan kemunculan lebih penting, panggil groupby dengan sort=False sehingga hasilnya mengikuti urutan data asli.

Sekarang kita tahu bahwa groupby hanyalah otomatisasi dari tiga tahap yang bisa kita tulis manual; tanda tangan lengkap method ini terdokumentasi pada pandas.DataFrame.groupby . Chapter berikutnya memakai groupby() langsung pada satu kolom kunci, dari membuat objeknya sampai memilih bentuk hasil. Setelah pola satu kolom dikuasai, kita perluas ke pengelompokan dua kolom sekaligus.