Kolom kategorikal sering dianggap “cuma label” dan kurang mendapat perhatian dibanding kolom angka. Padahal banyak temuan penting justru bersembunyi di sana: menu yang paling sering dipesan, cabang yang polanya berbeda, hingga label yang tidak konsisten yang membuat hitungan meleset. Pada chapter ini kita mengolah kolom kategorikal Toko Kopi Kita secara utuh — dari memeriksa nilai uniknya, merapikan label yang berubah-ubah, mencari modus, sampai membaca proporsi berlapis dari tabulasi silang.
Memeriksa dan Merapikan Kategori #
Analisis kategorikal selalu dimulai dari pertanyaan sederhana: nilai apa saja yang benar-benar tercatat? Kita periksa catatan 12 pesanan yang baru diketik ulang oleh dua barista berbeda:
import pandas as pd
pesanan = pd.DataFrame({
"menu": ["kopi susu", "Kopi Susu", "kopi susu", "kopi-susu", "teh tawar",
"Teh Tawar", "teh tawar", "matcha latte", "Matcha Latte",
"matcha latte", "kopi susu", "teh tawar"],
"cabang": ["Bandung", "Bandung", "Surabaya", "Bandung", "Surabaya",
"Bandung", "Surabaya", "Bandung", "Surabaya", "Bandung",
"Surabaya", "Surabaya"],
})
print("Nilai unik :", pesanan["menu"].unique().tolist())
print("Jumlah unik:", pesanan["menu"].nunique())
print(pesanan["menu"].value_counts())Output yang Dihasilkan:
Nilai unik : ['kopi susu', 'Kopi Susu', 'kopi-susu', 'teh tawar', 'Teh Tawar', 'matcha latte', 'Matcha Latte']
Jumlah unik: 7
menu
kopi susu 3
teh tawar 3
matcha latte 2
kopi-susu 1
Kopi Susu 1
Teh Tawar 1
Matcha Latte 1
Name: count, dtype: int64Tujuh nilai unik untuk tiga menu yang sebenarnya — Kopi Susu, kopi-susu, dan kopi susu adalah tiga label untuk minuman yang sama. Tanpa perapian, frekuensi menu terpecah dan top pada describe() bisa menunjuk menu yang keliru. Perbaikannya adalah pemetaan lewat replace(), lalu menyimpannya sebagai kolom baru:
import pandas as pd
# Tabel yang sama dengan blok sebelumnya, dibangun lagi agar blok mandiri.
pesanan = pd.DataFrame({
"menu": ["kopi susu", "Kopi Susu", "kopi susu", "kopi-susu", "teh tawar",
"Teh Tawar", "teh tawar", "matcha latte", "Matcha Latte",
"matcha latte", "kopi susu", "teh tawar"],
"cabang": ["Bandung", "Bandung", "Surabaya", "Bandung", "Surabaya",
"Bandung", "Surabaya", "Bandung", "Surabaya", "Bandung",
"Surabaya", "Surabaya"],
})
peta = {
"Kopi Susu": "kopi susu",
"kopi-susu": "kopi susu",
"Teh Tawar": "teh tawar",
"Matcha Latte": "matcha latte",
}
pesanan["menu_bersih"] = pesanan["menu"].replace(peta)
print(pesanan["menu_bersih"].value_counts())
print()
print("Modus:", pesanan["menu_bersih"].mode().tolist())Output yang Dihasilkan:
menu_bersih
kopi susu 5
teh tawar 4
matcha latte 3
Name: count, dtype: int64
Modus: ['kopi susu']Bedah kode di atas:
petamemasangkan tiap label menyimpang dengan bentuk bakunya.replace(peta)menukar seluruh kemunculannya sekaligus — jauh lebih aman daripada mengedit baris satu per satu.- Kolom baru
menu_bersihmenyimpan hasil terjemahan tanpa menghapus kolom asli, sehingga kita tetap bisa menelusuri kembali ke catatan awal. mode()mengembalikan nilai yang paling sering muncul. Hasilnya berupa list (bukan satu nilai) karena seri data bisa saja seri antara dua kategori — kategori dengan hitungan sama besar semuanya dikembalikan.
Setelah perapian, hitungan menjadi jujur: kopi susu 5, teh tawar 4, matcha latte 3 — dan modusnya kopi susu.
Tabulasi Silang dan Proporsi Berlapis #
Hitungan satu kolom menjawab “apa yang paling sering secara keseluruhan”. Tabulasi silang menambah dimensi: bagaimana pola menu berbeda antar cabang? Kita susun lagi matriks hitungan dari chapter Analisis Frekuensi, kali ini dengan kolom yang sudah bersih:
import pandas as pd
# Tabel yang sama dengan blok sebelumnya, dibangun lagi agar blok mandiri.
pesanan = pd.DataFrame({
"menu": ["kopi susu", "Kopi Susu", "kopi susu", "kopi-susu", "teh tawar",
"Teh Tawar", "teh tawar", "matcha latte", "Matcha Latte",
"matcha latte", "kopi susu", "teh tawar"],
"cabang": ["Bandung", "Bandung", "Surabaya", "Bandung", "Surabaya",
"Bandung", "Surabaya", "Bandung", "Surabaya", "Bandung",
"Surabaya", "Surabaya"],
})
pesanan["menu_bersih"] = pesanan["menu"].replace({
"Kopi Susu": "kopi susu",
"kopi-susu": "kopi susu",
"Teh Tawar": "teh tawar",
"Matcha Latte": "matcha latte",
})
tabel = pd.crosstab(pesanan["menu_bersih"], pesanan["cabang"])
print(tabel)
print()
print("Proporsi per baris (tiap baris berjumlah 1):")
print(pd.crosstab(pesanan["menu_bersih"], pesanan["cabang"], normalize="index").round(2))Output yang Dihasilkan:
cabang Bandung Surabaya
menu_bersih
kopi susu 3 2
matcha latte 2 1
teh tawar 1 3
Proporsi per baris (tiap baris berjumlah 1):
cabang Bandung Surabaya
menu_bersih
kopi susu 0.60 0.40
matcha latte 0.67 0.33
teh tawar 0.25 0.75Cara membaca kedua tabel tersebut:
- Tabel hitungan menunjukkan pola mentah: kopi susu tercatat 3 di Bandung dan 2 di Surabaya; teh tawar 1 di Bandung tetapi 3 di Surabaya.
normalize="index"mengubah tiap baris menjadi proporsi yang berjumlah 1. Baris teh tawar terbaca 0,25 Bandung dan 0,75 Surabaya — 75% pesanan teh tawar berasal dari Surabaya, padahal Surabaya hanya menyumbang separuh (6 dari 12) pesanan keseluruhan.- Di sinilah letak kekuatan proporsi berlapis: modus global (kopi susu) dan modus lokal (teh tawar di Surabaya) bisa berbeda, dan keduanya sama-sama benar pada wilayahnya masing-masing.
Argumen normalize mengenal tiga nilai. "index" menghitung proporsi per baris seperti di atas, "columns" menghitung proporsi per kolom (berguna untuk mengetahui susunan menu pada tiap cabang), dan "all" menghitung proporsi terhadap keseluruhan tabel — setiap sel menjadi pecahan dari total data.
Rangkuman #
- Mulai analisis kategorikal dari
unique()dannunique(): label menyimpang seperti beda kapital atau tanda hubung memecah frekuensi dan mengaburkan modus. replace()dengan peta label merapikan kategori sekaligus; simpan hasilnya sebagai kolom baru agar jejak data asli tetap ada.mode()menemukan kategori terbanyak; hasilnya berupa list karena kemungkinan ada kategori yang seri.pd.crosstab(..., normalize=...)menghitung proporsi berlapis:"index"per baris,"columns"per kolom,"all"terhadap total — modus global dan modus lokal bisa berbeda.
Kolom kategorikal kini kita kuasai dari pemeriksaan sampai proporsi berlapis. Berikutnya kita kembali ke wilayah angka dengan mata yang lebih tajam: bagaimana merangkum kolom numerik — tendensi sentral, penyebaran, dan letak setiap data di dalam sebaran — serta bagaimana satu nilai ekstrem mengubah kesimpulan kita. Lanjut ke chapter Analisis Data Numerik .