Nilai yang hilang adalah sel data yang tidak terisi, ditandai NaN pada kolom numerik atau None pada kolom teks. Topik ini membahas cara mendeteksinya dengan isna, akibat yang ditimbulkannya pada perhitungan, pilihan antara dropna dan fillna, serta cara mendokumentasikan keputusan penanganannya. Setelah topik ini, data dengan sel kosong dapat ditangani secara sengaja dan tercatat, bukan secara diam-diam.
Mendeteksi nilai yang hilang#
DataFrame contoh berisi catatan peminjaman perpustakaan dengan dua kolom yang tidak terisi sempurna. Not a Number (NaN) adalah penanda sel kosong pada kolom numerik, sedangkan nilai None dari Python tetap tampil sebagai None pada kolom teks. Keduanya diperlakukan sebagai nilai yang hilang oleh pandas.
import pandas as pd
pinjam = pd.DataFrame({
"anggota": ["Ali", "Budi", "Citra", "Dewi", "Eka", "Fajar"],
"judul": ["Atlas Dunia", "Kamus Biologi", None, "Ensiklopedia Sains", "Atlas Dunia", None],
"lama_hari": [7, 10, 5, None, None, 12],
})
print(pinjam) anggota judul lama_hari
0 Ali Atlas Dunia 7.0
1 Budi Kamus Biologi 10.0
2 Citra None 5.0
3 Dewi Ensiklopedia Sains NaN
4 Eka Atlas Dunia NaN
5 Fajar None 12.0Perhatikan perbedaan penandanya. Sel kosong pada kolom lama_hari tampil sebagai NaN dan seluruh kolom berubah menjadi float64, sedangkan sel kosong pada kolom judul tetap tampil sebagai None. Penjumlahan kolom berisi None tidak mungkin, sehingga pandas mengonversinya menjadi NaN pada kolom numerik agar perhitungan tetap bisa dijalankan.
Perintah isna mengembalikan tabel boolean dengan ukuran yang sama, berisi True untuk sel kosong dan False untuk sel terisi. Penjumlahan atas tabel boolean itu, yaitu isna().sum(), menghitung jumlah sel kosong per kolom dan menjadi jawaban atas pertanyaan pertama yang diajukan saat data diperiksa.
import pandas as pd
pinjam = pd.DataFrame({
"anggota": ["Ali", "Budi", "Citra", "Dewi", "Eka", "Fajar"],
"judul": ["Atlas Dunia", "Kamus Biologi", None, "Ensiklopedia Sains", "Atlas Dunia", None],
"lama_hari": [7, 10, 5, None, None, 12],
})
print(pinjam.isna().sum())anggota 0
judul 2
lama_hari 2
dtype: int64Hasilnya menyebutkan dua sel kosong pada kolom judul dan dua pada kolom lama_hari, sedangkan kolom anggota terisi penuh. Jumlah inilah dasar semua keputusan berikutnya. Data dengan satu atau dua sel kosong pada ribuan baris menuntut strategi yang berbeda daripada data dengan kolom yang kosong sebagian besar isinya.
Akibat pada perhitungan#
Nilai yang hilang bukan nol, dan perbedaannya terlihat pada perhitungan. Fungsi agregasi seperti mean dan sum melewati sel kosong secara default, sehingga rata-rata lama_hari dihitung hanya dari empat nilai yang terisi. Argumen skipna=False mematikan perilaku itu, dan hasilnya berubah menjadi NaN karena sel kosong ikut dihitung.
import pandas as pd
pinjam = pd.DataFrame({
"anggota": ["Ali", "Budi", "Citra", "Dewi", "Eka", "Fajar"],
"judul": ["Atlas Dunia", "Kamus Biologi", None, "Ensiklopedia Sains", "Atlas Dunia", None],
"lama_hari": [7, 10, 5, None, None, 12],
})
print(pinjam["lama_hari"].mean())
print(pinjam["lama_hari"].sum(skipna=False))
print()
print(pinjam["lama_hari"] > 6)8.5
nan
0 True
1 True
2 False
3 False
4 False
5 True
Name: lama_hari, dtype: boolBagian ketiga keluaran menunjukkan akibat yang lebih halus. Perbandingan lama_hari > 6 menghasilkan False untuk sel kosong, sehingga penyaringan dengan syarat semacam itu diam-diam membuang baris yang nilainya belum diketahui. Baris Dewi dan Eka tidak memenuhi syarat bukan karena nilainya kecil, melainkan karena nilainya tidak ada. Perilaku ini wajar untuk sebagian analisis dan menyesatkan untuk yang lain, sehingga perlu disadari sebelum penyaringan dijalankan.
Memilih antara dropna dan fillna#
Dua strategi dasar menangani nilai yang hilang adalah membuang barisnya dengan dropna atau mengisinya dengan fillna. Tanpa argumen tambahan, dropna membuang setiap baris yang memuat minimal satu sel kosong. Pada data contoh yang hanya berisi enam baris, perilaku itu menyisakan dua baris, sehingga empat catatan hilang begitu saja.
import pandas as pd
pinjam = pd.DataFrame({
"anggota": ["Ali", "Budi", "Citra", "Dewi", "Eka", "Fajar"],
"judul": ["Atlas Dunia", "Kamus Biologi", None, "Ensiklopedia Sains", "Atlas Dunia", None],
"lama_hari": [7, 10, 5, None, None, 12],
})
print(pinjam.dropna())
print()
print(pinjam.dropna(subset=["judul"])) anggota judul lama_hari
0 Ali Atlas Dunia 7.0
1 Budi Kamus Biologi 10.0
anggota judul lama_hari
0 Ali Atlas Dunia 7.0
1 Budi Kamus Biologi 10.0
3 Dewi Ensiklopedia Sains NaN
4 Eka Atlas Dunia NaNArgumen subset membatasi kolom yang diperiksa. Dengan dropna(subset=["judul"]), hanya baris dengan judul kosong yang dibuang, sehingga catatan Dewi dan Eka tetap ada meskipun lama_hari tidak terisi. Pilihan ini lebih presisi dan biasanya lebih aman daripada dropna tanpa argumen. Kehilangan dua dari enam baris sudah terasa besar, dan pembuangan baris dalam jumlah besar pada data nyata dapat mengubah hasil analisis tanpa terlihat.
Alternatif kedua adalah mengisi sel kosong dengan nilai tertentu. Nilai isian harus masuk akal untuk kolomnya, misalnya median untuk kolom angka dan teks penanda untuk kolom judul. Contoh berikut mengisi kedua kolom dengan strategi yang berbeda pada salinan data, agar data asli tetap utuh sebagai pembanding.
import pandas as pd
pinjam = pd.DataFrame({
"anggota": ["Ali", "Budi", "Citra", "Dewi", "Eka", "Fajar"],
"judul": ["Atlas Dunia", "Kamus Biologi", None, "Ensiklopedia Sains", "Atlas Dunia", None],
"lama_hari": [7, 10, 5, None, None, 12],
})
bersih = pinjam.copy()
bersih["judul"] = bersih["judul"].fillna("Judul tidak tercatat")
bersih["lama_hari"] = bersih["lama_hari"].fillna(bersih["lama_hari"].median())
print(bersih) anggota judul lama_hari
0 Ali Atlas Dunia 7.0
1 Budi Kamus Biologi 10.0
2 Citra Judul tidak tercatat 5.0
3 Dewi Ensiklopedia Sains 8.5
4 Eka Atlas Dunia 8.5
5 Fajar Judul tidak tercatat 12.0Kolom lama_hari diisi dengan median dari nilai yang terisi, sedangkan kolom judul diisi dengan teks penanda. Hasil akhirnya berukuran enam baris utuh, dan setiap selnya kini dapat dihitung atau disaring tanpa perilaku tersembunyi. Isian teks penanda tetap perlu ditandai sebagai data tanpa informasi, sebab baris dengan “Judul tidak tercatat” bukan judul sebenarnya, melainkan ketiadaan informasi judul yang diberi nama.
Keputusan per kolom dan dokumentasinya#
Penanganan nilai yang hilang berakhir pada keputusan yang berbeda untuk setiap kolom, dan keputusan itu mengikuti makna kolomnya. Judul buku yang tidak tercatat tidak dapat ditebak, sehingga diisi teks penanda. Lama pinjam yang kosong dapat diisi median karena nilainya berkisar sempit, atau dibuang bila analisis menuntut data lengkap. Kolom anggota yang terisi penuh tidak membutuhkan perlakuan apa pun.
| Kolom | Sel kosong | Keputusan | Alasan |
|---|---|---|---|
| anggota | 0 | tanpa perlakuan | kolom terisi penuh |
| judul | 2 | isi “Judul tidak tercatat” | judul tidak dapat ditebak |
| lama_hari | 2 | isi median | nilai berkisar sempit dan digunakan untuk perhitungan |
Tabel semacam ini menjadi dokumentasi strategi. Tanpa dokumentasi, pembaca laporan tidak dapat membedakan antara nilai median hasil pengisian dan data asli, dan analisis yang diulang di kemudian hari dapat mengambil keputusan yang berbeda. Dokumentasi yang cukup mencatat kolom, jumlah sel kosong, keputusan, dan alasannya. Catatan yang sama dapat ditulis sebagai komentar pada kode pembersihan, sehingga keputusan dan eksekusinya berada di satu tempat.
Kesalahan umum#
Kesalahan pertama adalah mengisi sel kosong dengan nol tanpa alasan. Metode fillna(0) mudah ditulis dan hasilnya terlihat rapi, tetapi nol memiliki makna sendiri pada kebanyakan kolom, misalnya peminjaman dengan lama nol hari. Statistik yang dihitung dari data berisi nol hasil pengisian menjadi salah secara diam-diam, dan kesalahan ini jarang muncul pada pesan error apa pun.
Kesalahan kedua adalah menjalankan dropna tanpa subset pada data yang lebar. Satu kolom yang tidak relevan untuk analisis, misalnya kolom catatan tambahan yang jarang terisi, cukup untuk membuang baris yang sebenarnya lengkap. Batasi kolom yang diperiksa pada kolom yang digunakan analisisnya.
Kesalahan ketiga adalah membandingkan kolom dengan None untuk mencari sel kosong. Ekspresi pinjam["lama_hari"] == None menghasilkan False untuk semua baris termasuk yang kosongnya NaN, karena perbandingan dengan NaN selalu False. Fungsi isna adalah cara yang tepat untuk mendeteksi sel kosong, baik berupa NaN maupun None.
Ringkasan#
isna().sum()menghitung sel kosong per kolom dan menjadi dasar semua keputusan penanganannya.dropnamembuang baris dengansubsetuntuk membatasi kolom yang diperiksa, sedangkanfillnamengisi sel kosong dengan nilai yang masuk akal untuk kolomnya.- Nilai kosong berperilaku khusus pada perhitungan, yaitu dilewati agregasi dan selalu False pada perbandingan, sehingga penyaringan perlu diperiksa ulang.
- Setiap keputusan didokumentasikan per kolom beserta alasannya, misalnya dalam bentuk tabel keputusan.
Referensi#
- pandas user guide — Pandas — Panduan resmi pandas yang memuat bagian working with missing data.
- NumPy documentation — NumPy — Dokumentasi numpy, library yang menyediakan nilai nan pada kolom numerik pandas.