Pertanyaan analisis nyata jarang selesai dengan satu agregasi tunggal. Satu laporan penjualan biasanya menuntut ringkasan per kelompok, kontribusi persen per baris, penyaringan kelompok berdasarkan ambang, dan penandaan transaksi yang berbeda dari kelompoknya. Chapter ini menutup Section GroupBy dan Agregasi dengan satu studi kasus utuh: sepuluh transaksi toko yang dijawab dengan menggabungkan agg(), transform(), dan filter() dalam satu skrip. Setelah chapter ini, seluruh teknik kelompok siap kita bawa ke Section berikutnya.

Studi Kasus dan Empat Pertanyaan Analisis #

Kita memakai data transaksi tiga kategori (Elektronik, Pakaian, Makanan) di empat kota, lengkap dengan kuantitas dan harga satuan. Dari data ini, empat pertanyaan bisnis yang wajar diajukan manajer adalah:

  1. Bagaimana ringkasan total nilai, jumlah transaksi, dan rata-rata nilai per kota?
  2. Berapa persen kontribusi setiap transaksi terhadap total kotanya?
  3. Kota mana saja yang total nilainya mencapai minimal 5000?
  4. Transaksi mana saja yang nilainya di atas rata-rata kotanya?

Pertanyaan 1 dijawab dengan named aggregation, pertanyaan 2 dengan transform("sum") plus div(), pertanyaan 3 dengan filter(), dan pertanyaan 4 dengan perbandingan baris terhadap hasil transform("mean"). Satu skrip menjawab semuanya secara berurutan.

Dataset dan Kode Lengkap #

python
import pandas as pd

transaksi = pd.DataFrame({
    "kota": ["Jakarta", "Jakarta", "Jakarta", "Bandung", "Bandung", "Bandung",
             "Surabaya", "Surabaya", "Medan", "Medan"],
    "kategori": ["Elektronik", "Pakaian", "Makanan", "Elektronik", "Pakaian", "Makanan",
                 "Elektronik", "Pakaian", "Elektronik", "Pakaian"],
    "qty": [2, 5, 10, 1, 8, 4, 3, 4, 2, 3],
    "harga_satuan": [1500, 400, 200, 2500, 250, 300, 1000, 500, 900, 200],
})
transaksi["nilai"] = transaksi["qty"] * transaksi["harga_satuan"]
print(transaksi, "\n")

print("1) Ringkasan per kota:")
ringkas = transaksi.groupby("kota").agg(
    total=("nilai", "sum"),
    jumlah_transaksi=("nilai", "size"),
    rata_rata=("nilai", "mean"),
)
print(ringkas.round(1), "\n")

print("2) Kontribusi tiap transaksi terhadap total kotanya:")
total_kota = transaksi.groupby("kota")["nilai"].transform("sum")
transaksi["persen"] = transaksi["nilai"].div(total_kota).mul(100).round(1)
print(transaksi[["kota", "kategori", "nilai", "persen"]], "\n")

print("3) Kota dengan total nilai minimal 5000:")
utama = transaksi.groupby("kota").filter(lambda g: g["nilai"].sum() >= 5000)
print(utama[["kota", "kategori", "nilai"]], "\n")

print("4) Transaksi di atas rata-rata kotanya:")
rata_kota = transaksi.groupby("kota")["nilai"].transform("mean")
unggul = transaksi[transaksi["nilai"] > rata_kota]
print(unggul[["kota", "kategori", "nilai"]])

Output yang Dihasilkan:

text
       kota    kategori  qty  harga_satuan  nilai
0   Jakarta  Elektronik    2          1500   3000
1   Jakarta     Pakaian    5           400   2000
2   Jakarta     Makanan   10           200   2000
3   Bandung  Elektronik    1          2500   2500
4   Bandung     Pakaian    8           250   2000
5   Bandung     Makanan    4           300   1200
6  Surabaya  Elektronik    3          1000   3000
7  Surabaya     Pakaian    4           500   2000
8     Medan  Elektronik    2           900   1800
9     Medan     Pakaian    3           200    600 

1) Ringkasan per kota:
          total  jumlah_transaksi  rata_rata
kota                                        
Bandung    5700                 3     1900.0
Jakarta    7000                 3     2333.3
Medan      2400                 2     1200.0
Surabaya   5000                 2     2500.0 

2) Kontribusi tiap transaksi terhadap total kotanya:
       kota    kategori  nilai  persen
0   Jakarta  Elektronik   3000    42.9
1   Jakarta     Pakaian   2000    28.6
2   Jakarta     Makanan   2000    28.6
3   Bandung  Elektronik   2500    43.9
4   Bandung     Pakaian   2000    35.1
5   Bandung     Makanan   1200    21.1
6  Surabaya  Elektronik   3000    60.0
7  Surabaya     Pakaian   2000    40.0
8     Medan  Elektronik   1800    75.0
9     Medan     Pakaian    600    25.0 

3) Kota dengan total nilai minimal 5000:
       kota    kategori  nilai
0   Jakarta  Elektronik   3000
1   Jakarta     Pakaian   2000
2   Jakarta     Makanan   2000
3   Bandung  Elektronik   2500
4   Bandung     Pakaian   2000
5   Bandung     Makanan   1200
6  Surabaya  Elektronik   3000
7  Surabaya     Pakaian   2000 

4) Transaksi di atas rata-rata kotanya:
       kota    kategori  nilai
0   Jakarta  Elektronik   3000
3   Bandung  Elektronik   2500
4   Bandung     Pakaian   2000
6  Surabaya  Elektronik   3000
8     Medan  Elektronik   1800

Baris 3-10 membangun dataset sepuluh transaksi, lalu baris 11 menambahkan kolom nilai hasil perkalian qty * harga_satuan, sehingga setiap baris mewakili nilai uang satu transaksi. Empat bagian berikutnya saling berurutan dengan nomor 1 sampai 4 pada output. Mari kita baca hasil setiap bagian.

Ringkasan per Kota (Bagian 1) #

Named aggregation pada baris 15-19 menghasilkan tiga kolom sekaligus dalam satu panggilan agg(): total menjumlahkan nilai, jumlah_transaksi menghitung baris dengan "size", dan rata_rata menghitung mean. Output menunjukkan Jakarta sebagai kota dengan total tertinggi 7000 dari tiga transaksi, sedangkan Medan hanya 2400 dari dua transaksi. Bandingkan rata_rata Jakarta 2333.3 dengan Medan 1200.0: selisih ini yang nanti memengaruhi bagian 4.

Kontribusi Persen Tiap Transaksi (Bagian 2) #

Baris 23 menghasilkan total per kota di setiap baris dengan transform("sum"), lalu baris 24 membagi nilai transaksi dengan total tersebut dan mengalikan 100. Hasilnya bisa dibaca langsung: transaksi Elektronik Jakarta menyumbang 42.9 persen dari total kotanya, sedangkan di Medan satu transaksi Elektronik menyumbang 75.0 persen. Kolom persen seperti ini biasanya langsung dimasukkan ke dashboard karena menjawab “porsi apa” tanpa perlu pembaca berhitung.

Menyaring Kota Utama (Bagian 3) #

Baris 28 memakai groupby("kota").filter(lambda g: g["nilai"].sum() >= 5000). Medan dengan total 2400 dibuang utuh, sementara Surabaya yang tepat 5000 masih lolos karena kondisinya “minimal”. Output menyisakan delapan baris dari tiga kota dengan index asli 0 sampai 7. Perhatikan bahwa kondisi >= versus > benar-benar menentukan hasil di ambang batas, sehingga rumus ambang pada laporan harus dibaca dengan teliti.

Transaksi di Atas Rata-rata Kotanya (Bagian 4) #

Baris 31-32 menghitung rata-rata per kota pada setiap baris, lalu baris 33 membandingkannya dengan nilai transaksi menggunakan boolean mask. Lima transaksi lolos: Elektronik Jakarta 3000, Elektronik dan Pakaian Bandung (2500 dan 2000), Elektronik Surabaya 3000, serta Elektronik Medan 1800. Menariknya, semua transaksi yang berada di atas rata-rata kotanya berasal dari kategori Elektronik, sebuah temuan yang muncul justru karena kita membandingkan setiap transaksi dengan konteks kelompoknya, bukan dengan rata-rata keseluruhan data.

Pola Kerja Analisis Berbasis Kelompok #

Studi kasus ini memperlihatkan pola kerja yang bisa dipakai ulang untuk dataset apa pun. Pertama, pastikan kolom nilai siap (misalnya hasil perkalian kuantitas dan harga), lalu bangun ringkasan per kelompok dengan agg(). Selanjutnya bawa angka agregat kembali ke baris asli dengan transform() bila analisis membutuhkan perbandingan atau proporsi, dan gunakan filter() hanya saat kelompok utuh harus masuk atau keluar dari laporan.

Dokumentasi resmi untuk menuntaskan materi Section ini adalah panduan GroupBy , DataFrame.groupby , dan DataFrameGroupBy.agg .

Sampai di sini kita sudah mampu memecah data menjadi kelompok, merangkumnya, menyaringnya, dan menafsirkan proporsinya. Pertanyaan berikutnya biasanya bukan lagi tentang satu tabel, melainkan tentang menggabungkan beberapa tabel yang berbeda sumber; itulah topik Section Menggabungkan dan Membentuk Data.