Analisis data yang terarah dimulai dari hal yang tampak paling sederhana: memeriksa satu variabel sampai tuntas. Analisis univariat adalah pemeriksaan satu kolom pada satu waktu — profilnya, bentuk sebarannya, nilai yang menonjol, hingga pola nilai kosongnya. Langkah ini terasa biasa, tetapi hampir semua kesalahan analisis yang serius berakar pada satu kolom yang belum dipahami: rata-rata yang ditarik nilai ekstrem, kategori yang luput tercatat, atau persentase yang dihitung dari data yang sebagian kosong. Pada chapter ini kita menyusun prosedur baku untuk menganalisis satu variabel, lalu menjalankannya tuntas pada satu dataset kecil.

Kerangka Pertanyaan untuk Satu Kolom #

Analisis univariat bukan sekadar memanggil satu fungsi, melainkan mengajukan daftar pertanyaan yang sama ke setiap kolom. Lima pertanyaan berikut membentuk kerangka kerja yang bisa kita pakai ulang di dataset apa pun:

PertanyaanUntuk kolom numerikUntuk kolom kategorikal
Di mana nilai berkumpul?mean, mediankategori terbanyak (modus)
Seberapa lebar sebarannya?simpangan baku, kuartiljumlah kategori
Bagaimana bentuk sebarannya?kemiringan (skewness)proporsi kategori dominan
Ada nilai yang menonjol?nilai minimum, maksimum, pencilankategori yang sangat jarang
Ada nilai yang kosong?jumlah dan letak NaNkategori “tidak tercatat”

Rumus tendensi sentral dan penyebaran telah kita bahas pada chapter Ukuran Tendensi Sentral dan Ukuran Penyebaran , dan latihan praktisnya sudah kita cicipi pada Analisis Data Numerik . Peran chapter ini berbeda: kita menyusun seluruh pemeriksaan menjadi satu prosedur yang berurutan dan bisa direproduksi — profil numerik, profil kategorikal, kemiringan, lalu pola kosong — sebelum kita berani menyentuh hubungan antar variabel.

Dataset Catatan Transaksi Toko Kopi Kita #

Kita bekerja pada 40 transaksi dari Toko Kopi Kita yang memuat tiga kolom substantif: menu (kategorikal), nilai_ribu (nilai transaksi dalam ribuan rupiah), dan menunggu_menit (lama pesanan disiapkan). Kolom id hanyalah penomoran baris. Dataset ini sengaja memuat lima sel kosong dan satu pesanan katering seharga 150 ribu rupiah agar setiap pertanyaan pada kerangka di atas punya jawaban yang nyata:

csv
id,menu,nilai_ribu,menunggu_menit
1,kopi susu,22,5
2,kopi susu,18,4
3,kopi susu,26,6
4,kopi susu,21,5
5,kopi susu,19,7
6,kopi susu,24,4
7,kopi susu,20,5
8,kopi susu,23,6
9,kopi susu,19,8
10,kopi susu,25,5
11,kopi susu,150,8
12,kopi susu,21,4
13,kopi susu,22,6
14,kopi susu,24,5
15,kopi hitam,17,6
16,kopi hitam,19,5
17,kopi hitam,16,4
18,kopi hitam,20,6
19,kopi hitam,18,5
20,kopi hitam,17,7
21,kopi hitam,,5
22,kopi hitam,,6
23,kopi hitam,,4
24,espresso,20,4
25,espresso,24,5
26,espresso,22,6
27,espresso,21,5
28,espresso,23,3
29,espresso,22,5
30,espresso,21,6
31,matcha latte,32,8
32,matcha latte,36,7
33,matcha latte,30,6
34,matcha latte,38,8
35,matcha latte,34,7
36,matcha latte,33,6
37,teh tawar,16,3
38,teh tawar,15,3
39,,21,5
40,,19,4

Profil Numerik dengan describe() #

Fungsi describe() merangkum delapan statistik dalam satu panggilan. Kita menerapkannya pada dua kolom numerik substantif — kolom id sengaja dikeluarkan karena penomoran baris bukan variabel yang dianalisis:

python
import pandas as pd

transaksi = pd.read_csv("transaksi.csv")

print(transaksi[["nilai_ribu", "menunggu_menit"]].describe().round(2))
print()
print(transaksi.describe(include="object"))

Output yang Dihasilkan:

text
       nilai_ribu  menunggu_menit
count       37.00           40.00
mean        26.16            5.42
std         21.68            1.38
min         15.00            3.00
25%         19.00            4.75
50%         21.00            5.00
75%         24.00            6.00
max        150.00            8.00

             menu
count          38
unique          5
top     kopi susu
freq           14

Mari kita baca hasilnya per bagian:

  1. count: nilai_ribu terhitung 37 dari 40 baris — tiga sel kosong otomatis dilewati, dan selisih 40 - 37 adalah informasi, bukan sekadar keterbatasan. menunggu_menit lengkap 40.
  2. mean vs 50% (median): pada nilai_ribu, mean 26,16 berada jauh di atas median 21,00 — sinyal awal sebaran yang miring ke kanan. Pada menunggu_menit, mean 5,42 dan median 5,00 hampir berimpitan — sebaran yang relatif seimbang.
  3. max vs kuartil: tiga perempat transaksi bernilai 24 ribu ke bawah, tetapi max melonjak ke 150 — pesanan katering itu sendirian di ekor kanan, sementara std 21,68 ikut membengkak karenanya.
  4. describe(include="object"): profil ringkas kolom kategorikal — 38 nilai tercatat, 5 kategori unik, kategori terbanyak kopi susu dengan 14 kemunculan.

Profil Kategorikal dengan value_counts() #

Untuk kolom kategorikal, value_counts() adalah padanan describe(): ia menghitung frekuensi setiap kategori. Dua argumen membuat hasilnya jujur — dropna=False agar kategori “tidak tercatat” ikut tampil, dan normalize=True agar kita sekaligus memperoleh proporsi:

python
import pandas as pd

transaksi = pd.read_csv("transaksi.csv")

jumlah = transaksi["menu"].value_counts(dropna=False)
proporsi = transaksi["menu"].value_counts(dropna=False, normalize=True)

print(pd.DataFrame({"jumlah": jumlah, "proporsi": proporsi.round(3)}))

Output yang Dihasilkan:

text
              jumlah  proporsi
menu                          
kopi susu         14     0.350
kopi hitam         9     0.225
espresso           7     0.175
matcha latte       6     0.150
teh tawar          2     0.050
NaN                2     0.050

Bedah hasilnya:

  1. Modus terbaca langsung: kopi susu mendominasi 35% transaksi — menu andalan yang sehat untuk stok, tetapi juga menandai ketergantungan pada satu produk.
  2. NaN tampil sebagai baris: dua transaksi (5%) tidak mencatat menunya. Tanpa dropna=False, baris ini diam-diam hilang dan tabel terlihat lebih bersih daripada kenyataannya.
  3. Kategori langka tetap penting: teh tawar hanya 5% — terlalu kecil untuk disimpulkan sendirian, tetapi cukup untuk menandainya saat kita membandingkan kelompok pada analisis berikutnya.

Membaca Kemiringan Sebaran #

Selisih mean dan median pada nilai_ribu tadi mengundang pertanyaan: seberapa miring sebarannya? Koefisien kemiringan (skew()) menjawab dengan satu angka — positif berarti ekor memanjang ke kanan, negatif berarti ekor memanjang ke kiri:

python
import pandas as pd

transaksi = pd.read_csv("transaksi.csv")

for kolom in ["nilai_ribu", "menunggu_menit"]:
    s = transaksi[kolom]
    print(f"{kolom:15s} skew {s.skew():6.2f} | mean {s.mean():6.2f} | median {s.median():6.2f}")

Output yang Dihasilkan:

text
nilai_ribu      skew   5.46 | mean  26.16 | median  21.00
menunggu_menit  skew   0.23 | mean   5.42 | median   5.00

Sebagai bahasa bersama, patokan berikut lazim dipakai untuk membaca angka kemiringan:

Nilai skewnessBentuk sebaranKonsekuensi praktis
-0,5 sampai 0,5hampir simetrismean dan median sama-sama layak dipakai
-1 sampai -0,5 atau 0,5 sampai 1miring moderatutamakan median saat meringkas
di bawah -1 atau di atas 1miring ekstremperiksa pencilan sebelum meringkas

nilai_ribu mencatat 5,46 — jauh di wilayah ekstrem karena satu pesanan katering 150 ribu menarik ekor kanan sejauh itu. menunggu_menit bernilai 0,23, hampir simetris. Bentuknya bisa kita lihat langsung pada histogram berikut:

python
import matplotlib.pyplot as plt
import pandas as pd

transaksi = pd.read_csv("transaksi.csv")

plt.hist(transaksi["nilai_ribu"].dropna(), bins=12, edgecolor="white")
plt.xlabel("Nilai transaksi (ribu rupiah)")
plt.ylabel("Jumlah transaksi")
plt.title("Distribusi nilai transaksi Toko Kopi Kita")
plt.show()

Histogram yang tergambar menampilkan satu dinding batang yang tinggi dan rapat di sisi kiri — mayoritas transaksi berkumpul pada kisaran 15 sampai 38 ribu — lalu sebaran tipis menurun, dan satu batang tunggal berdiri terpisah jauh di ujung kanan pada kisaran 150 ribu. Bentuk seperti inilah wujud visual kemiringan +5,46: kerumunan di kiri, ekor panjang ke kanan. Untuk menunggu_menit, histogram akan menampilkan batang yang naik lalu turun secara berimbang di sekitar nilai 5.

Membedah Pola Nilai Kosong #

Pertanyaan terakhir pada kerangka kita menuntut prosedur tiga langkah: hitung nilai kosong per kolom, temukan baris yang memuatnya, lalu duga mekanismenya. Ketiganya dijalankan satu blok kode:

python
import pandas as pd

transaksi = pd.read_csv("transaksi.csv")

print(transaksi.isna().sum())
print()
print("Baris dengan sel kosong:", transaksi.isna().any(axis=1).sum(), "dari", len(transaksi))
print()
print(transaksi[transaksi.isna().any(axis=1)])

Output yang Dihasilkan:

text
id                0
menu              2
nilai_ribu        3
menunggu_menit    0
dtype: int64

Baris dengan sel kosong: 5 dari 40

    id        menu  nilai_ribu  menunggu_menit
20  21  kopi hitam         NaN               5
21  22  kopi hitam         NaN               6
22  23  kopi hitam         NaN               4
38  39         NaN        21.0               5
39  40         NaN        19.0               4

Temuan dari pola tersebut:

  1. Kosong tidak tersebar merata: lima sel kosong berkumpul pada lima baris, dan tiga di antaranya (transaksi 21-23) semuanya bermenu kopi hitam dengan nilai_ribu yang kosong. Pola berkelompok seperti ini biasanya menandakan sumber masalah yang sama — misalnya satu sesi pencatatan yang gagal — bukan kecelakaan acak per sel.
  2. Dampaknya sudah terukur: rata-rata nilai_ribu untuk kopi hitam kelak hanya dihitung dari enam transaksi, bukan sembilan. Setiap ringkasan per kelompok perlu menyertakan count agar pembaca tahu dasar hitungnya.
  3. Mekanisme kosong menentukan penanganan: kosong yang benar-benar acak (missing completely at random) relatif aman diabaikan, sedangkan kosong yang berkaitan dengan kategori tertentu (missing at random) berpotensi membuat kelompok itu tampak lebih baik atau lebih buruk dari kenyataannya. Diagnosis seluruh strategi penanganan — mengisi, menandai, atau menimbang — dibahas pada chapter Menangani Missing Values .

Rangkuman #

  • Analisis univarat memakai kerangka lima pertanyaan yang sama untuk setiap kolom: pusat, sebaran, bentuk, nilai menonjol, dan nilai kosong.
  • describe() merangkum kolom numerik dan describe(include="object") merangkum kolom kategorikal; value_counts(dropna=False, normalize=True) memberi profil frekuensi yang jujur terhadap data tak tercatat.
  • Kemiringan dibaca lewat skew() dan diperkuat perbandingan mean vs median; sebaran miring ekstrem membuat median dan kuartil lebih mewakili daripada mean.
  • Pola nilai kosong diperiksa tiga langkah — jumlah per kolom, baris yang terdampak, dugaan mekanisme — karena mekanisme kosong menentukan penanganan yang sah.

Prosedur ini memberi kita profil utuh untuk setiap kolom, tetapi pertanyaan bisnis nyata hampir selalu menyandingkan dua hal: apakah menu menentukan nilai transaksi? Apakah pelanggan yang menunggu lama bertransaksi lebih kecil? Menyandingkan dua variabel adalah pekerjaan chapter berikutnya, Analisis Bivariat .

Referensi #

  1. pandas — User Guide
  2. pandas — Working with Missing Data
  3. NumPy — Absolute Beginners