Pada chapter sebelumnya kita merapikan isi satu kolom teks, dan hasilnya memang rapi. Masalah konsistensi yang sesungguhnya baru tampak ketika kita berhenti memandang satu kolom dan mulai membandingkan: Tunai di baris ini dengan Cash di baris itu, nama menu di tabel transaksi dengan nama menu di tabel daftar harga. Dua nilai yang bermakna sama tertulis berbeda, dan komputer menaatinya sebagai dua hal yang tidak berhubungan. Pada chapter ini kita memburu varian penulisan dengan value_counts(), menyatukannya dengan rantai metode .str plus kamus pengganti, lalu melihat bagaimana satu huruf kapital bisa membuat penggabungan dua tabel gagal tanpa satu pun pesan galat.
Varian yang Terlihat dari value_counts #
Kolom kategori yang sehat punya sedikit nilai unik: metode pembayaran di kasir Toko Kopi Kita seharusnya hanya tunai dan qris. Cara tercepat menguji dugaan itu adalah menghitung frekuensi setiap nilai. Tabel rekap di bawah memuat delapan pesanan akhir pekan; kolom menu-nya sudah kita rapikan pada chapter Membersihkan Teks
, sedangkan kolom metode baru kali ini diperiksa.
import pandas as pd
pesanan = pd.DataFrame({
"pemesan": ["Budi", "Siti", "Dewi", "Rani", "Agus",
"Farhan", "Tono", "Sari"],
"menu": ["kopi susu", "es kopi susu", "teh tawar", "americano",
"matcha latte", "kopi susu", "teh tawar", "es kopi susu"],
"metode": ["Tunai", "Cash", "tunai", "QRIS",
"qris", "Cash", "TUNAI", "qris "],
})
print(pesanan)
print()
print("Nilai unik kolom metode:", pesanan["metode"].nunique())
print(pesanan["metode"].value_counts())Output yang Dihasilkan:
pemesan menu metode
0 Budi kopi susu Tunai
1 Siti es kopi susu Cash
2 Dewi teh tawar tunai
3 Rani americano QRIS
4 Agus matcha latte qris
5 Farhan kopi susu Cash
6 Tono teh tawar TUNAI
7 Sari es kopi susu qris
Nilai unik kolom metode: 7
metode
Cash 2
Tunai 1
tunai 1
QRIS 1
qris 1
TUNAI 1
qris 1
Name: count, dtype: int64Mari kita telaah baris-barisnya:
- Baris 3-10 (
pesanan = pd.DataFrame({...})): delapan pesanan dibuat sebagai tabel latihan. Perhatikan kolommetode— sekilas hanya berisi tunai dan QRIS, tetapi penulisannya bervariasi:Tunai,Cash,tunai,QRIS,qris,TUNAI, hingga"qris "yang berakhiran spasi. - Baris 14 (
nunique()): hitungan cepat jumlah nilai unik — hasilnya tujuh. Untuk kolom kategori, angka yang lebih besar dari jumlah kategori sebenarnya selalu menjadi bendera peringatan. - Baris 15 (
value_counts()):Cashmuncul dua kali, sementara keenam nilai lainnya masing-masing sekali. Tujuh label itu sebenarnya hanya mewakili dua metode pembayaran.
Daftar frekuensi yang panjang seperti ini hampir selalu bisa dilacak ke segelintir gejala yang berulang. Tabel berikut memetakan gejala ke alat perbaikannya:
| Gejala pada nilai | Contoh | Alat perbaikan |
|---|---|---|
| Spasi di tepi teks | "qris " | .str.strip() |
| Kapital tak seragam | "TUNAI" vs "tunai" | .str.lower() |
| Istilah berbeda, makna sama | "Cash" vs "tunai" | .replace() dengan kamus |
| Singkatan tidak baku | "JKT" untuk "Jakarta" | .replace() dengan kamus |
Menyatukan Istilah dengan Kamus Pengganti #
Dua gejala pertama sudah kita selesaikan pada chapter sebelumnya dengan .str.strip() dan .str.lower(). Tetapi hasil keduanya tetap menyisakan cash — kata yang bersih ejaannya namun berbeda istilah dari tunai. Tidak ada metode perapikan otomatis yang tahu bahwa dua kata itu bermakna sama; keputusan itu milik kita, maka kita rumuskan sebagai kamus pengganti dan serahkan pada .replace(). Proses ini disebut normalisasi kategori: menyatukan nilai-nilai yang secara bisnis merujuk kategori yang sama.
import pandas as pd
metode = pd.Series(["Tunai", "Cash", "tunai", "QRIS",
"qris", "Cash", "TUNAI", "qris "])
kamus = {"cash": "tunai"}
seragam = (metode.str.strip()
.str.lower()
.replace(kamus))
perbandingan = pd.DataFrame({"asli": metode, "seragam": seragam})
print(perbandingan)
print()
print(seragam.value_counts())Output yang Dihasilkan:
asli seragam
0 Tunai tunai
1 Cash tunai
2 tunai tunai
3 QRIS qris
4 qris qris
5 Cash tunai
6 TUNAI tunai
7 qris qris
tunai 5
qris 3
Name: count, dtype: int64Mari kita telaah rantai normalisasinya:
- Baris 8-10 (
metode.str.strip().str.lower().replace(kamus)): tiga langkah berjalan berurutan — tepi dirapikan, kapital diseragamkan menjadi kecil, baru kamus diterapkan. Urutan ini penting: kamus ditulis untuk bentuk akhir ("cash"), jadi ia harus dikerjakan paling akhir. - Baris 6 (
kamus = {"cash": "tunai"}):.replace()dengan dictionary mengganti nilai yang cocok seluruhnya —"cash"menjaditunai, nilai lain dibiarkan. Karena mencocokkan nilai utuh, kamus ini aman dari salah ganti kata sebagian. - Hasil akhir (
value_counts()): dari tujuh nilai unik tersisa dua kategori —tunailima kali danqristiga kali. Rekap metode pembayaran kini bisa dihitung tanpa memecah kategori.
Kapital yang Membuat Penggabungan Gagal #
Inkonsistensi paling merugikan muncul ketika dua tabel harus dipertemukan. Kasir mencatat menu sebagaimana diketik kasir — Kopi Susu — sedangkan tim harga menyusun daftar harga dengan huruf kecil — kopi susu. Kita coba menggabungkan keduanya dengan pd.merge
untuk membawa harga ke tiap pesanan.
import pandas as pd
pesanan = pd.DataFrame({
"menu": ["Kopi Susu", "Es Kopi Susu", "Teh Tawar", "Americano"],
"jumlah": [3, 1, 2, 2],
})
daftar_harga = pd.DataFrame({
"menu": ["kopi susu", "es kopi susu", "teh tawar",
"americano", "matcha latte"],
"harga": [24000, 26000, 20000, 22000, 28000],
})
gabung = pd.merge(pesanan, daftar_harga, on="menu", how="left")
print(gabung)
print()
print("Baris tanpa harga:", gabung["harga"].isna().sum(), "dari", len(gabung))Output yang Dihasilkan:
menu jumlah harga
0 Kopi Susu 3 NaN
1 Es Kopi Susu 1 NaN
2 Teh Tawar 2 NaN
3 Americano 2 NaN
Baris tanpa harga: 4 dari 4Mari kita telaah kegagalannya:
- Baris 13 (
pd.merge(..., on="menu", how="left")): penggabungan mengacu pada kolommenudi kedua tabel. NilaiKopi Susupada tabel kiri dibandingkan dengan nilaikopi susupada tabel kanan — dan dibandingkan secara persis karakter demi karakter, termasuk besar kecil hurufnya. - Kolom
hargayang kosong: tidak ada satu pun kecocokan, sehingga seluruh kolomhargaberisiNaN. Empat dari empat pesanan gagal mendapat harga — padahal semua menunya ada di daftar harga. - Baris 16 (
isna().sum()): satu baris pemeriksaan ini menyelamatkan kita. Tanpa menghitung kekosongan setelah penggabungan, tabel hasil tampak sah dan analisis berikutnya akan berjalan di atas data yang bolong.
Menyeragamkan Kunci Sebelum Menggabungkan #
Perbaikannya mengikuti pelajaran chapter sebelumnya: seragamkan kolom kunci di kedua sisi sebelum menggabungkan. Karena daftar harga sudah memakai huruf kecil, cukup satu gaya penulisan yang kita tetapkan sebagai kunci — di sini bentuk kecil tanpa spasi tepi.
import pandas as pd
pesanan = pd.DataFrame({
"menu": ["Kopi Susu", "Es Kopi Susu", "Teh Tawar", "Americano"],
"jumlah": [3, 1, 2, 2],
})
daftar_harga = pd.DataFrame({
"menu": ["kopi susu", "es kopi susu", "teh tawar",
"americano", "matcha latte"],
"harga": [24000, 26000, 20000, 22000, 28000],
})
pesanan["menu"] = pesanan["menu"].str.strip().str.lower()
daftar_harga["menu"] = daftar_harga["menu"].str.strip().str.lower()
gabung = pd.merge(pesanan, daftar_harga, on="menu", how="left")
print(gabung)
print()
print("Baris tanpa harga:", gabung["harga"].isna().sum())
print("Total pendapatan:", (gabung["jumlah"] * gabung["harga"]).sum())Output yang Dihasilkan:
menu jumlah harga
0 kopi susu 3 24000
1 es kopi susu 1 26000
2 teh tawar 2 20000
3 americano 2 22000
Baris tanpa harga: 0
Total pendapatan: 182000Mari kita telaah perbaikannya:
- Baris 13-14 (
.str.strip().str.lower()): kedua kolom kunci dinormalkan dengan rantai yang sama — bukan hanya salah satu. Menyeragamkan satu sisi saja tetap membuat kecocokan gagal. - Baris 16 (
pd.merge): dengan kunci yang kini identik, keempat pesanan menemukan harganya. Pemeriksaanisna().sum()mengembalikan nol dan total pendapatan 182000 rupiah akhirnya bisa dihitung. - Kolom
matcha lattedi daftar harga: satu menu tanpa pesanan itu tidak masuk hasil karenahow="left"mempertahankan seluruh baris tabel kiri saja. Ragam pilihanhowdan aturan kunci penggabungan kita bedah tuntas pada chapter Menggabungkan Dataset .
Rangkuman #
nunique()danvalue_counts()mendeteksi inkonsistensi kategori: tujuh nilai unik untuk kategori yang seharusnya berisi dua anggota..str.strip()dan.str.lower()menyeragamkan tepi dan kapital;.replace()dengan kamus menyatukan istilah berbeda bermakna sama sepertiCashmenjaditunai.- Kamus pengganti bekerja pada nilai utuh dan diterapkan paling akhir, setelah bentuk teks dirapikan.
- Perbedaan kapital membuat
pd.mergegagal senyap — kolom harga terisiNaNtanpa satu pun pesan galat; hitungisna().sum()setelah setiap penggabungan. - Normalisasikan kolom kunci di kedua tabel sebelum menggabungkan, dengan rantai yang sama di kedua sisi.
Nilai kategori dan kunci penggabungan kini seragam. Namun satu jenis kolom masih menyimpan masalah yang tidak terlihat dari value_counts(): tanggal. Teks "15/01/2026" tampak rapi, tetapi ia tidak bisa diurutkan secara kronologis dan bermakna dua tanggal berbeda tergantung siapa yang membacanya. Kita urai kolom waktu itu pada chapter berikutnya, Menangani Format Tanggal
.