Laporan bisnis jarang berbicara dalam angka kontinu. Tim produk tidak bertanya “berapa transaksi bernilai persis 234.500 rupiah?”, melainkan “berapa transaksi di kelas kecil, menengah, dan besar?”. Mengubah nilai kontinu menjadi nomor kelompok — istilah teknisnya binning — adalah jembatan antara data mentah dan laporan seperti itu, dan np.digitize adalah alat NumPy untuk pekerjaan ini.

Bab ini mencakup dua alat yang saling melengkapi:

  1. np.digitize — mengubah setiap nilai kontinu menjadi nomor bin berdasarkan batas yang kita tentukan.
  2. np.histogram2d — menghitung distribusi dua variabel sekaligus ke dalam satu matriks frekuensi.

Keduanya tetangga dekat Counting dan Frekuensi: di sana kita menghitung kemunculan nilai yang sudah diskret; di sini kita mengelompokkan dulu nilai kontinu, baru menghitungnya.

Mengelompokkan Pengeluaran ke Kelas Tarif #

python
import numpy as np

pengeluaran = np.array([45, 120, 680, 320, 90, 500, 1000, 75])  # ribu rupiah
batas = np.array([100, 500])
kelas = np.digitize(pengeluaran, batas)
print("kelas   :", kelas)
print("bincount:", np.bincount(kelas))
nama_kelas = np.array(["hemat", "menengah", "mewah"])
print(nama_kelas[kelas])

Output yang Dihasilkan:

text
kelas   : [0 1 2 1 0 2 2 0]
bincount: [3 2 3]
['hemat' 'menengah' 'mewah' 'menengah' 'hemat' 'mewah' 'mewah' 'hemat']

Mari kita bedah:

  1. Baris 3 (batas): dua batas bin yang terurut naik membagi garis bilangan menjadi tiga wilayah — di bawah 100, 100 sampai sebelum 500, dan 500 ke atas.
  2. Baris 4 (np.digitize): setiap elemen pengeluaran diperiksa terhadap batas, dan fungsi mengembalikan nomor binnya: 0 berarti di bawah batas pertama, 1 di antara dua batas, 2 di atas batas kedua.
  3. Baris 6 (np.bincount): menghitung banyaknya anggota tiap kelas — 3 pelanggan hemat, 2 menengah, 3 mewah — pola yang sama dengan Counting dan Frekuensi.
  4. Baris 8-9: fancy indexing dengan array nomor bin menerjemahkan nomor kelas menjadi label yang siap dilaporkan.

Perilaku di Batas Bin: right=False dan right=True #

Nilai yang persis sama dengan batas bin milik wilayah mana? Parameter right yang menentukan. Mode bawaan right=False memakai wilayah setengah-terbuka bins[i-1] <= x < bins[i], sehingga nilai yang sama dengan batas masuk ke bin di kanannya. Sebaliknya, right=True memakai bins[i-1] < x <= bins[i], sehingga batas ikut bin di kirinya.

python
import numpy as np

batas = np.array([100, 500])
nilai = np.array([99, 100, 499, 500, 501])
print("right=False:", np.digitize(nilai, batas))
print("right=True :", np.digitize(nilai, batas, right=True))

Output yang Dihasilkan:

text
right=False: [0 1 1 2 2]
right=True : [0 0 1 1 2]

Perilaku kedua mode pada kelima nilai tersebut:

Nilai xright=Falseright=True
9900
10010
49911
50021
50122

Konvensi [a, b) cocok untuk skema tarif “di atas 500 ribu” yang memang tidak menyertakan angka 500. Bila kelas kita menyatakan “sampai dengan 500”, right=True yang tepat. Kesalahan memilih mode ini hanya terlihat pada data yang jatuh tepat di batas — dan data seperti itu hampir selalu muncul pada nilai uang yang bulat.

histogram2d: Distribusi Dua Variabel dalam Satu Matriks #

Korelasi merangkum hubungan dua variabel dalam satu angka, seperti dibahas pada Korelasi dan Kovarians. Bila kita ingin melihat bentuk sebarannya, np.histogram2d(x, y, bins=...) menghitung frekuensi gabungan: sel H[i, j] berisi banyaknya sampel yang x-nya jatuh di bin ke-i dan y-nya di bin ke-j. Fungsi ini mengembalikan tiga nilai: matriks H beserta xedges dan yedges, yaitu batas bin tiap sumbu.

python
import numpy as np

rng = np.random.default_rng(42)
durasi = rng.integers(5, 35, 200)   # lama kunjungan (menit)
item = rng.integers(0, 8, 200)      # banyaknya item dibeli
H, xedges, yedges = np.histogram2d(
    durasi, item, bins=([0, 10, 20, 30, 40], [-0.5, 2.5, 4.5, 7.5])
)
print(H.round(0))
print("xedges:", xedges)
print("yedges:", yedges)
print("total :", H.sum())

Output yang Dihasilkan:

text
[[16.  1. 16.]
 [26. 16. 24.]
 [34. 21. 21.]
 [ 8.  7. 10.]]
xedges: [ 0 10 20 30 40]
yedges: [-0.5  2.5  4.5  7.5]
total : 200.0

Mari kita telaah:

  1. Baris 3-4 (rng.integers): data sintetis ber-seed dengan nilai bulat eksak, sehingga setiap sel H berisi jumlah yang bulat; H sendiri tetap bertipe float64.
  2. Baris 5-7 (bins=...): dua list batas eksplisit menghasilkan 4 bin untuk durasi dan 3 bin untuk item, sehingga H berbentuk (4, 3); H.sum() mengembalikan 200.0, persis banyaknya data.
  3. Baris 8 (H.round(0)): karena hasil histogram2d bertipe float, kita bulatkan untuk tampilan yang bersih.
  4. xedges dan yedges: batas bin per sumbu yang benar-benar dipakai fungsi — dicatat agar setiap sel H[i, j] tetap bisa ditafsirkan ulang di kemudian hari.

Pola Heatmap Sederhana #

Heatmap menampilkan matriks angka sebagai kumpulan sel berwarna: makin besar nilai sel, makin gelap warnanya. Tanpa pustaka grafik pun polanya bisa kita amati dengan mencetak matriks kecil berlabel:

python
import numpy as np

rng = np.random.default_rng(42)
durasi = rng.integers(5, 35, 200)
item = rng.integers(0, 8, 200)
H, xe, ye = np.histogram2d(
    durasi, item, bins=([0, 10, 20, 30, 40], [-0.5, 2.5, 4.5, 7.5])
)
header = "".join(f"{h:>5}" for h in ["0-2", "3-4", "5-7"])
label = ["  0-9", "10-19", "20-29", "30-39"]
print("menit  " + header)
for i in range(4):
    print(f"{label[i]}: " + "".join(f"{int(H[i, j]):5d}" for j in range(3)))

Output yang Dihasilkan:

text
menit    0-2  3-4  5-7
  0-9:    16    1   16
10-19:    26   16   24
20-29:    34   21   21
30-39:     8    7   10

Matriks kecil ini sudah menceritakan pola: sesi 20-29 menit paling banyak berakhir tanpa pembelian atau dengan 0-2 item saja (34), sedangkan kunjungan 30-39 menit jarang terjadi (25 total). Dalam pustaka visualisasi, matriks H inilah yang diberi warna per sel; int(H[i, j]) dan format :5d pada kode hanya merapikan tampilan teksnya.

Keluarga histogram masih lebih luas lagi. Untuk lebih dari dua variabel, np.histogramdd melakukan hal yang sama dan mengembalikan array N dimensi beserta daftar batas per sumbu. Untuk melihat batas bin yang diusulkan otomatis sebelum menetapkannya, np.histogram_bin_edges(data, bins=4) menghitung batasnya tanpa menghitung frekuensi:

python
import numpy as np

pengeluaran = np.array([45, 120, 680, 320, 90, 500, 1000, 75])
print(np.histogram_bin_edges(pengeluaran, bins=4))

Output yang Dihasilkan:

text
[  45.    283.75  522.5   761.25 1000.  ]

Bila batas bin ingin mengikuti kuantil data — misalnya tiap kelas berisi seperempat pelanggan — kombinasikan np.percentile dari quantile dan percentile dengan np.digitize: batasnya adalah kuantil-kuantil itu sendiri.