Nilai numerik kontinu seperti nominal transaksi sulit dibaca kalau ditampilkan apa adanya. Laporan bisnis biasanya lebih mudah dipahami bila nilainya dikelaskan, misalnya menjadi Murah, Sedang, dan Mahal. Proses membagi rentang angka ke dalam beberapa interval (bin) ini disebut binning, dan pandas menyediakan fungsi pd.cut() untuk keperluan itu. Pada Chapter ini kita menentukan batas bin secara manual, memberi label Indonesia, lalu memeriksa perilaku tepi interval dan nilai yang berada di luar rentang.
Membagi Transaksi ke Kelas Harga #
Skrip berikut membagi nilai_transaksi menjadi tiga kelas harga dengan tepi yang kita pilih sendiri. Setelah kolom baru terbentuk, skrip menghitung rekap per kelas, lalu menguji dua perilaku tepi yang paling sering membuat pemula terkejut. Jalankan dan amati kelima cetakannya.
import pandas as pd
pesanan = pd.DataFrame({
"id_pesanan": ["PSN-001", "PSN-002", "PSN-003", "PSN-004",
"PSN-005", "PSN-006", "PSN-007", "PSN-008"],
"nama_pelanggan": ["Budi", "Siti", "Dewi", "Andi",
"Rina", "Tono", "Lina", "Sari"],
"kota": ["Jakarta", "Bandung", "Surabaya", "Jakarta",
"Medan", "Bandung", "Jakarta", "Surabaya"],
"pembayaran": ["QRIS", "Transfer", "QRIS", "Kartu Kredit",
"COD", "Transfer", "QRIS", "COD"],
"nilai_transaksi": [250_000, 1_800_000, 750_000, 2_400_000,
480_000, 1_200_000, 320_000, 980_000],
"berat_paket": [1.2, 4.5, 0.8, 7.0, 2.5, 3.0, 1.0, 5.5],
})
tepi = [0, 500_000, 1_500_000, 2_500_000]
label = ["Murah", "Sedang", "Mahal"]
pesanan["kelas_harga"] = pd.cut(
pesanan["nilai_transaksi"], bins=tepi, labels=label
)
print(pesanan[["id_pesanan", "nilai_transaksi", "kelas_harga"]])
print()
print(pesanan["kelas_harga"].value_counts())
print()
print("dtype:", pesanan["kelas_harga"].dtype)
print()
transaksi_lain = pd.Series([300_000, 3_000_000, 2_500_000])
print(pd.cut(transaksi_lain, bins=tepi, labels=label))
print()
print(pd.cut(pd.Series([0]), bins=tepi, labels=label).tolist())
print(pd.cut(pd.Series([0]), bins=tepi, labels=label, include_lowest=True).tolist())Output yang Dihasilkan:
id_pesanan nilai_transaksi kelas_harga
0 PSN-001 250000 Murah
1 PSN-002 1800000 Mahal
2 PSN-003 750000 Sedang
3 PSN-004 2400000 Mahal
4 PSN-005 480000 Murah
5 PSN-006 1200000 Sedang
6 PSN-007 320000 Murah
7 PSN-008 980000 Sedang
kelas_harga
Murah 3
Sedang 3
Mahal 2
Name: count, dtype: int64
dtype: category
0 Murah
1 NaN
2 Mahal
dtype: category
Categories (3, str): ['Murah' < 'Sedang' < 'Mahal']
[nan]
['Murah']Mari kita telaah apa yang terjadi pada kode di atas:
- Baris 17-18 (
tepi = [...],label = [...]): listtepiberisi empat angka yang membentuk tiga interval: 0-500 ribu, 500 ribu-1,5 juta, dan 1,5-2,5 juta. Panjanglabelharus sama dengan jumlah interval, yaitu tiga. - Baris 20-22 (
pesanan["kelas_harga"] = pd.cut(...)):pd.cut()mencari interval untuk setiap nilainilai_transaksidan menggantinya dengan label kelasnya. Hasilnya Series bertipecategorydengan urutan kategoriMurah < Sedang < Mahal, terlihat pada cetakandtype: categorydi baris 27. - Baris 25 (
value_counts()): method Series.value_counts() merangkum isi tiap kelas: Murah 3, Sedang 3, Mahal 2. Bin dengan lebar sama belum tentu berisi jumlah data yang sama, karena isi bin mengikuti sebaran data. - Baris 30-31 (
transaksi_lain): nilai 3.000.000 berada di atas tepi atas sehingga menjadiNaN, sedangkan 2.500.000 yang tepat di tepi atas tetap masuk Mahal. Secara bawaan interval ditutup di sisi kanan (right=True), sehingga bentuknya (tepi kiri, tepi kanan]. - Baris 34-35 (
pd.Series([0])): nilai 0 menjadiNaNkarena interval pertama terbuka di sisi kiri. Argumeninclude_lowest=Truemenutup tepi pertama, sehingga 0 ikut masuk ke kelas Murah.
Aturan Tepi Interval dan Nilai di Luar Rentang #
Konvensi interval pd.cut() mengikuti notasi matematika. Dengan right=True (bawaan), interval berbentuk (a, b]: nilai a tidak termasuk, nilai b termasuk. Mengirim right=False membalik konvensinya menjadi [a, b); pada data Chapter ini, nilai 500.000 yang semula masuk Murah akan berpindah ke Sedang. Pilihan right penting saat tepi bin bertepatan dengan nilai data yang nyata, misalnya batas 500 ribu yang sering muncul di transaksi.
pd.cut() memberi kontrol penuh atas batas kelas, sehingga setiap kelas punya definisi bisnis yang tetap dan mudah dikomunikasikan. Bila tujuannya berubah menjadi menjaga jumlah isi tiap bin tetap seimbang, batas harus dihitung dari data itu sendiri. Chapter berikutnya membahas pd.qcut(), yang menentukan batas bin dari kuantil data.