Data sudah bersih berkat chapter Data Cleaning dengan Pandas — sekarang pertanyaan klasik muncul: mulai menganalisis dari mana? Exploratory Data Analysis (EDA) menjawabnya dengan disiplin sederhana: sebelum membangun laporan atau model, kita berkeliling dulu mengumpulkan fakta. Chapter ini memakai penjualan.csv dari chapter Dasar Pandas sebagai lapangan latihan.
Mulai dari Pertanyaan, Bukan Kode #
EDA yang baik diberi arah oleh pertanyaan, bukan oleh daftar function yang hafal. Untuk dataset penjualan ritel, lima pertanyaan pembuka yang hampir selalu relevan:
- Berapa skala bisnisnya — total transaksi, total pendapatan, harga rata-rata?
- Bagaimana sebaran nilai transaksi — merata, atau didominasi beberapa transaksi besar?
- Kategori atau kota mana yang menyumbang terbesar?
- Kolom mana yang saling berhubungan — barang mahal terjual lebih jarang?
- Transaksi mana yang paling besar — adakah pola pada waktunya?
Setiap bagian berikut menjawab satu pertanyaan dengan satu alat pandas. Kita mulai dengan menambahkan kolom turunan total — nilai transaksi per baris:
import pandas as pd
df = pd.read_csv("penjualan.csv")
df["total"] = df["harga"] * df["jumlah"]Tur Keliling describe() #
Ringkasan statistik lima angka plus mean dan standar deviasi terlihat sekali baca, tetapi isinya padat:
print(df.describe())Output yang Dihasilkan:
harga jumlah total
count 24.000000 24.000000 2.400000e+01
mean 242208.333333 3.333333 5.990417e+05
std 189435.082185 1.833663 2.214220e+05
min 95000.000000 1.000000 2.400000e+05
25% 120000.000000 2.000000 4.500000e+05
50% 150000.000000 3.000000 5.850000e+05
75% 275000.000000 4.000000 7.500000e+05
max 750000.000000 8.000000 1.050000e+06Kolom total tampil dalam notasi ilmiah — 2.400000e+01 berarti 2,4 dikali sepuluh pangkat satu, yaitu 24 — karena rentang nilainya lebar, dari 24 hingga 1.050.000, sehingga pandas memilih format kompak. Cara membaca hasil harga: rata-rata Rp242.208 jauh di atas median Rp150.000 (baris 50%), artinya sebagian kecil produk mahal menarik rata-rata ke atas. Jarak kuartil (25% Rp120.000 ke 75% Rp275.000) memuat separuh transaksi, sementara standar deviasi Rp189.435 hampir sebesar rata-rata — sebaran yang lebar. Bandingkan dengan jumlah: median 3, maksimum 8, sebaran rapat.
groupby: Split, Apply, Combine #
Pertanyaan “kategori mana yang paling menguntungkan?” dijawab groupby() lewat tiga fase yang bekerja berurutan:
print(df.groupby("kategori")[["harga", "jumlah"]].mean().round(1))
print()
print(df.groupby("kategori")["total"].agg(["sum", "mean", "count"]))
print()
print(df.groupby("kota")["total"].sum().sort_values(ascending=False))Output yang Dihasilkan:
harga jumlah
kategori
Buku 122571.4 3.1
Elektronik 340000.0 2.8
Fashion 222142.9 4.3
sum mean count
kategori
Buku 2622000 374571.428571 7
Elektronik 7300000 730000.000000 10
Fashion 4455000 636428.571429 7
kota
Surabaya 4915000
Jakarta 4815000
Bandung 4647000
Name: total, dtype: int64Dua tabel pertama membelah data menurut kategori dan langsung memperlihatkan pola utama: Elektronik menyumbang pendapatan terbesar (Rp7,3 juta dari 10 transaksi) karena harga per unitnya tinggi, sementara Fashion menjual unit terbanyak rata-rata (4,3 per transaksi) meski totalnya lebih kecil. Tabel ketiga memeringkat kontribusi per kota — selisihnya tipis: Surabaya unggul Rp100.000 atas Jakarta. Fungsi agg(["sum", "mean", "count"]) menghitung beberapa statistik sekaligus, dan sort_values(ascending=False) langsung memeringkatkan hasil.
Tabel Silang, Proporsi, dan Korelasi #
Untuk menghitung frekuensi kombinasi dua kolom kategorikal, pd.crosstab() membuat tabel silang tanpa perlu groupby:
print(pd.crosstab(df["kota"], df["kategori"]))
print()
proporsi = (df["kategori"].value_counts(normalize=True) * 100).round(1)
print(proporsi)Output yang Dihasilkan:
kategori Buku Elektronik Fashion
kota
Bandung 3 3 2
Jakarta 2 3 3
Surabaya 2 4 2
kategori
Elektronik 41.7
Fashion 29.2
Buku 29.2
Name: proportion, dtype: float64Tabel silang menunjukkan transaksi tersebar cukup merata — tidak ada kota yang obses pada satu kategori. Parameter normalize=True pada value_counts() mengubah hitungan menjadi proporsi: 41,7% transaksi adalah Elektronik, sisanya terbagi sama antara Fashion dan Buku.
Setelah peta frekuensi, giliran hubungan antar kolom numerik. Metode corr() menghitung korelasi Pearson antar semua kolom numerik sekaligus:
print(df[["harga", "jumlah", "total"]].corr().round(2))Output yang Dihasilkan:
harga jumlah total
harga 1.00 -0.63 0.43
jumlah -0.63 1.00 0.19
total 0.43 0.19 1.00Angka diagonal selalu 1,00 karena setiap kolom berkorelasi sempurna dengan dirinya sendiri. Bacaan yang perlu digarisbawahi: korelasi -0.63 antara harga dan jumlah — produk mahal terjual dalam jumlah lebih sedikit, sesuai intuisi ritel. Sementara total berkorelasi positif dengan harga (0,43) — nilai transaksi besar lebih sering datang dari barang mahal daripada dari pembelian banyak unit.
| Nilai korelasi | Cara membaca |
|---|---|
| mendekati +1 | bergerak searah bersama |
| mendekati 0 | tidak berhubungan linear |
| mendekati -1 | bergerak berlawanan arah |
Transaksi Teratas dan Pemeriksaan Visual #
Metode nlargest(n, kolom) mengambil baris bernilai terbesar tanpa mengurutkan seluruh DataFrame:
print(df.nlargest(3, "total")[["tanggal", "kota", "produk", "total"]])Output yang Dihasilkan:
tanggal kota produk total
15 2025-02-19 Jakarta Speaker Bluetooth 1050000
23 2025-03-16 Surabaya Powerbank 10000mAh 1000000
20 2025-03-07 Surabaya Sepatu Sneakers 900000
```
Tiga transaksi teratas seluruhnya Elektronik dan Fashion — konsisten dengan temuan `groupby` sebelumnya. Tahap akhir EDA selalu visual: pandas menyediakan pintu cepat ke matplotlib lewat metode `.plot`:
```python
import matplotlib.pyplot as plt
ax = df["total"].plot.hist(bins=8, figsize=(7, 4))
ax.set_title("Distribusi Nilai Transaksi")
ax.set_xlabel("Total per transaksi (Rp)")
ax.set_ylabel("Jumlah transaksi")
fig = ax.figure
fig.tight_layout()
fig.savefig("distribusi_total.png", dpi=150)
ax_bar = df.groupby("kategori")["total"].sum().plot.bar(figsize=(7, 4))
ax_bar.set_title("Total Penjualan per Kategori")
ax_bar.set_xlabel("Kategori")
ax_bar.set_ylabel("Total (Rp)")
fig_bar = ax_bar.figure
fig_bar.tight_layout()
fig_bar.savefig("total_per_kategori.png", dpi=150)
print("Plot tersimpan: distribusi_total.png dan total_per_kategori.png")
```
Output yang Dihasilkan:
```text
Plot tersimpan: distribusi_total.png dan total_per_kategori.png
```
Histogram yang dihasilkan menampilkan mayoritas transaksi menumpuk di kiri (di bawah Rp600 ribu) dengan ekor tipis hingga Rp1,05 juta — grafik dari dugaan kemiringan di awal chapter. Grafik batang kedua memperlihatkan Elektronik menjulang tertinggi, disusul Fashion dan Buku — cermin langsung tabel `groupby`. Diagram seperti ini akan dibedah mendalam di dua chapter visualisasi; di tahap EDA, fokus kita adalah kecepatan menjawab pertanyaan.
Sebelum menutup chapter, susun daftar periksa dari seluruh fakta yang terkumpul agar tidak ada temuan yang tertinggal di layar:
- **Skala**: 24 transaksi, total pendapatan Rp14.377.000, rata-rata transaksi Rp599.041.
- **Sebaran**: distribusi `total` miring ke kanan; median lebih jujur daripada mean.
- **Segmentasi**: Elektronik = pendapatan tertinggi; Fashion = unit per transaksi tertinggi.
- **Geografi**: tiga kota nyaris seimbang; tidak ada temuan anomali kota.
- **Hubungan**: korelasi harga-jumlah negatif (-0,63) layak diuji lebih lanjut.
Setiap butir di daftar itu lahir dari satu function pandas. Ketika fakta-fakta seperti ini cukup untuk mengisi laporan, langkah berikutnya adalah membuat grafik yang layak presentasi — materi chapter *Visualisasi dengan Matplotlib*.