Idenya
Rata-rata menyembunyikan banyak hal. Dua toko bisa sama-sama punya rata-rata Rp 400.000 per order: satu dengan setiap order di sekitar Rp 400.000, yang lain dengan banyak order kecil dan beberapa order yang sangat besar. Keduanya butuh strategi berbeda. Grafik distribusi menunjukkan seluruh sebaran, bukan hanya bagian tengahnya.
Kamu sudah bertemu histogram. Modul ini menambahkan alat untuk membandingkan distribusi antar kelompok: box plot, violin plot dan strip plot.
import pandas as pd
import plotly.express as px
sales = pd.read_csv("sales.csv")
completed = sales[sales["status"] == "completed"]
orders = (completed.groupby(["order_id", "channel", "segment"], as_index=False)["revenue"].sum()
.rename(columns={"revenue": "order_value"}))
print(orders.head())
print(orders.groupby("channel")["order_value"].describe().round(0))
order_id channel segment order_value
0 1 app Business 89000
1 2 web Consumer 285000
2 3 app Consumer 960000
3 4 app Consumer 195000
4 5 app Consumer 75000
count mean std min 25% 50% 75% max
channel
app 10.0 473400.0 385090.0 75000.0 116250.0 349500.0 834000.0 1024000.0
web 16.0 443875.0 264994.0 89000.0 281250.0 375000.0 666250.0 918000.0
describe() memberi angka-angkanya; grafik di bawah membuatnya terlihat.
Box plot
Apakah pesanan lewat aplikasi biasanya lebih besar daripada lewat website? Rata-rata memberimu satu angka per channel, tapi menyembunyikan seberapa tersebar pesanannya dan apakah ada beberapa pesanan raksasa yang menariknya naik. Box plot menampilkan seluruh distribusi setiap kelompok, berdampingan:
fig = px.box(orders, x="channel", y="order_value", title="Order value by channel")
fig.show()
Cara membaca sebuah box:
| Bagian | Menunjukkan |
|---|---|
| garis di dalam box | median (separuh order di bawahnya, separuh di atasnya) |
| tepi box | persentil ke-25 dan ke-75: 50% order di tengah (interquartile range, IQR) |
| whisker | rentang nilai "normal", sampai 1,5 × IQR di luar box |
| titik di luar whisker | outlier: nilai yang luar biasa kecil atau besar |
Box plot memadatkan sebuah distribusi menjadi lima angka, sehingga beberapa kelompok mudah dibandingkan berdampingan. Arahkan kursor ke sebuah box untuk melihat angka persisnya.
Tampilkan juga titik-titiknya
Dengan kelompok kecil (di sini, 10 order app), sebuah box bisa menyembunyikan betapa sedikitnya titik data. points="all" menggambar setiap observasi di samping box:
fig = px.box(orders, x="channel", y="order_value", points="all",
hover_data=["order_id"], title="Order value by channel")
fig.show()
print(fig.data[0].boxpoints)
all
Selalu ketahui n-mu (jumlah titik per kelompok). Box yang digambar dari 5 order terlihat sama meyakinkannya dengan box dari 5.000 order. Menampilkan titik-titiknya, atau menaruh n di label, menjaga grafiknya tetap jujur.
Strip plot: hanya titik-titiknya
Untuk data kecil, strip plot (setiap titik, digeser sedikit ke samping supaya tidak bertumpuk) sering lebih jelas daripada box:
fig = px.strip(orders, x="channel", y="order_value", color="segment",
title="Every completed order")
fig.show()
Violin plot: bentuknya
Violin adalah histogram yang dihaluskan dan dicerminkan di kedua sisi, sehingga kamu bisa melihat di mana nilai-nilai mengumpul (bagian yang lebar) dan apakah ada dua punuk. box=True menggambar box kecil di dalamnya:
fig = px.violin(orders, x="segment", y="order_value", box=True, points="all",
title="Order value by segment")
fig.show()
print(fig.data[0].type, fig.data[0].box.visible)
violin True
Violin butuh data dalam jumlah yang cukup supaya bermakna; pada segelintir titik, penghalusannya mengarang bentuk yang sebenarnya tidak ada. Pakai untuk ratusan observasi, dan box serta strip untuk yang lebih sedikit.
Histogram dengan grafik marginal
Histogram bisa membawa grafik distribusi kecil di sepanjang tepinya:
fig = px.histogram(orders, x="order_value", nbins=8, marginal="box",
title="Distribution of completed order values")
fig.show()
print([t.type for t in fig.data])
['histogram', 'box']
Histogram menunjukkan bentuknya, box marginal menandai median dan outlier. marginal juga menerima "violin" dan "rug" (satu garis kecil per nilai). Scatter plot mendukung marginal_x dan marginal_y dengan cara yang sama.
Histogram bertumpuk untuk dua kelompok
Kalau kamu lebih suka melihat bentuk utuh setiap kelompok daripada kotak ringkasan, kamu bisa menggambar kedua histogram di sumbu yang sama. Membuat bar-barnya agak transparan memungkinkanmu melihat di mana keduanya tumpang tindih:
fig = px.histogram(orders, x="order_value", color="channel", nbins=8,
barmode="overlay", opacity=0.6)
fig.show()
barmode="overlay" dengan sedikit transparansi membuat kedua distribusi sama-sama terlihat. Dengan ukuran kelompok yang sangat berbeda, tambahkan histnorm="percent" supaya bar setiap kelompok berjumlah 100%, membandingkan bentuk alih-alih jumlah.
Yang mana?
| Pertanyaan | Grafik |
|---|---|
| Seperti apa distribusi satu angka? | histogram (+ marginal="box") |
| Bagaimana beberapa kelompok dibandingkan? | box plot |
| ... dan kelompoknya kecil? | box dengan points="all", atau strip |
| ... dan kelompoknya besar, bentuknya penting? | violin |
Mengapa ini penting untuk kode yang bersih
Hanya melaporkan rata-rata adalah versi analitik dari menelan error: informasinya ada, tapi tersembunyi. Box atau strip plot di samping sebuah KPI menunjukkan sebaran, outlier dan ukuran sampelnya, sehingga keputusan tidak dibuat berdasarkan mean yang menyesatkan. Bangun tabel per observasi dulu (orders, satu baris per order), lalu pilih grafiknya, supaya kamu menggambar pada tingkat detail yang tepat.
Rangkuman
- Distribusi menunjukkan sebaran, bukan hanya rata-rata.
- Box: median, box IQR, whisker, titik outlier;
points="all"menambahkan setiap observasi. - Strip: setiap titik, digeser sedikit; paling cocok untuk kelompok kecil.
- Violin: bentuk yang dihaluskan; paling cocok untuk banyak titik;
box=Truemenambahkan box di dalamnya. px.histogram(..., marginal="box")menambahkan ringkasan di sepanjang tepi;barmode="overlay"danhistnorm="percent"membandingkan kelompok.- Selalu ketahui n per kelompok.