Rata-rata durasi kunjungan pelanggan Toko Kopi Kita tercatat 54 menit — angka itu nyaris tidak berbicara apa-apa. Berapa pelanggan yang singkat 20 menit? Apakah ada yang duduk sampai dua jam? Pertanyaan-pertanyaan tentang sebaran seperti ini dijawab oleh keluarga grafik distribusi, bukan oleh angka rangkuman. Pada chapter ini kita bedah histogram sebagai mesin penghitungnya, melihat bagaimana jumlah bin mengubah cerita yang disampaikan, lalu berkenalan dengan dua turunannya: kurva kepadatan (density plot) dan violin plot untuk membandingkan sebaran antar kelompok.

Apa Itu Distribusi #

Distribusi adalah gambaran bagaimana nilai-nilai sebuah variabel numerik tersebar: di mana nilainya berkumpul, seberapa lebar sebarannya, dan apakah ada nilai yang menyendiri. Pertanyaan khasnya berbunyi “bagaimana sebarannya?” atau “nilai yang umum itu berapa?”. Variabel yang cocok adalah satu kolom numerik mentah — durasi kunjungan, nilai transaksi, umur pelanggan — bukan hasil agregasi per kategori seperti pada grafik perbandingan.

Angka rangkuman seperti rata-rata memang sering tidak cukup. Dua kelompok pelanggan yang berbeda perilaku bisa menghasilkan rata-rata yang sama dengan satu kelompok yang seragam, dan hanya distribusilah yang bisa membedakan keduanya. Kita akan menemukan kasus persis seperti itu pada data latihan chapter ini.

Histogram: Mesin Penghitung Interval #

Histogram bekerja dengan mekanisme yang sederhana sekali: rentang nilai dibagi menjadi beberapa interval bernama bin, lalu setiap bin dihitung berapa banyak nilai yang jatuh ke dalamnya. Tinggi batang pada histogram adalah hasil hitungan itu. Sebelum menggambar, kita jalankan mekanismenya secara terbuka memakai np.histogram():

python
import numpy as np

rng = np.random.default_rng(42)
hari_kerja = rng.normal(40, 8, 25).round().astype(int)     # menit
akhir_pekan = rng.normal(75, 12, 15).round().astype(int)   # menit
durasi = np.concatenate([hari_kerja, akhir_pekan])

print("Jumlah pelanggan :", len(durasi))
print("Rata-rata        :", round(durasi.mean(), 1), "menit")
print("Terkecil         :", durasi.min(), "menit")
print("Terbesar         :", durasi.max(), "menit")

jumlah, batas = np.histogram(durasi, bins=5)
print()
print("Menghitung per interval (5 bin):")
for n, bawah, atas in zip(jumlah, batas[:-1], batas[1:]):
    print(f"  {bawah:3.0f}-{atas:3.0f} menit : {n:2d} pelanggan")

Output yang Dihasilkan:

text
Jumlah pelanggan : 40
Rata-rata        : 53.7 menit
Terkecil         : 24 menit
Terbesar         : 101 menit

Menghitung per interval (5 bin):
   24- 39 menit : 11 pelanggan
   39- 55 menit : 14 pelanggan
   55- 70 menit :  5 pelanggan
   70- 86 menit :  8 pelanggan
   86-101 menit :  2 pelanggan

Mari kita telaah baris-barisnya:

  1. Baris 3-6: 40 durasi kunjungan dibangkitkan dari dua populasi berbeda — 25 pelanggan hari kerja yang rata-rata 40 menit dan 15 pelanggan akhir pekan yang rata-rata 75 menit — dengan seed 42 agar hasilnya dapat direproduksi persis.
  2. Baris 13 (np.histogram(..., bins=5)): fungsi ini mengembalikan dua hal: jumlah berisi banyaknya nilai per bin, dan batas berisi tepi interval. Seluruh isi histogram sesungguhnya ada di dua larik ini.
  3. Baris 16-17: loop mencetak pasangan tepi interval dan isinya — persis baris yang akan digambar sebagai batang oleh ax.hist().

Perhatikan pola pada hasil hitungannya: dua interval pertama menampung 25 pelanggan, interval ketiga hanya 5, lalu interval keempat naik lagi ke 8. Angka-angka itu mengisyaratkan dua gundukan yang terpisah — dan memang, datanya memang datang dari dua perilaku berbeda. Rata-rata 53,7 menit tidak menyentuh satu pun kelompok; rata-rata berada di wilayah yang justru nyaris kosong.

Dengan mekanisme yang sama, ax.hist() menggambar seluruh proses itu dalam satu panggilan:

python
import matplotlib.pyplot as plt
import numpy as np

rng = np.random.default_rng(42)
hari_kerja = rng.normal(40, 8, 25).round().astype(int)
akhir_pekan = rng.normal(75, 12, 15).round().astype(int)
durasi = np.concatenate([hari_kerja, akhir_pekan])

fig, ax = plt.subplots(figsize=(6, 3.5))
ax.hist(durasi, bins=8, color="tab:blue", edgecolor="white")
ax.set_title("Durasi Kunjungan Pelanggan")
ax.set_xlabel("Durasi kunjungan (menit)")
ax.set_ylabel("Jumlah pelanggan")
plt.show()

Grafik yang muncul memuat delapan batang yang membentuk dua gundukan: gundungan kiri terdiri atas tiga batang di rentang 24-53 menit yang menampung 25 pelanggan dengan puncak di rentang 34-43 menit (11 pelanggan), lalu satu batang kosong di rentang 53-62 menit sebagai lembah pemisah, dan gundungan kanan menurun dari rentang 62-72 menit (6 pelanggan) sampai 91-101 menit (1 pelanggan) yang menampung 15 pelanggan akhir pekan. Dua puncak dengan lembah di tengah adalah bentuk klasik data yang terdiri atas dua kelompok — temuan yang tidak akan pernah muncul dari rata-rata saja.

Jumlah Bin Mengubah Cerita #

Histogram menuntut satu keputusan yang tidak diambilkan oleh library: berapa bin yang dipakai. Terlalu sedikit, pola yang penting melebur; terlalu banyak, derau acak mengambil alih. Kita bandingkan dua kutubnya pada data yang sama:

python
import matplotlib.pyplot as plt
import numpy as np

rng = np.random.default_rng(42)
hari_kerja = rng.normal(40, 8, 25).round().astype(int)
akhir_pekan = rng.normal(75, 12, 15).round().astype(int)
durasi = np.concatenate([hari_kerja, akhir_pekan])

fig, (kiri, kanan) = plt.subplots(1, 2, figsize=(9, 3.5), sharey=True)
kiri.hist(durasi, bins=3, color="tab:blue", edgecolor="white")
kiri.set_title("Terlalu kasar: 3 bin")
kiri.set_xlabel("Durasi (menit)")
kiri.set_ylabel("Jumlah pelanggan")
kanan.hist(durasi, bins=30, color="tab:blue", edgecolor="white")
kanan.set_title("Terlalu halus: 30 bin")
kanan.set_xlabel("Durasi (menit)")
plt.show()

Gambar kiri memuat tiga batang lebar: satu batang raksasa di rentang 24-50 menit dengan 24 pelanggan, lalu dua batang kecil menurun — kesan yang muncul hanyalah “mayoritas singkat, sebagian lama”, dan lembah pemisah dua kelompok hampir tidak terbaca. Gambar kanan memuat tiga puluh batang kurus yang naik-turun tak berpola antara 0 dan 4 pelanggan; derau acak mengaburkan kedua gundungan yang sebenarnya ada. Dengan 40 data, bin di kisaran 5-12 biasanya tepat — versi delapan bin pada contoh sebelumnya memperlihatkan dua kelompok dengan jelas tanpa memuat derau.

Kurva Kepadatan (Density Plot) #

Kurva kepadatan, umum disebut kernel density estimate (KDE), adalah pasangan mulus dari histogram. Cara kerjanya bisa dibayangkan seperti ini: setiap titik data menyumbang satu bukit kecil berbentuk lonceng, lalu seluruh bukit dijumlahkan menjadi satu kurva mulus. Hasilnya menghapus ketegantungan pada jumlah bin dan membuat bentuk umum sebaran lebih mudah dibanding antar kelompok. Kombinasi keduanya tinggal satu argumen di seaborn:

python
import matplotlib.pyplot as plt
import numpy as np
import seaborn as sns

rng = np.random.default_rng(42)
hari_kerja = rng.normal(40, 8, 25).round().astype(int)
akhir_pekan = rng.normal(75, 12, 15).round().astype(int)
durasi = np.concatenate([hari_kerja, akhir_pekan])

sns.histplot(x=durasi, bins=8, kde=True, color="tab:blue")
plt.title("Durasi Kunjungan Pelanggan")
plt.xlabel("Durasi kunjungan (menit)")
plt.ylabel("Jumlah pelanggan")
plt.show()

Gambar yang dihasilkan memuat batang histogram yang sama dengan contoh sebelumnya, kini ditambah satu kurva gelap yang melengkung mengikuti puncak-puncak batang: kurva itu naik membentuk bukit pertama di sekitar 40 menit, turun mendekati nol di wilayah 55-60 menit, lalu membentuk bukit kedua yang lebih rendah di sekitar 75 menit. Dua bukit pada kurva inilah pesan utamanya — durasi kunjungan terbagi menjadi dua dunia, dan setiap penonton grafik menangkapnya tanpa perlu menghitung batang.

Perlu dicatat bahwa sumbu tegak kurva KDE bukan lagi “jumlah pelanggan”, melainkan kepadatan; saat kurva dan batang digambar bersama, seaborn mengubah skala batang agar keduanya cocok secara visual. Nilai yang bisa dibaca langsung dari kurva adalah bentuk dan posisi puncaknya, bukan jumlah pengunjung.

Violin Plot: Membandingkan Sebaran Antar Kelompok #

Saat pertanyaannya berubah menjadi “bagaimana perbedaan sebaran antar kelompok?”, violin plot memadukan dua kurva KDE menjadi satu bentuk yang mudah dibandingkan berdampingan. Bentuknya seperti biola: makin lebar pada nilai tertentu, makin banyak data di sekitar nilai itu.

python
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
import seaborn as sns

rng = np.random.default_rng(42)
hari_kerja = rng.normal(40, 8, 25).round().astype(int)
akhir_pekan = rng.normal(75, 12, 15).round().astype(int)

kunjungan = pd.DataFrame({
    "durasi": np.concatenate([hari_kerja, akhir_pekan]),
    "jenis_hari": ["hari kerja"] * 25 + ["akhir pekan"] * 15,
})

sns.violinplot(data=kunjungan, x="jenis_hari", y="durasi", hue="jenis_hari",
               palette=["tab:blue", "tab:orange"], legend=False)
plt.title("Sebaran Durasi Kunjungan")
plt.xlabel("Jenis hari")
plt.ylabel("Durasi kunjungan (menit)")
plt.show()

Gambar yang muncul memuat dua bentuk biola berdampingan: biola biru “hari kerja” gemuk di sekitar 35-45 menit dan meruncing cepat, sedangkan biola oranye “akhir pekan” bergeser ke kanan dengan badan lebih panjang yang melandai dari sekitar 65 sampai 90 menit — kunjungan akhir pekan bukan hanya lebih lama rata-ratanya, tetapi juga lebih bervariasi. Seaborn kita pakai di sini sebagai selingan; library ini dibahas tuntas pada chapter Visualisasi dengan Seaborn.

Rangkuman #

  • Distribusi menjawab pertanyaan “bagaimana sebarannya?” pada satu variabel numerik — sesuatu yang tidak dijawab rata-rata.
  • Histogram menghitung banyaknya nilai per bin lalu menggambarnya sebagai batang; np.histogram() memperlihatkan mesin hitungnya secara terbuka.
  • Jumlah bin adalah keputusan analis: terlalu sedikit meleburkan pola, terlalu banyak memunculkan derau; untuk 40 data, kisaran 5-12 bin umumnya tepat.
  • Kurva KDE menghaluskan histogram menjadi kurva kepadatan yang bentuk dan puncaknya mudah dibaca, meski sumbunya bukan lagi jumlah.
  • Violin plot menyandingkan kurva kepadatan dua kelompok sehingga perbedaan pusat dan lebar sebarannya terlihat seketika.

Dua puncak pada durasi kunjungan mengingatkan kita bahwa variabel-variabel kerap saling terkait: durasi dengan jenis hari, nilai transaksi dengan jam kedatangan. Untuk melihat keterkaitan dua variabel numerik sekaligus, kita berpindah ke keluarga grafik berikutnya pada chapter Grafik Hubungan.

Referensi #

  1. Seaborn — Tutorial — panduan resmi seaborn untuk plot distribusi, termasuk histogram, KDE, dan violin plot.
  2. Matplotlib — Plot Types — referensi resmi jenis plot, termasuk histogram dan statistiknya.
  3. NumPy — Absolute Beginners — pengantar array NumPy yang menjadi dasar np.histogram().