Pengisian adalah strategi pembersihan yang mempertahankan setiap baris dengan mengganti NaN menggunakan nilai pengganti, dan alat utamanya pada pandas adalah fillna beserta ffill dan bfill. Topik ini membahas pengisian dengan konstanta, dengan median global, dengan median per grup menggunakan groupby dan transform, serta pengisian berurutan pada log sensor yang tersusun menurut waktu. Bagian akhir membahas batasan metode ini, yaitu kondisi ketika imputasi justru menyesatkan analisis. Dataset yang dipakai tetap log sensor tiga ruangan versi kotor, dan setelah topik ini dipraktikkan nilai pengganti dapat dipilih dengan alasan yang dapat dipertanggungjawabkan.
fillna dengan konstanta dan median global#
Metode fillna(nilai) menggantikan seluruh NaN dengan nilai yang diberikan, dan pilihan nilai penggantinya adalah keputusan analitis, bukan sekadar formalitas sintaks. Untuk kolom numerik seperti lembap_pct, median adalah pengganti yang lazim karena lebih tahan terhadap nilai ekstrem dibanding rata-rata. Pada skrip di bagian berikut, df["lembap_pct"].fillna(median_global) menghabiskan seluruh NaN kolom itu sehingga hitungan NaN turun dari 3 menjadi 0. Untuk kolom kategori, konstanta teks semacam "tidak diketahui" lebih tepat daripada angka statistik karena kategori tidak punya urutan yang bermakna untuk dirata-ratakan. Perlu diingat bahwa fillna tidak mengubah kolom aslinya, sehingga hasilnya ditampung ke variabel baru atau ditugaskan kembali ke kolom yang sama.
Median per grup dengan groupby dan transform#
Pengisian yang lebih halus memperhitungkan konteks baris, dan pada dataset ini konteksnya adalah ruangan. Ekspresi df.groupby("ruang")["suhu_c"].median() menghasilkan median per ruang sebesar 23.55 untuk Lab A, 23.85 untuk Lab B, dan 24.10 untuk Ruang Arsip. Nilai tersebut belum bisa langsung dipakai sebagai pengganti karena bentuknya tabel ringkas tiga baris, sedangkan yang dibutuhkan fillna adalah deret sepanjang tabel. Metode transform("median") pada objek grup menjembatani perbedaan itu dengan mengembalikan deret sepanjang df yang setiap barisnya berisi median grupnya masing-masing, sehingga df["suhu_c"].fillna(median_ruang) mengisi setiap NaN dengan median ruang baris yang bersangkutan.
Jalankan skrip berikut dan perhatikan bahwa hitungan NaN suhu_c turun dari 7 menjadi 0 tanpa satu baris pun dibuang.
import numpy as np
import pandas as pd
# Dataset kontrak versi kotor: log sensor tiga ruangan dengan NaN dan duplikat.
rng = np.random.default_rng(42)
n = 96
df = pd.DataFrame({
"waktu": pd.date_range("2026-01-05 07:00", periods=n, freq="15min"),
"ruang": rng.choice(["Lab A", "Lab B", "Ruang Arsip"], n, p=[0.4, 0.35, 0.25]),
"suhu_c": np.round(rng.normal(24, 1.5, n), 1),
"lembap_pct": np.round(rng.normal(60, 5, n), 1),
"status_sensor": rng.choice(["normal", "kalibrasi", "rusak"], n, p=[0.85, 0.10, 0.05]),
})
df.loc[rng.random(n) < 0.05, "suhu_c"] = np.nan
df.loc[rng.random(n) < 0.05, "lembap_pct"] = np.nan
df = pd.concat([df, df.sample(3, random_state=42)], ignore_index=True)
print(df.groupby("ruang")["suhu_c"].median().round(2))
median_ruang = df.groupby("ruang")["suhu_c"].transform("median")
suhu_isi_grup = df["suhu_c"].fillna(median_ruang)
print("NaN suhu setelah isi median grup :", suhu_isi_grup.isna().sum())
median_global = df["lembap_pct"].median()
lembap_isi_global = df["lembap_pct"].fillna(median_global)
print("NaN lembap setelah median global :", lembap_isi_global.isna().sum())
arsip = df[df["ruang"] == "Ruang Arsip"].sort_values("waktu")
posisi = len(arsip) - 1 - int(arsip["suhu_c"].isna().values[::-1].argmax())
jendela = slice(max(0, posisi - 2), posisi + 3)
print(arsip[["waktu", "suhu_c"]].iloc[jendela])
print(arsip[["waktu", "suhu_c"]].ffill().iloc[jendela])
print("sisa NaN setelah ffill:", arsip["suhu_c"].ffill().isna().sum())
print("sisa NaN setelah bfill:", arsip["suhu_c"].bfill().isna().sum())# menjalankan skrip pengisian nilai hilang
python3 pengisian_nilai.pyruang
Lab A 23.55
Lab B 23.85
Ruang Arsip 24.10
Name: suhu_c, dtype: float64
NaN suhu setelah isi median grup : 0
NaN lembap setelah median global : 0
waktu suhu_c
13 2026-01-05 10:15:00 23.5
18 2026-01-05 11:30:00 23.1
20 2026-01-05 12:00:00 NaN
22 2026-01-05 12:30:00 24.3
23 2026-01-05 12:45:00 24.0
waktu suhu_c
13 2026-01-05 10:15:00 23.5
18 2026-01-05 11:30:00 23.1
20 2026-01-05 12:00:00 23.1
22 2026-01-05 12:30:00 24.3
23 2026-01-05 12:45:00 24.0
sisa NaN setelah ffill: 1
sisa NaN setelah bfill: 0ffill dan bfill pada log berurutan#
Metode ffill mengisi NaN dengan nilai terisi terakhir di atasnya, sedangkan bfill mengisinya dengan nilai terisi berikutnya di bawahnya, dan keduanya memanfaatkan urutan baris sebagai informasi. Log sensor adalah kandidat ideal karena setiap baris mewakili satu waktu pengukuran yang berurutan, sehingga pengukuran yang hilang paling wajar didekati dengan pengukuran tepat sebelum atau sesudahnya. Pada jendela keluaran di atas, NaN milik Ruang Arsip pada pukul 12.00 terisi menjadi 23.1, yaitu nilai pengukuran pukul 11.30 sebelumnya, dan baris di sekitarnya tidak berubah sama sekali.
Dua angka penutup skrip menunjukkan batas tiap metode. Hitungan NaN setelah ffill tersisa 1 karena satu kehilangan terletak di baris pertama deret Ruang Arsip sehingga tidak punya pendahulu untuk disalin, sedangkan bfill menghabiskannya karena selalu ada nilai di bawahnya. Terakhir, urutan baris adalah prasyarat kedua metode ini, dan sort_values("waktu") pada skrip menjalankan perannya di situ.
Kapan imputasi menyesatkan#
Imputasi bukan pilihan netral, dan ada dua kondisi pada dataset ini yang membuatnya menyesatkan. Kondisi pertama adalah pengisian dengan statistik global pada data yang kehilangannya berkaitan dengan kejadian nyata. Apabila kehilangan suhu_c justru terjadi saat sensor berstatus rusak, mengisi sel itu dengan median ruangan menciptakan deret yang tampak berkelanjutan padahal alatnya sedang gagal, sehingga sinyal gangguan hilang dan laporan pemantauan menjadi terlalu optimis. Kondisi kedua adalah ffill pada periode gangguan yang panjang, karena nilai satu pengukuran lama disalin berulang kali dan varians deret palsu menurun.
Cara kerja yang lebih hati-hati adalah memisahkan pengisian dari pencatatan. Kolom mask tambahan seperti suhu_c_imputasi yang berisi True untuk sel yang diisi memungkinkan analisis dijalankan dua kali, yaitu dengan dan tanpa imputasi, agar pengaruhnya terukur. Kolom status_sensor pada dataset ini juga sudah menyediakan konteks yang dibutuhkan, sehingga baris berstatus rusak atau kalibrasi dapat diperiksa sebelum nilai penggantinya dipercaya. Keputusan akhirnya tetap bergantung pada tujuan analisis, dan profil dari topik Deteksi Data Hilang adalah bahan penilaian pertamanya.
Ringkasan#
fillnamengganti NaN dengan konstanta atau statistik, dan median lebih tahan terhadap nilai ekstrem dibanding rata-rata.- Kombinasi
groupby,transform("median"), danfillnamengisi setiap NaN dengan statistik grup barisnya sendiri. ffilldanbfillmemanfaatkan urutan baris, sehingga tabel wajib diurutkan lebih dulu, dan keduanya gagal pada ujung deret yang berbeda.- Imputasi menyesatkan apabila kehilangan adalah sinyal kejadian, sehingga kolom mask dan status sensor perlu dipertimbangkan sebelum nilai pengganti dipercaya.
Referensi#
- pandas.DataFrame.fillna — pandas
— Dokumentasi metode
fillnabeserta perilaku parametervalue,method, danlimit. - Working with missing data — pandas
— Panduan resmi pandas tentang pengisian data hilang termasuk
ffilldanbfill.