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:

  1. Berapa skala bisnisnya — total transaksi, total pendapatan, harga rata-rata?
  2. Bagaimana sebaran nilai transaksi — merata, atau didominasi beberapa transaksi besar?
  3. Kategori atau kota mana yang menyumbang terbesar?
  4. Kolom mana yang saling berhubungan — barang mahal terjual lebih jarang?
  5. 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:

python
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:

python
print(df.describe())

Output yang Dihasilkan:

text
               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+06

Kolom 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:

python
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:

text
               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: int64

Dua 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:

python
print(pd.crosstab(df["kota"], df["kategori"]))
print()
proporsi = (df["kategori"].value_counts(normalize=True) * 100).round(1)
print(proporsi)

Output yang Dihasilkan:

text
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: float64

Tabel 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:

python
print(df[["harga", "jumlah", "total"]].corr().round(2))

Output yang Dihasilkan:

text
        harga  jumlah  total
harga    1.00   -0.63   0.43
jumlah  -0.63    1.00   0.19
total    0.43    0.19   1.00

Angka 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 korelasiCara membaca
mendekati +1bergerak searah bersama
mendekati 0tidak berhubungan linear
mendekati -1bergerak berlawanan arah

Transaksi Teratas dan Pemeriksaan Visual #

Metode nlargest(n, kolom) mengambil baris bernilai terbesar tanpa mengurutkan seluruh DataFrame:

python
print(df.nlargest(3, "total")[["tanggal", "kota", "produk", "total"]])

Output yang Dihasilkan:

text
       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*.