Pada Section Indexing dan Seleksi Data kita sudah mengenal boolean masking: menyaring baris berdasarkan kondisi yang dievaluasi per baris, misalnya df[df["nilai"] > 100]. Kondisi seperti itu tidak bisa menjawab pertanyaan tingkat kelompok, misalnya “pertahankan hanya kota yang total penjualannya mencapai 100 atau lebih”. Untuk kebutuhan semacam ini, objek GroupBy menyediakan method filter(). Chapter ini membahas mekanisme filter(), dua contoh pemakaiannya, dan perbedaannya dengan DataFrame.filter() yang namanya sama tetapi perilakunya berbeda.
Dua Level Penyaringan: Baris dan Kelompok #
Sebelum masuk ke kode, kita luruskan dulu dua level penyaringan yang berbeda ini. Boolean masking menguji setiap baris secara terpisah, sehingga baris yang lolos bisa berasal dari kelompok mana pun. Sebaliknya, penyaringan tingkat kelompok menguji kelompok secara utuh: jika kondisinya terpenuhi, semua baris kelompok dipertahankan; jika tidak, seluruh kelompok dibuang. Tabel berikut memetakan kapan kita memakai alat yang mana:
| Kebutuhan | Alat | Kondisi dievaluasi pada |
|---|---|---|
| Buang baris dengan nilai tertentu | boolean mask | setiap baris |
| Buang kelompok yang totalnya di bawah ambang | groupby().filter() | setiap kelompok utuh |
| Buang kelompok dengan anggota terlalu sedikit | groupby().filter() | jumlah baris kelompok |
Mekanisme filter() pada GroupBy #
Method filter() menerima satu argumen wajib: sebuah fungsi yang mengembalikan True atau False. GroupBy menyerahkan sub-DataFrame setiap kelompok ke fungsi tersebut satu per satu. Ketika fungsi mengembalikan True, seluruh baris kelompok itu dipertahankan; ketika False, seluruh kelompok dilewati. Hasil akhir adalah gabungan baris-baris kelompok yang lolos, dengan urutan dan index asli tetap dipertahankan, sehingga hasilnya langsung siap dipakai sebagai DataFrame biasa.
Contoh: Menyaring Kota dengan Total Nilai Tertentu #
Skrip berikut memakai data penjualan empat kota yang sama dengan chapter sebelumnya. Pertama kita lihat total per kota sebagai pembanding, lalu kita pertahankan hanya kota dengan total nilai minimal 100, dan terakhir kota dengan minimal dua transaksi.
import pandas as pd
penjualan = pd.DataFrame({
"kota": ["Jakarta", "Jakarta", "Bandung", "Bandung", "Surabaya", "Surabaya", "Medan"],
"kategori": ["Elektronik", "Pakaian", "Elektronik", "Pakaian", "Elektronik", "Pakaian", "Elektronik"],
"nilai": [120, 80, 90, 70, 110, 60, 50],
})
print("total nilai per kota:")
print(penjualan.groupby("kota")["nilai"].sum(), "\n")
print("kelompok dengan total nilai >= 100:")
lolos = penjualan.groupby("kota").filter(lambda g: g["nilai"].sum() >= 100)
print(lolos, "\n")
print("kelompok dengan minimal dua transaksi:")
ramai = penjualan.groupby("kota").filter(lambda g: len(g) >= 2)
print(ramai)Output yang Dihasilkan:
total nilai per kota:
kota
Bandung 160
Jakarta 200
Medan 50
Surabaya 170
Name: nilai, dtype: int64
kelompok dengan total nilai >= 100:
kota kategori nilai
0 Jakarta Elektronik 120
1 Jakarta Pakaian 80
2 Bandung Elektronik 90
3 Bandung Pakaian 70
4 Surabaya Elektronik 110
5 Surabaya Pakaian 60
kelompok dengan minimal dua transaksi:
kota kategori nilai
0 Jakarta Elektronik 120
1 Jakarta Pakaian 80
2 Bandung Elektronik 90
3 Bandung Pakaian 70
4 Surabaya Elektronik 110
5 Surabaya Pakaian 60Mari kita bedah baris-baris kuncinya:
- Baris 9-10: total per kota menunjukkan Jakarta 200, Bandung 160, Surabaya 170, dan Medan 50. Angka inilah yang menjadi dasar keputusan filter.
- Baris 13: lambda
gmenerima sub-DataFrame satu kota. Ekspresig["nilai"].sum() >= 100menghitung total kelompok itu lalu membandingkannya dengan ambang; hasilnya satu nilai boolean per kelompok. - Baris 13-14: hanya Medan yang totalnya di bawah 100, sehingga kelompok Medan dibuang utuh dan output menyisakan enam baris dari tiga kota.
- Baris 17:
len(g) >= 2menguji jumlah baris kelompok, bukan nilainya. Medan kembali dibuang karena hanya memiliki satu transaksi.
Perhatikan bahwa output mempertahankan index asli 0 sampai 5 tanpa penomoran ulang. Perilaku ini berbeda dari agg() yang menghasilkan index baru berupa nama kelompok. Karena hasil filter() adalah DataFrame biasa, kita bisa langsung melanjutkan dengan operasi apa pun, termasuk groupby lagi jika analisis menuntutnya.
Kapan Memakai filter() pada GroupBy #
Pola ini paling berguna ketika ambang keputusan bersifat agregat: total minimal, rata-rata maksimal, atau jumlah anggota tertentu. Contoh nyatanya beragam, seperti memilih cabang dengan omzet di atas target, membuang produk dengan total penjualan terlalu kecil agar tidak mengganggu laporan, atau menyeleksi kategori yang datanya cukup banyak untuk dianalisis. Jika kondisinya hanya menyangkut nilai per baris, tetap gunakan boolean masking karena lebih langsung. Dokumentasi resmi yang relevan adalah panduan GroupBy , DataFrameGroupBy.filter , dan DataFrame.filter .
Sampai di sini kita sudah bisa menghitung agregat per kelompok dan menyaring kelompok utuh. Satu persoalan penting belum disentuh: apa yang terjadi bila data yang dikelompokkan mengandung nilai kosong. Chapter berikutnya membahas GroupBy dan missing values, mulai dari kunci kelompok NaN hingga nilai yang diagregasi.