Data yang baru kita terima hampir tidak pernah sebersih data latihan di buku. Laporan hasil ekspor sering memuat baris ganda, sel yang kosong, angka yang tersimpan sebagai teks, serta label yang ditulis dengan gaya berbeda-beda. Bila keempat masalah itu langsung dihitung tanpa pemeriksaan, laporan yang dihasilkan bisa menyesatkan keputusan bisnis. Chapter ini menjadi pintu masuk Section Data Cleaning: kita memetakan empat masalah data yang paling umum, berlatih diagnosis cepat dengan pandas, lalu menyiapkan satu dataset kotor yang akan dibersihkan bertahap sampai akhir Section ini.

Empat Masalah Data yang Paling Umum #

Pembersihan data di dunia nyata berputar pada empat kategori masalah. Tabel berikut merangkum bentuk masing-masing masalah beserta akibatnya bila data langsung dipakai:

MasalahBentuk di dalam dataAkibat bila dibiarkan
Nilai kosong (missing value)Sel yang tidak terisi, ditandai NaN oleh pandassum() dan mean() melewati sel kosong, statistik menjadi bias
Baris duplikatBaris identik tercatat dua kali atau lebihTotal penjualan terhitung ganda
Tipe data salahAngka tersimpan sebagai teks strAritmetika error dan urutan sortir menyimpang
Label tidak konsisten"Jakarta" dan "JAKARTA" dianggap dua kota berbedagroupby dan value_counts() terpecah

Keempat masalah jarang datang sendirian. Satu file CSV hasil gabungan beberapa sumber biasanya memuat semuanya sekaligus, sehingga urutan pembersihan juga penting: masalah yang satu bisa menyembunyikan masalah lain. Karena itu diagnosis kita harus menyapu keempat kategori secara sistematis, bukan menebak berdasarkan dugaan.

Dataset Latihan: Laporan Pesanan yang Kotor #

Sepanjang Section Data Cleaning kita memakai satu dataset laporan pesanan toko daring fiktif berisi sepuluh baris dan lima kolom: id_pesanan, nama_pelanggan, kota, umur, dan total_belanja. Dataset ini sengaja dibuat kotor di dalam skrip sehingga contoh tetap bisa dijalankan offline tanpa file tambahan. Skrip berikut memuat data tersebut lalu menjalankan diagnosis lengkap dalam sekali eksekusi:

python
import pandas as pd

pesanan = pd.DataFrame(
    {
        "id_pesanan": [
            "PSC-101", "PSC-102", "PSC-103", "PSC-104", "PSC-105",
            "PSC-106", "PSC-101", "PSC-102", "PSC-103", "PSC-107",
        ],
        "nama_pelanggan": [
            "Budi", "Siti", "Dewi", "Andi", "Rina",
            "Tono", "Budi", "Siti", "Dewi", "Sari",
        ],
        "kota": [
            "Jakarta", "Bandung", "Surabaya", "JAKARTA", "Bandung",
            None, "Jakarta", "Bandung", "Surabaya", "Medan",
        ],
        "umur": [29, 34, None, 41, 27, 38, 29, 34, None, 45],
        "total_belanja": [
            250000, 480000, 150000, None, 320000,
            275000, 250000, 480000, 165000, 190000,
        ],
    }
)

print(pesanan)
print()
print("Sel kosong per kolom:")
print(pesanan.isna().sum())
print()
print("Baris duplikat penuh :", pesanan.duplicated().sum())
print("Duplikat id_pesanan  :", pesanan.duplicated(subset=["id_pesanan"]).sum())
print()
print("Label kota yang terdeteksi:")
print(sorted(pesanan["kota"].dropna().unique()))
print()
print(pesanan.dtypes)

Output yang Dihasilkan:

text
  id_pesanan nama_pelanggan      kota  umur  total_belanja
0    PSC-101           Budi   Jakarta  29.0       250000.0
1    PSC-102           Siti   Bandung  34.0       480000.0
2    PSC-103           Dewi  Surabaya   NaN       150000.0
3    PSC-104           Andi   JAKARTA  41.0            NaN
4    PSC-105           Rina   Bandung  27.0       320000.0
5    PSC-106           Tono       NaN  38.0       275000.0
6    PSC-101           Budi   Jakarta  29.0       250000.0
7    PSC-102           Siti   Bandung  34.0       480000.0
8    PSC-103           Dewi  Surabaya   NaN       165000.0
9    PSC-107           Sari     Medan  45.0       190000.0

Sel kosong per kolom:
id_pesanan        0
nama_pelanggan    0
kota              1
umur              2
total_belanja     1
dtype: int64

Baris duplikat penuh : 2
Duplikat id_pesanan  : 3

Label kota yang terdeteksi:
['Bandung', 'JAKARTA', 'Jakarta', 'Medan', 'Surabaya']

id_pesanan            str
nama_pelanggan        str
kota                  str
umur              float64
total_belanja     float64
dtype: object

Membaca Hasil Diagnosis #

Mari kita telaah peran setiap bagian skrip di atas:

  1. Baris 3-23 (pesanan = pd.DataFrame(...)): dataset kotor sepuluh baris; perhatikan None pada kolom kota, umur, dan total_belanja yang menjadi sumber nilai kosong.
  2. Baris 27-28 (pesanan.isna().sum()): setiap sel diperiksa apakah kosong, lalu hasilnya dijumlahkan per kolom sehingga terlihat kota kehilangan 1 sel dan umur kehilangan 2 sel.
  3. Baris 30-31 (pesanan.duplicated().sum()): menghitung baris duplikat. Angka 2 berarti dua baris salinan identik; angka 3 pada subset=["id_pesanan"] berarti ada satu baris tambahan dengan id_pesanan sama tetapi isinya berbeda. Halaman Duplicate labels mendokumentasikan bagaimana pandas menandai nilai yang berulang.
  4. Baris 33-34 (sorted(pesanan["kota"].dropna().unique())): mengurutkan label unik kolom kota; daftar memuat "JAKARTA" dan "Jakarta" sekaligus, tanda label tidak konsisten.
  5. Baris 36 (pesanan.dtypes): menampilkan tipe setiap kolom; umur dan total_belanja menjadi float64 karena kehadiran NaN.

Hasil diagnosis memperlihatkan keempat masalah hadir dalam satu tabel kecil. Kolom umur ber-dtype float64 meskipun berisi bilangan bulat adalah sinyal klasik: satu sel kosong mengubah tipe seluruh kolom karena NaN bertipe float. Label "JAKARTA" di samping "Jakarta" adalah masalah berbeda; nilainya terisi dan tipenya benar, tetapi penulisannya tidak seragam. Masalah tipe kita perbaiki pada Chapter Memperbaiki Tipe Data, sedangkan label teks dibahas pada Chapter Membersihkan Teks.

Alur Diagnosis Empat Langkah #

Sebelum menyentuh satu sel pun, jadikan alur berikut kebiasaan awal setiap kali menerima data baru:

  1. Periksa bentuk dan tipe data dengan df.shape, df.dtypes, dan pandas.DataFrame.info .
  2. Hitung sel kosong per kolom dengan df.isna().sum().
  3. Hitung baris duplikat dengan df.duplicated().sum() dan df.duplicated(subset=["kolom_kunci"]).sum().
  4. Daftar nilai unik kolom kategorikal dengan df["kota"].unique() untuk menemukan label yang tidak seragam.

Dengan peta masalah di tangan, arah pembersihan menjadi jelas: nilai kosong ditangani lebih dulu karena paling sering memicu masalah lain. Chapter berikutnya membahas apa itu missing values, bagaimana pandas 3.0 menandainya pada tiap tipe data, dan mengapa NaN tidak pernah dibandingkan dengan tanda sama dengan. Panduan resmi Working with missing data menjadi rujukan utama sepanjang pembahasan tersebut.