Log sensor suhu dan kelembapan pada jalur ini dipakai dalam versi kotor sepanjang modul ini, yaitu versi yang memuat nilai NaN dan baris duplikat di atas pola datanya. Topik ini membahas cara mendeteksi dan mengukur data hilang menggunakan isna, notna, profil per kolom dengan isna().sum(), proporsi kehilangan dengan mean() pada mask, serta kolom non-null count pada df.info(). Setelah topik ini dipraktikkan, angka kehilangan pada setiap kolom dapat ditafsirkan sehingga pemilihan strategi pada topik Penghapusan dengan dropna dan Pengisian Nilai Hilang berpijak pada bukti yang terukur, bukan pada tebakan.
Data kotor yang menjadi bahan latihan#
Dataset kontrak jalur ini adalah log pengukuran tiga ruangan, yaitu Lab A, Lab B, dan Ruang Arsip, dengan lima kolom bernama waktu, ruang, suhu_c, lembap_pct, dan status_sensor. Versi kotor yang dipakai di modul ini menambahkan dua kekotoran di atas pola aslinya, yaitu sebagian sel suhu_c dan lembap_pct diubah menjadi NaN serta tiga baris yang dipilih dari seed tetap digandakan di bagian akhir tabel. Seluruh angka acak dibangkitkan dari seed yang tetap sehingga dataset yang sama dapat dibuat ulang kapan pun. Jalankan skrip berikut untuk membangkitkan dataset kotor tersebut sekaligus menampilkan potongan dan strukturnya.
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.head(3))
df.info()
print(df.isna().sum())
print((df.isna().mean() * 100).round(2))
print(df["suhu_c"].isna().head(10))
print("suhu terisi:", df["suhu_c"].notna().sum())# menjalankan skrip deteksi data hilang
python3 deteksi_hilang.py waktu ruang suhu_c lembap_pct status_sensor
0 2026-01-05 07:00:00 Ruang Arsip NaN 68.6 normal
1 2026-01-05 07:15:00 Lab B 21.8 59.1 normal
2 2026-01-05 07:30:00 Ruang Arsip 22.0 58.1 normal
<class 'pandas.DataFrame'>
RangeIndex: 99 entries, 0 to 98
Data columns (total 5 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 waktu 99 non-null datetime64[us]
1 ruang 99 non-null str
2 suhu_c 92 non-null float64
3 lembap_pct 96 non-null float64
4 status_sensor 99 non-null str
dtypes: datetime64[us](1), float64(2), str(2)
memory usage: 5.2 KB
waktu 0
ruang 0
suhu_c 7
lembap_pct 3
status_sensor 0
dtype: int64
waktu 0.00
ruang 0.00
suhu_c 7.07
lembap_pct 3.03
status_sensor 0.00
dtype: float64
0 True
1 False
2 False
3 False
4 False
5 False
6 False
7 False
8 False
9 False
Name: suhu_c, dtype: bool
suhu terisi: 92Keluaran tersebut memperlihatkan kekotoran yang tidak selalu tampak sekilas. Baris berindeks 0 kehilangan nilai suhu_c sehingga selnya tampil sebagai NaN, sedangkan kolom lain pada baris itu tetap terisi. Bagian df.info() melengkapi pengamatan visual dengan angka karena kolom suhu_c hanya memiliki 92 nilai terisi dan lembap_pct 96 nilai terisi dari total 99 baris, sementara waktu, ruang, dan status_sensor lengkap. Tipe data juga terbaca pada keluaran yang sama, yaitu datetime64[us] untuk waktu dan str untuk kolom teks.
Mask boolean dengan isna dan notna#
Metode isna menghasilkan mask boolean, yaitu deret atau tabel berisi True dan False yang menandai posisi nilai hilang, dengan True untuk NaN dan False untuk nilai terisi. Metode notna merupakan kebalikannya dan menandai nilai yang terisi. Kedua metode bekerja pada DataFrame maupun Series, sehingga deteksi dapat dilakukan per sel, per kolom, atau pada seluruh tabel sekaligus tanpa mengubah datanya.
Pada keluaran skrip, potongan df["suhu_c"].isna().head(10) menampilkan sepuluh entri pertama mask kolom suhu_c, dan hanya baris berindeks 0 yang bernilai True. Mask inilah bahan mentah untuk semua perhitungan berikutnya karena True diperlakukan sebagai 1 ketika dijumlahkan dan False sebagai 0. Ekspresi df["suhu_c"].notna().sum() yang mencetak angka 92 menghitung banyaknya nilai terisi pada kolom itu. Angkanya persis sama dengan non-null count kolom suhu_c pada df.info(), dan kesesuaian dua cara penghitungan ini berguna sebagai pemeriksa silang ketika profil data hilang disusun.
Profil cepat dengan sum dan mean#
Pemrofilan cepat data hilang pada seluruh tabel dilakukan dengan satu ekspresi, yaitu df.isna().sum(), karena penjumlahan mask boolean dilakukan per kolom. Keluarannya menunjukkan suhu_c kehilangan 7 nilai dan lembap_pct kehilangan 3 nilai, sedangkan waktu, ruang, dan status_sensor tidak kehilangan apa pun. Tabel semacam ini sudah cukup untuk menentukan kolom mana yang bermasalah tanpa membuka datanya satu per satu. Instruksi praktisnya, jalankan isna().sum() setiap kali tabel baru diterima sebelum analisis apa pun dimulai.
Jumlah absolut perlu ditimbang terhadap ukuran tabel, dan proporsinya diperoleh dengan menghitung rata-rata mask, yakni (df.isna().mean() * 100).round(2). Rata-rata dari mask boolean sama dengan banyaknya True dibagi banyaknya baris, sehingga hasilnya adalah proporsi kehilangan dalam bentuk desimal. Pada dataset ini kehilangan suhu_c sebesar 7.07 persen dan lembap_pct sebesar 3.03 persen. Kedua angka tersebut tergolong kecil, tetapi kedua kolomnya tidak simetris, sehingga pola kehilangan yang berbeda antarkolom ini perlu diperhatikan ketika strategi dibahas pada bagian berikutnya.
Membaca angka hilang untuk memilih strategi#
Angka hasil pemrofilan dibaca dengan tiga lapis pertanyaan yang berurutan. Lapis pertama adalah seberapa banyak, yaitu perbandingan antara jumlah absolut dan proporsi, karena 7 baris yang hilang pada tabel 99 baris bermakna berbeda dibanding pada tabel 99000 baris. Lapis kedua adalah di mana kehilangannya, dan pada dataset ini kehilangan hanya menyerang kolom pengukuran sedangkan kolom identitas seperti waktu dan ruang utuh, sehingga baris tetap dapat dikenali meskipun nilainya hilang. Lapis ketiga adalah apakah polanya seragam, dan ketidaksamaan 7.07 persen terhadap 3.03 persen menunjukkan bahwa sensor suhu lebih sering gagal mencatat dibanding sensor kelembapan.
Ketiga lapis pembacaan itu menentukan strategi tanpa perlu menghukum NaN sejak awal. Kehilangan yang kecil dan menyerang kolom pengukuran biasanya ditangani dengan pengisian yang mempertahankan baris, sedangkan kolom yang hilang hampir seluruhnya lebih layak dibuang daripada diisi. Keputusan finalnya ditegaskan pada topik Penghapusan dengan dropna yang membahas pembuangan baris dan topik Pengisian Nilai Hilang yang membahas penggantian nilai, dan keduanya memakai profil yang sama seperti yang dibangun di sini.
Ringkasan#
isnadannotnamenghasilkan mask boolean per sel, dan penjumlahan mask menghitung banyaknya NaN karenaTruebernilai 1 danFalsebernilai 0.df.isna().sum()menghasilkan profil jumlah NaN per kolom, sedangkanmean()pada mask yang sama menghasilkan proporsi kehilangannya.- Non-null count pada
df.info()sama dengannotna().sum()per kolom, sehingga struktur tabel dapat diperiksa silang dari dua arah.
Referensi#
- Working with missing data — pandas — Panduan resmi pandas tentang representasi nilai hilang dan perhitungan yang terkait.
- pandas.DataFrame.isna — pandas
— Dokumentasi metode
isnayang menghasilkan mask boolean untuk nilai NaN.