Validasi pada Bagian 3 meninggalkan daftar masalah yang jelas: satu baris duplikat, satu sel harga kosong, dan satu nama komoditas yang tidak seragam. Bagian ini memperbaiki ketiganya dengan perlakuan yang berbeda-beda — bukan sekadar menghapus yang terlihat kotor — lalu memverifikasi ulang hasilnya sampai data layak dianalisis. Setiap keputusan pembersihan kita catat alasannya, karena cara data dibersihkan ikut menentukan batas tafsir hasil akhirnya.
Tiga Masalah, Tiga Perlakuan #
Tidak semua kotoran dibuang. Tiap masalah mendapat perlakuan yang paling sesuai dengan sebab kemunculannya:
| Masalah | Perlakuan | Alasan |
|---|---|---|
| Baris duplikat M3 cabai merah | Buang baris keduanya | Baris ganda tidak membawa informasi baru; justru memberi bobot ganda pada M3 |
| Sel harga kosong M6 bawang merah | Isi dengan interpolasi linear | Harga bergerak per waktu; pekan yang hilang lebih dekat ke perilaku pekan tetangganya |
Nama Cabai Merah pada M7 | Seragamkan ke huruf kecil | Kesalahan ketik kapitalisasi, bukan komoditas baru |
Perlakuan pada sel kosong adalah keputusan yang paling perlu dipertanggungjawabkan, jadi kita bahas lebih dalam pada bagian khusus di bawah.
Membuang Duplikat dan Menyeragamkan Nama #
Dua langkah pertama berjalan bersama karena keduanya murah dan tidak berisiko:
import pandas as pd
df = pd.read_csv("../data/harga_komoditas.csv")
# Langkah 1: buang baris duplikat — satu pekan satu komoditas cukup satu baris.
bersih = df.drop_duplicates(subset=["minggu", "komoditas"], keep="first").copy()
print("Setelah buang duplikat :", bersih.shape)
# Langkah 2: seragamkan nama komoditas (huruf kecil, tanpa spasi tepi).
bersih["komoditas"] = bersih["komoditas"].str.strip().str.lower()
print("Nama komoditas unik :", sorted(bersih["komoditas"].unique()))Output yang Dihasilkan:
Setelah buang duplikat : (40, 3)
Nama komoditas unik : ['ayam broiler', 'bawang merah', 'beras', 'cabai merah', 'gula pasir']Dua keputusan pada blok di atas perlu dijelaskan:
subset=["minggu", "komoditas"]: duplikat kita definisikan berdasarkan pasangan kunci pekan-komoditas, bukan kesamaan seluruh kolom. Dengan begitu, bila suatu saat ada dua baris M3 cabai dengan harga berbeda (salah ketik), keduanya tetap terdeteksi sebagai duplikat dan baris pertama yang dipertahankan (keep="first")..str.strip().str.lower(): spasi tepi dibuang dulu baru huruf dikecilkan. “Cabai Merah”, “cabai merah “, dan “CABAI MERAH” berakhir menjadi satu identitas yang sama.
Mengisi Sel Kosong dengan Interpolasi #
Sel harga M6 bawang merah berisi -. Kita punya tiga pilihan, dan pilihan ketiga yang kita ambil:
- Membuang barisnya — data bawang tinggal 7 pekan; perbandingan antar komoditas jadi timpang.
- Mengisi dengan rata-rata komoditas (32.94) — mengabaikan bahwa harga bergerak mengikuti waktu; bawang sedang menurun saat itu, jadi rata-rata justru terasa terlalu tinggi.
- Interpolasi linear antar pekan berdekatan — M6 diisi nilai tengah antara M5 (33.0) dan M7 (32.0), yaitu 32.5; menghormati urutan waktu tanpa mengarang tren baru.
import pandas as pd
df = pd.read_csv("../data/harga_komoditas.csv")
bersih = df.drop_duplicates(subset=["minggu", "komoditas"], keep="first").copy()
bersih["komoditas"] = bersih["komoditas"].str.strip().str.lower()
# Langkah 3: '-' menjadi NaN, lalu kolom harga menjadi numerik.
bersih["harga_rata_ribu"] = pd.to_numeric(bersih["harga_rata_ribu"], errors="coerce")
print(f"{'Sel kosong sesudah konversi':<32}:", bersih["harga_rata_ribu"].isna().sum())
# Langkah 4: isi sel kosong dengan interpolasi linear antar pekan berdekatan.
bersih = bersih.sort_values(["komoditas", "minggu"])
bersih["harga_rata_ribu"] = bersih.groupby("komoditas")["harga_rata_ribu"].transform(
lambda s: s.interpolate()
)
print(f"{'Sel kosong sesudah interpolasi':<32}:", bersih["harga_rata_ribu"].isna().sum())
print()
bawang = bersih[bersih["komoditas"] == "bawang merah"]
print(bawang[["minggu", "harga_rata_ribu"]].to_string(index=False))Output yang Dihasilkan:
Sel kosong sesudah konversi : 1
Sel kosong sesudah interpolasi : 0
minggu harga_rata_ribu
M1 30.0
M2 34.0
M3 31.0
M4 36.0
M5 33.0
M6 32.5
M7 32.0
M8 35.0Mari kita telaah langkah-langkah kuncinya:
pd.to_numeric(..., errors="coerce"): tanda-yang gagal dikonversi berubah menjadiNaN— cara pandas menyatakan “tidak ada data” — dan sisanya menjadi angka. Kolom harga pun berubah tipe menjadi numerik.sort_values(["komoditas", "minggu"])sebelum interpolasi: interpolasi linear mengisiNaNdari nilai di kiri-kanannya berdasarkan posisi baris. Tanpa pengurutan ini, “pekan tetangga” bisa berarti baris yang salah. M1–M8 berurut abjad dengan benar, jadi pengurutan tunggal ini sudah cukup.groupby("komoditas")...transform(lambda s: s.interpolate()): interpolasi dijalankan terpisah per komoditas, sehinggaNaNbawang M6 hanya dipengaruhi harga bawang — bukan harga komoditas lain.- Hasilnya 32.5: persis titik tengah antara 33.0 dan 32.0, dan tabel bawang kini utuh 8 pekan.
Memverifikasi Ulang Hasil #
Pembersihan belum selesai sebelum buktinya diperiksa. Blok berikut menjalankan resep yang sama secara diam, lalu mengulang seluruh pemeriksaan Bagian 3:
import pandas as pd
# Resep pembersihan lengkap Bagian 4, dijalankan ulang dalam diam.
df = pd.read_csv("../data/harga_komoditas.csv")
bersih = df.drop_duplicates(subset=["minggu", "komoditas"], keep="first").copy()
bersih["komoditas"] = bersih["komoditas"].str.strip().str.lower()
bersih["harga_rata_ribu"] = pd.to_numeric(bersih["harga_rata_ribu"], errors="coerce")
bersih = bersih.sort_values(["komoditas", "minggu"])
bersih["harga_rata_ribu"] = bersih.groupby("komoditas")["harga_rata_ribu"].transform(
lambda s: s.interpolate()
)
print(f"{'Dimensi akhir':<16}:", bersih.shape)
print(f"{'Baris duplikat':<16}:", bersih.duplicated().sum())
print(f"{'Sel kosong':<16}:", bersih["harga_rata_ribu"].isna().sum())
print(f"{'Tipe kolom harga':<16}:", bersih["harga_rata_ribu"].dtype)
print()
print(bersih["komoditas"].value_counts().sort_index())Output yang Dihasilkan:
Dimensi akhir : (40, 3)
Baris duplikat : 0
Sel kosong : 0
Tipe kolom harga: float64
komoditas
ayam broiler 8
bawang merah 8
beras 8
cabai merah 8
gula pasir 8
Name: count, dtype: int64Kelima pemeriksaan kini hijau: 40 baris tepat, tanpa duplikat, tanpa sel kosong, kolom harga bertipe float64, dan lima komoditas masing-masing tepat 8 pekan. Data bersih ini — dan resep lima baris pembersihannya — akan dipakai berulang kali pada Bagian 5 sampai 9.
Ringkasan Bagian 4 #
Tiga masalah diperbaiki dengan tiga perlakuan: duplikat dibuang, sel kosong diisi interpolasi linear (32.5 untuk bawang M6, dengan catatan bahwa nilai itu adalah imputasi), dan nama komoditas diseragamkan. Verifikasi ulang menutup bagian ini dengan data 40 baris yang rapi.
Dengan data yang sudah bisa dipercaya, saatnya bertanya pertanyaan pertama dari Bagian 1: bagaimana harga bergerak dari pekan ke pekan, dan di mana perubahannya paling keras? Kita kejar pada Bagian 5: Eksplorasi Perubahan Harga .