Kursus Python / Menghitung dan mengelompokkan data dengan collections dan itertools
collections menyediakan wadah khusus untuk menghitung atau mengakumulasi data, sedangkan itertools menggabungkan alur iterasi. Pilih berdasarkan arti hasil, urutan input, dan perilaku konsumsi, bukan hanya untuk memendekkan kode.
Bedakan jumlah kemunculan dan jumlah nilai
Counter menghitung banyaknya kemunculan unsur yang dapat dijadikan kunci. Dua record berkategori food berarti hitungan food adalah 2, bukan jumlah pengeluarannya. Untuk menjumlahkan nilai pengeluaran menurut kategori, gunakan akumulasi yang terpisah.
defaultdict(int) membuat nilai nol dari factory int ketika kunci yang belum ada diakses dengan tanda kurung siku. Dengan demikian, totals[category] += amount dapat langsung mengakumulasi angka. totals.get("missing") tidak mempunyai efek pembuatan kunci yang sama; membaca melalui API berbeda dapat mengubah keadaan dengan cara berbeda.
Jika pembacaan kunci yang hilang tidak boleh menyisipkan nilai, dictionary biasa dengan get mungkin lebih jelas. Konsepnya mengikuti pengelolaan dictionary. Rujukan perilaku khusus tersedia pada dokumentasi collections.
Jalankan hitungan, total, dan pengelompokan
Simpan kode lengkap sebagai collections_demo.py dengan encoding UTF-8. Gunakan Python 3.12 atau lebih baru melalui lingkungan proyek dan jalankan python collections_demo.py. Semua impor berasal dari pustaka standar.
from collections import Counter, defaultdict
from itertools import chain, groupby
rows = [("food", 3500), ("bus", 2500), ("food", 8000)]
counts = Counter(category for category, _ in rows)
totals = defaultdict(int)
for category, amount in rows:
totals[category] += amount
print(sorted(counts.items()))
print(sorted(totals.items()))
print(list(chain([1, 2], [3])))
for category, group in groupby(sorted(rows), key=lambda row: row[0]):
print(category, sum(amount for _, amount in group))
Keluaran yang diharapkan:
[('bus', 1), ('food', 2)]
[('bus', 2500), ('food', 11500)]
[1, 2, 3]
bus 2500
food 11500
Baris pertama menghitung kategori, baris kedua menjumlahkan biayanya, dan baris ketiga membaca dua list secara berurutan melalui chain. sorted(...items()) membuat tampilan kunci konsisten; urutan tampilan itu tidak boleh disamakan dengan operasi penghitungan.
Pada dua baris terakhir, groupby menerima record yang telah diurutkan. Fungsi lambda row: row[0] mengambil kategori dari setiap tuple. Isi masing-masing grup langsung dijumlahkan sebelum iterator berpindah ke grup berikutnya.
Ingat bahwa groupby mengelompokkan kunci yang bersebelahan
itertools.groupby membuat satu grup selama nilai kunci berturut-turut masih sama. Ia tidak otomatis mengumpulkan semua record berkunci sama yang tersebar di berbagai posisi seperti agregasi global. Karena input awal berurutan food, bus, food, tanpa pengurutan akan muncul dua grup food.
Simpan program pembanding lengkap sebagai groups.py, lalu jalankan python groups.py. Program berdiri sendiri dan memakai input yang sama pada dua kondisi.
from itertools import groupby
rows = [("food", 3500), ("bus", 2500), ("food", 8000)]
def category(row):
return row[0]
for label, data in [("original", rows), ("sorted", sorted(rows, key=category))]:
print(label)
for name, group in groupby(data, key=category):
print(name, sum(amount for _, amount in group))
print(category(rows[0]) == (lambda row: row[0])(rows[0]))
Keluaran yang diharapkan:
original
food 3500
bus 2500
food 8000
sorted
bus 2500
food 11500
True
Fungsi category(row) dan bentuk singkat lambda row: row[0] menghasilkan kunci yang sama untuk record contoh. Pengurutan dengan kunci kategori menempatkan seluruh food berdekatan, sehingga satu grup food dapat dijumlahkan menjadi 11500. Pada program pertama, sorted(rows) mengurutkan tuple dan juga menempatkan kategori yang sama bersama; bila aturan kunci lebih kompleks, nyatakan fungsi kunci yang sesuai secara eksplisit.
Iterator grup berbagi aliran sumber. Jika iterator utama sudah maju ke grup berikutnya, jangan mengharapkan grup sebelumnya masih dapat dibaca lengkap. Konsumsi atau simpan hasil agregasi saat grup itu sedang aktif. Penjelasan resminya ada pada dokumentasi groupby.
Uji konsumsi, nilai bawaan, dan biaya penyimpanan
- Jalankan kedua sumber asli dan cocokkan hitungan kategori, total uang, serta keluaran grup.
- Pada program pertama, hilangkan hanya
sorteddari inputgroupby. Total dictionary tetap sama, tetapi bagian grup kini menampilkan food 3500, bus 2500, lalu food 8000. - Pulihkan pengurutan. Baca kunci hilang melalui
totals.get, lalu melaluitotals["missing"]pada percobaan terpisah dan periksa apakah kunci baru muncul. - Pulihkan program sebelum membandingkan keluaran lengkap lagi. Jalankan dalam proses baru agar keadaan wadah percobaan tidak tertinggal.
chain membaca input secara berurutan tanpa terlebih dahulu menyimpan satu list gabungan. Namun konversi akhirnya menjadi list tetap menyimpan semua hasil. Pengurutan input juga membutuhkan penyimpanan dan mengubah urutan pengamatan. Untuk data besar yang tidak perlu diurutkan, akumulasi dictionary dapat lebih sesuai daripada memaksakan pola sort lalu groupby.
islice dapat mengambil bagian terbatas dari iterator, misalnya tiga unsur dari aliran hitungan. Iterator tak berhingga harus dibatasi atau dihentikan dengan aturan yang jelas; jangan mengubahnya langsung menjadi list tanpa batas. Dasar keadaan habis dan perbedaan input-hasil dijelaskan pada iterator dan generator.
Gunakan Counter ketika yang dibutuhkan frekuensi, accumulator ketika yang dibutuhkan total nilai, dan groupby ketika yang dibutuhkan grup berurutan. Kesamaan bentuk output tidak menggantikan pemeriksaan arti dan cara sumber dikonsumsi.




