Laporan omzet per kota sudah membantu, tetapi manajer toko sering menanyakan potongan yang lebih halus: berapa omzet kategori Sembako khusus di kota Bandung? Pertanyaan seperti itu melibatkan dua kunci sekaligus dan tidak bisa dijawab dengan groupby satu kolom tanpa langkah penyaringan tambahan. Pandas menerima list kolom pada groupby(), dan setiap kombinasi nilai unik dari kolom-kolom tersebut menjadi satu kelompok. Konsekuensinya, hasil agregasi membawa MultiIndex, yaitu index bertingkat dengan beberapa level nama. Chapter ini membahas cara membuat kelompok multi-kolom, membaca indexnya, dan menata ulang hasilnya menjadi tabel silang.
Daftar Kunci sebagai Argumen groupby #
Bentuk paling umum dari groupby beberapa kolom adalah df.groupby(["kota", "kategori"]). List yang dipakai sebagai argumen menentukan urutan level index: kolom pertama menjadi level paling luar dan kolom kedua menjadi level di dalamnya. pandas menghitung semua kombinasi nilai yang benar-benar muncul di data, bukan semua kombinasi teoretis; dataset transaksi kita memiliki sembilan kombinasi kota-kategori yang aktif berjualan. Karena itu jumlah kelompok hasil groupby bisa lebih banyak daripada jumlah nilai unik setiap kolomnya.
Membaca MultiIndex Hasil Agregasi #
Script berikut mengelompokkan transaksi berdasarkan dua kolom, menjumlahkan kolom total, lalu menunjukkan cara mengintip struktur index hasilnya.
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],
})
d = transaksi.groupby(["kota", "kategori"])["total"].sum()
print(d)
print()
print("nama level index :", list(d.index.names))
print("jumlah level :", d.index.nlevels)
print()
print("omzet Bandung untuk semua kategori:")
print(d.loc["Bandung"])
print()
print("omzet Sembako di Bandung saja:", d.loc[("Bandung", "Sembako")])
print()
print("bentuk tabel silang dengan unstack():")
print(d.unstack())Output yang Dihasilkan:
kota kategori
Bandung Makanan 65000
Minuman 90000
Sembako 204000
Jakarta Makanan 60000
Minuman 78000
Sembako 68000
Surabaya Makanan 28000
Minuman 90000
Sembako 136000
Name: total, dtype: int64
nama level index : ['kota', 'kategori']
jumlah level : 2
omzet Bandung untuk semua kategori:
kategori
Makanan 65000
Minuman 90000
Sembako 204000
Name: total, dtype: int64
omzet Sembako di Bandung saja: 204000
bentuk tabel silang dengan unstack():
kategori Makanan Minuman Sembako
kota
Bandung 65000 90000 204000
Jakarta 60000 78000 68000
Surabaya 28000 90000 136000Mari kita bedah baris-baris penting script di atas:
- Baris 20: argumen
["kota", "kategori"]membentuk sembilan kelompok; hasilnya Series bernamatotaldengan index bertingkat dua level. - Baris 24-25:
d.index.namesmengembalikan nama kedua level (kotadankategori), sedangkand.index.nlevelsmengonfirmasi bahwa index memiliki dua level. - Baris 29:
d.loc["Bandung"]adalah akses parsial; level pertama saja disebut sehingga pandas mengembalikan Series omzet seluruh kategori di Bandung. - Baris 32:
d.loc[("Bandung", "Sembako")]menyebut kedua level lewat tuple dan mengembalikan satu angka, yaitu204000. - Baris 36:
d.unstack()memutar level terdalam menjadi kolom sehingga hasilnya berbentuk tabel silang kota dan kategori.
Mengakses Satu Kombinasi Kunci #
Penulisan tuple ("Bandung", "Sembako") pada .loc mengikuti aturan yang konsisten: urutan elemennya dari level terluar ke terdalam, dan jumlahnya harus sama dengan jumlah level bila kita menginginkan satu angka saja. Bila sebuah level sengaja tidak disebut, pandas mengembalikan hasil untuk semua nilai level tersebut, seperti Series Bandung pada output tadi. Akses parsial semacam ini praktis untuk laporan satu wilayah karena kita tidak perlu menyaring DataFrame asal lagi.
Menata Hasil dengan unstack() #
Series MultiIndex bagus untuk komputasi lanjutan, tetapi laporan untuk manusia lebih nyaman dibaca dalam bentuk tabel silang. Method unstack() memindahkan level index terdalam menjadi kolom, sehingga baris menunjukkan kota dan kolom menunjukkan kategori. Operasi kebalikannya adalah stack(), yang mengembalikan kolom menjadi level index lagi; keduanya membentuk pasangan yang bisa diputar bolak-balik tanpa kehilangan informasi. Struktur index bertingkat seperti ini dijelaskan lebih rinci pada user guide MultiIndex
resmi pandas.
Dengan dua kunci, satu baris groupby mampu menjawab pertanyaan yang pada SQL menuntut GROUP BY dua kolom, seperti dirangkum pada user guide groupby
. Dataset transaksi yang sama akan terus kita pakai sehingga setiap angka mudah dicek ulang. Berikutnya kita fokus ke tahap apply: fungsi agregasi bawaan apa saja yang bisa dipanggil setelah pengelompokan, mulai dari sum() sampai nunique(), termasuk perbedaan count() dan size() yang sering tertukar.