Duplikat dan Validitas

Deduplikasi, pemeriksaan rentang nilai, dan integritas referensial antar kolom.

Daftar isi

Data yang hilang sebagian terlihat segera, sedangkan data yang ganda, di luar rentang, atau saling bertentangan justru lolos ke laporan karena keluarannya tetap tampak wajar. Topik ini menutup celah itu dengan tiga pemeriksaan yang menjadi satu rangkaian, yaitu deduplikasi, pemeriksaan rentang, dan konsistensi antar kolom, semuanya dijalankan pada ukuran_udara.csv. Setelah membacanya, dataset latihan ini dapat dinyatakan bersih dengan bukti angka, bukan dengan perasaan.

Duplikat: eksak dan berdasarkan kunci#

Duplikat datang dalam dua tingkat yang perlu dibedakan. Duplikat eksak adalah baris yang seluruh kolomnya sama, umumnya akibat ekspor yang berulang, dan cukup dibuang dengan drop_duplicates(). Duplikat kunci berbeda, yaitu dua baris yang kunci logisnya sama, misalnya pasangan stasiun dan waktu, tetapi nilai lainnya berbeda, dan penyelesaiannya adalah keputusan analisis, bukan pembuangan otomatis.

Skrip berikut menjalankan kedua pemeriksaan itu beserta pemeriksaan validitasnya pada dataset latihan.

python duplikat_validitas.py
"""Duplikat, rentang nilai, dan konsistensi antar kolom."""
import pandas as pd

data = pd.read_csv(
    "ukuran_udara.csv",
    na_values=["kosong", "-999.0"],
    dtype={"pm25": "string", "kelembapan": "string"},
)
data["pm25"] = data["pm25"].astype("float")
data["kelembapan"] = data["kelembapan"].str.replace(",", ".", regex=False).astype("float")
data["waktu"] = pd.to_datetime(data["waktu"], format="mixed", dayfirst=True)
data["stasiun"] = (
    data["stasiun"].str.strip().str.replace(r"\s+", " ", regex=True).str.title()
)

print("duplikat eksak       :", int(data.duplicated().sum()))
data = data.drop_duplicates()
print("baris setelah dibuang:", len(data))
print("kunci ganda          :", int(data.duplicated(subset=["stasiun", "waktu"]).sum()))
print("di luar rentang      :", int(((data["pm25"] < 0) | (data["pm25"] > 500)).sum()))
print()

def kualitas(pm):
    if pd.isna(pm):
        return None
    if pm < 50:
        return "Baik"
    if pm <= 100:
        return "Sedang"
    return "Tidak Sehat"

data["kualitas"] = data["kualitas"].str.title()
punya_pm = data[data["pm25"].notna()].copy()
punya_pm["cocok"] = punya_pm.apply(lambda r: kualitas(r["pm25"]) == r["kualitas"], axis=1)
print("tidak konsisten:", int((~punya_pm["cocok"]).sum()))
print(punya_pm.loc[~punya_pm["cocok"], ["stasiun", "pm25", "kualitas"]].to_string(index=False))
text Keluaran
duplikat eksak       : 2
baris setelah dibuang: 60
kunci ganda          : 0
di luar rentang      : 1

tidak konsisten: 2
  stasiun   pm25 kualitas
Stasiun B 9999.0   Sedang
Stasiun B   46.5   Sedang

Dua baris duplikat eksak dibuang sehingga tabel kembali ke enam puluh baris, dan pemeriksaan kunci berikutnya menghasilkan nol, yang berarti tidak ada konflik yang harus diputuskan. Urutan pemeriksaan ini penting, sebab pemeriksaan kunci yang dijalankan sebelum deduplikasi akan menemukan dua kunci ganda yang sebenarnya hanya duplikat ekspor.

Rentang yang masuk akal#

Pemeriksaan rentang membandingkan setiap nilai dengan batas yang datang dari pengetahuan domain, bukan dari data itu sendiri. PM2.5 di atas 500 adalah keanehan peralatan pada sebagian besar lokasi, suhu di luar rentang iklim setempat adalah kesalahan satuan, dan kelembapan di atas seratus persen adalah kepastian kesalahan. Satu baris 9999.0 tertangkap oleh syarat tersebut pada keluaran di atas.

Nilai yang melanggar rentang tidak otomatis dibuang. Pilihan yang tersedia adalah memperlakukannya sebagai data hilang bila keanehannya jelas bermula dari sensor, memotongnya ke batas, atau membiarkannya sambil mencatat, dan pilihannya bergantung pada pertanyaan analisis. Dataset latihan ini menyimpan baris tersebut sebagai data hilang pada topik data hilang, dan di sini ia hanya ditandai, sehingga dua topik mengambil posisi yang berbeda dan sama-sama jujur tentang alasannya.

Pemeriksaan rentang juga menangkap kode sentinel yang lolos. Apabila -999.0 tidak dinetralkan pada pembacaan, syarat pm25 < 0 menandainya sebagai di luar rentang, dan dua lapis pemeriksaan ini saling menggantikan sebagai pengaman.

Konsistensi antar kolom#

Kolom yang dihitung dari kolom lain dapat diverifikasi, dan ketidakcocokannya adalah temuan yang lebih bernilai daripada sekadar angka. Kolom kualitas pada dataset ini seharusnya mengikuti ambang PM2.5, dan perbandingan memunculkan dua baris yang tidak konsisten pada keluaran di atas.

Keduanya bercerita berbeda. Baris 9999.0 berlabel Sedang karena label itu dihitung dari pembacaan sebelum sensor bermasalah, sehingga pertanyaannya adalah urutan perekaman dua kolom, bukan label yang salah tulis. Baris 46.5 berlabel Sedang padahal nilainya di bawah ambang Baik, dan itu adalah salah tulis manual yang sebenarnya. Pembeda keduanya adalah penyelidikan singkat pada sumber data, dan yang pasti, tidak satu pun diselesaikan dengan mengedit nilai secara diam-diam.

Pola yang sama berlaku untuk integritas antar tabel, misalnya kunci asing yang tidak memiliki induknya, dan pemeriksaannya dilakukan dengan merge berindikator sebagaimana dibahas pada topik penggabungan sumber di modul yang sama.

Kesalahan umum#

Kesalahan pertama adalah drop_duplicates() tanpa pemeriksaan kunci logikanya. Dua baris dengan kunci sama tetapi nilai berbeda lolos dari pemeriksaan eksak, kemudian masing-masing ikut dihitung, dan ringkasan menjadi dobel pada kelompok yang salah.

Kesalahan kedua adalah menetapkan batas rentang dari data itu sendiri, misalnya membuang semua nilai di luar tiga simpangan baku. Outlier sungguhan justru peristiwa yang dicari pada banyak analisis, sehingga batasnya berasal dari domain, sedangkan statistik hanya membantu menandai kandidatnya.

Kesalahan ketiga adalah memperbaiki inkonsistensi dengan menimpa nilai langsung. Nilai yang disunting tanpa jejak menghancurkan reproduktibilitas, sedangkan perlakuan yang benar berupa aturan pada kode, misalnya menghitung ulang kolom kualitas dari pm25, sehingga keputusannya terdokumentasi dan dapat diulang.

Ringkasan#

  • Duplikat diperiksa dua tingkat, yaitu eksak dengan duplicated() dan kunci logis dengan subset, dan konflik kunci adalah keputusan, bukan pembuangan otomatis.
  • Rentang nilai diuji dengan batas dari pengetahuan domain, dan pelanggaran ditangani dengan pilihan yang dinyatakan, bukan dengan penghapusan diam- diam.
  • Konsistensi antar kolom memverifikasi kolom turunan, dan ketidakcocokannya menunjuk proses perekaman yang perlu diselidiki.
  • Semua perlakuan berupa aturan pada kode agar keputusannya terdokumentasi dan dapat diulang.

Referensi#