Seluruh teknik pembersihan pada Section ini sudah kita kuasai: nilai kosong, duplikat, tipe data, teks, label kategori, dan rentang nilai. Namun pembersihan baru dapat dipertanggungjawabkan bila efeknya terukur, bukan sekadar terasa. Pada chapter penutup ini kita merangkum kondisi data menjadi laporan kualitas yang ringkas, membandingkan angka sebelum dan sesudah pembersihan dalam satu skrip yang sama.

Empat Ukuran Inti Kualitas Data #

Laporan kualitas data yang praktis cukup dibangun dari empat ukuran yang sudah kita kenal. Keempatnya menjawab pertanyaan berbeda tentang kondisi tabel:

  • Jumlah baris menunjukkan efek drop_duplicates() dan dropna() terhadap ukuran data.
  • Nilai kosong per kolom dari isna().sum() menunjukkan kolom mana yang butuh pengisian dan seberapa banyak. Detail method-nya ada di pandas.DataFrame.isna .
  • Baris duplikat dari duplicated().sum() menghitung baris yang identik pada seluruh kolom; referensinya di pandas.DataFrame.duplicated .
  • Pelanggaran rentang menghitung nilai di luar aturan domain, misalnya umur negatif, dengan boolean mask dari chapter Validasi Rentang Nilai.

Membuat Fungsi Laporan yang Dapat Dipakai Ulang #

Skrip berikut membungkus keempat ukuran menjadi fungsi laporan_kualitas(), lalu memanggilnya dua kali: sekali untuk data mentah dan sekali untuk data yang sudah dibersihkan. Data mentahnya sengaja memuat semua masalah yang dibahas Section ini.

python
import pandas as pd
import numpy as np


def laporan_kualitas(data, judul):
    print(f"== {judul} ==")
    print("Jumlah baris :", len(data))
    print("Nilai kosong per kolom:")
    print(data.isna().sum().to_string())
    print("Baris duplikat :", int(data.duplicated().sum()))
    mask_umur = data["umur"].notna() & ~data["umur"].between(0, 120)
    print("Pelanggaran rentang umur :", int(mask_umur.sum()))
    print()


data_mentah = pd.DataFrame({
    "pelanggan": ["Budi", "Siti", "Dewi", "Andi", "Rina", "Tono", "Lina", "Budi"],
    "kota": ["Jakarta", " JAKARTA ", "Bandung", " bandung", "Surabaya", "SURABAYA", "Medan", "Jakarta"],
    "umur": [29, 34, -5, 41, None, 35, 31, 29],
})

laporan_kualitas(data_mentah, "Sebelum pembersihan")

data_bersih = data_mentah.drop_duplicates()
mask_umur = data_bersih["umur"].notna() & ~data_bersih["umur"].between(0, 120)
data_bersih.loc[mask_umur, "umur"] = np.nan
median_umur = data_bersih["umur"].median()
data_bersih["umur"] = data_bersih["umur"].fillna(median_umur)
data_bersih["kota"] = data_bersih["kota"].str.strip().str.title()

laporan_kualitas(data_bersih, "Sesudah pembersihan")
print("Data akhir:")
print(data_bersih)

Output yang Dihasilkan:

text
== Sebelum pembersihan ==
Jumlah baris : 8
Nilai kosong per kolom:
pelanggan    0
kota         0
umur         1
Baris duplikat : 1
Pelanggaran rentang umur : 1

== Sesudah pembersihan ==
Jumlah baris : 7
Nilai kosong per kolom:
pelanggan    0
kota         0
umur         0
Baris duplikat : 0
Pelanggaran rentang umur : 0

Data akhir:
  pelanggan      kota  umur
0      Budi   Jakarta  29.0
1      Siti   Jakarta  34.0
2      Dewi   Bandung  34.0
3      Andi   Bandung  41.0
4      Rina  Surabaya  34.0
5      Tono  Surabaya  35.0
6      Lina     Medan  31.0

Mari kita telaah apa yang terjadi pada kode di atas:

  1. Baris 5-13 (def laporan_kualitas(data, judul):): fungsi menerima DataFrame dan judul, lalu mencetak empat ukuran inti; data.isna().sum().to_string() menampilkan nilai kosong per kolom tanpa baris dtype.
  2. Baris 11 (mask_umur = data["umur"].notna() & ~data["umur"].between(0, 120)): pelanggaran rentang dihitung hanya untuk nilai yang benar-benar ada, karena nilai kosong sudah dilaporkan terpisah pada ukuran kedua.
  3. Baris 16-20 (data_mentah = pd.DataFrame({...})): delapan baris data dibuat dengan segala masalahnya: label kota tidak konsisten, umur -5, satu umur kosong, dan satu baris duplikat persis sama dengan baris pertama.
  4. Baris 22 (laporan_kualitas(data_mentah, "Sebelum pembersihan")): pemanggilan pertama merekam kondisi awal.
  5. Baris 24-29: rantai pembersihan dijalankan; drop_duplicates() menghapus baris kembar, umur tidak wajar ditandai NaN lalu diisi median, dan kota dirapikan dengan .str.strip().str.title() seperti pada chapter Membersihkan Teks. Referensi penghapus duplikat ada di pandas.DataFrame.drop_duplicates .
  6. Baris 31-33: pemanggilan kedua merekam kondisi akhir, lalu data_bersih dicetak utuh.

Membaca Perubahan Angka Sebelum dan Sesudah #

Dibaca berdampingan, kedua laporan menceritakan efek setiap teknik dengan angka. Jumlah baris turun dari 8 menjadi 7 akibat penghapusan duplikat, nilai kosong turun dari 1 menjadi 0 setelah pengisian median, dan pelanggaran rentang turun dari 1 menjadi 0 setelah umur -5 dikoreksi. Tabel data akhir juga memperlihatkan kolom kota yang kini seragam dengan tujuh baris umur yang masuk akal.

Laporan kondisi awal jangan dibuang setelah pembersihan selesai. Dokumen itu menjadi bukti keadaan data sebelum disentuh, dasar keputusan koreksi yang diambil, dan pembanding saat data serupa datang di kemudian hari.

Dengan laporan ini, Section Data Cleaning ditutup sebagai alur kerja yang utuh: deteksi, koreksi, lalu pembuktian lewat angka. Data yang sudah bersih inilah bekal kita masuk Section berikutnya, Operasi Aritmetika dan Statistika, tempat perhitungan antar kolom dan ringkasan statistik dikerjakan tanpa terganggu nilai yang tidak wajar.