NA berarti "tidak diketahui", dan ia menyebar
Dataset nyata punya lubang: pertanyaan survei yang dibiarkan kosong, sensor yang kehilangan satu pembacaan. R merepresentasikan setiap lubang dengan NA, singkatan dari not available. Model berpikir yang penting: NA bukan nol, bukan string kosong, bukan angka khusus. NA berarti "ada nilai di sini, tapi kita tidak tahu nilainya berapa."
Pahami itu dengan serius, maka perilaku R jadi masuk akal. Berapa hasil angka yang tidak diketahui ditambah satu? Tidak diketahui. Berapa rata-rata dari 4, 8, dan sesuatu yang tidak diketahui? Tidak diketahui: nilai yang hilang bisa berapa saja, jadi rata-ratanya juga bisa berapa saja:
Ketiganya mencetak NA. Sifat menular ini fitur, bukan bug: R menolak diam-diam berpura-pura tahu jawaban yang sebenarnya tidak diketahuinya. Spreadsheet yang diam-diam melewati sel kosong bisa menyembunyikan fakta bahwa separuh kolomnya hilang; R membuatmu sadar dan memutuskan apa arti nilai yang hilang bagi analisismu. Sisa artikel ini tentang membuat keputusan itu dengan sengaja.
Menguji NA: is.na(), jangan pernah ==
Inilah jebakan pertama yang menjerat semua orang. Kamu ingin menemukan nilai yang hilang, jadi kamu menulis sebuah perbandingan, dan itu tidak berhasil:
x == NA mengembalikan NA NA NA, tanpa satu pun TRUE. Kenapa? Ikuti logika "tidak diketahui": apakah 4 sama dengan suatu nilai yang tidak diketahui? Tidak bisa dipastikan, karena yang tidak diketahui itu mungkin saja 4. Bahkan slot NA pun dibandingkan sebagai NA: apakah satu nilai yang tidak diketahui sama dengan nilai tidak diketahui lainnya? Tidak diketahui. Perbandingan dengan NA tidak pernah bisa mengembalikan TRUE atau FALSE, jadi tidak berguna sebagai uji, dan lebih buruk lagi, mask yang seluruhnya NA di dalam [ ] tidak memilih apa yang kamu harapkan.
Alat yang benar adalah is.na(), yang dibuat untuk menjawab persis pertanyaan ini dan mengembalikan nilai logika yang jujur: FALSE TRUE FALSE. Dari situ, ada dua idiom yang akan terus kamu pakai:
sum(is.na(x)) menghitung jumlah nilai yang hilang (TRUE dijumlahkan sebagai 1); jalankan pada setiap kolom dataset baru sebelum hal lainnya. which(is.na(x)) menemukan letaknya. Dan x[!is.na(x)] hanya mempertahankan nilai yang teramati, penghapusan manual lewat mask logika, pola penyaringan vector yang sama seperti biasa.
Melewati NA dalam ringkasan: na.rm = TRUE
Kamu biasanya tidak perlu menghapus NA secara manual, karena fungsi ringkasan R punya jalan keluar bawaan, yaitu argumen na.rm (NA remove):
Dengan na.rm = TRUE, fungsinya membuang nilai yang hilang lalu menghitung dari yang tersisa: rata-rata dari 4 dan 8 adalah 6. sum(), sd(), median(), min(), max(), var(), seluruh keluarga statistik deskriptif menerimanya.
Perhatikan bahwa default-nya FALSE. Itulah R yang punya pendirian demi kebaikanmu: R ingin pengabaian data yang hilang menjadi pilihan eksplisit yang kamu tuliskan, bukan default yang diam. Saat kamu mengetik na.rm = TRUE, kamu menyatakan "nilai yang hilang di sini aman untuk diabaikan", yang benar saat sebuah sensor melewatkan beberapa pembacaan secara acak, dan berbahaya saat, misalnya, orang-orang berpenghasilan terendah melewati pertanyaan tentang penghasilan. Argumen itu membuatmu bertanggung jawab atas keputusan tersebut.
Membuang baris yang tidak lengkap: na.omit() dan complete.cases()
Di data frame, data yang hilang berada di sel, tapi analisis sering bekerja baris demi baris, jadi operasi yang umum adalah membuang baris yang punya NA:
na.omit(df) mengembalikan data frame tanpa setiap baris yang berisi setidaknya satu NA; di sini, hanya Rosa yang bertahan. complete.cases(df) mengembalikan mask baris logika (TRUE FALSE FALSE) di balik gagasan yang sama, dan mengindeks dengannya memberi hasil identik dengan dua kelebihan: kamu bisa menghitung dulu berapa yang akan hilang (sum(!complete.cases(df))), dan kamu bisa membatasi kolom mana yang penting: df[complete.cases(df[, "age"]), ] hanya membuang baris yang age-nya hilang, sehingga Mia tetap ada meskipun skornya tidak diketahui.
Bentuk yang dibatasi per kolom itu lebih penting daripada kelihatannya: na.omit() pada data frame yang lebar bisa diam-diam membuang sebagian besar barismu karena NA di kolom-kolom yang tidak pernah kamu rencanakan untuk dianalisis. Ketahui berapa banyak baris yang kamu buang, dan alasannya, sebelum membuangnya.
Mengganti NA
Kadang langkah yang tepat adalah mengisi lubang, bukan menghapus baris. Idiomnya menggabungkan is.na() dengan penugasan:
Bacalah sebagai: "di slot-slot tempat visits hilang, isi dengan 0." Ini sah tepat saat NA mewakili nilai yang sudah diketahui: pelanggan tanpa catatan kunjungan memang benar-benar punya nol kunjungan.
Tapi jujurlah soal kapan itu benar. Kalau NA berarti "kita gagal mengukurnya", mengganti dengan 0 sama dengan mengarang data: mengganti nilai ujian yang hilang dengan 0 menyeret rata-rata turun seolah-olah siswa-siswa itu mendapat nol, padahal sebenarnya kamu tidak tahu nilai mereka. Bandingkan rata-rata di atas (2,4) dengan rata-rata na.rm dari data aslinya (4): data yang sama, klaim yang berbeda. Mengganti dengan rata-rata atau median lebih sedikit mendistorsi, tapi tetap mengecilkan variabilitas. Aturannya: isi sebuah nilai hanya saat kamu bisa mengatakan, dengan kata-kata sederhana, mengapa nilai itulah yang sebenarnya untuk entri yang hilang. Kalau tidak, pertahankan NA dan pakai na.rm; "tidak diketahui" sering kali adalah nilai paling jujur di dataset itu.
NA vs NULL vs NaN vs Inf
R punya empat nilai khusus yang mirip tapi artinya benar-benar berbeda:
| Nilai | Arti | Panjang | Sumber yang umum |
|---|---|---|---|
NA | Nilainya ada tapi tidak diketahui | 1 (mengisi slot) | Data yang hilang |
NULL | Tidak ada objek sama sekali | 0 (tanpa slot) | Elemen list yang dihapus, hasil kosong |
NaN | Perhitungan yang hasilnya tidak terdefinisi | 1 | 0 / 0, log(-1) |
Inf | Angka di luar batas representasi | 1 | 1 / 0, overflow |
Perbedaan yang penting dalam praktik: NULL lenyap di dalam vector (c(1, NULL, 3) punya dua elemen, jadi NULL tidak bisa mewakili observasi yang hilang), sedangkan NA tetap menempati tempatnya. NaN dihitung sebagai nilai yang hilang (is.na(NaN) bernilai TRUE, jadi na.rm juga membuangnya), tapi kebalikannya tidak berlaku: is.nan(NA) bernilai FALSE. Dan Inf bukan nilai yang hilang; ia angka sungguhan yang bisa dibandingkan (Inf > 1e300 bernilai TRUE), jadi na.rm tidak akan membuangnya. Pakai is.finite() untuk menyaring hanya angka-angka biasa.
Sebagai pelengkap: NA diam-diam punya beberapa varian bertipe (NA_integer_, NA_real_, NA_character_) supaya bisa berada di vector apa pun tanpa melanggar aturan satu tipe. Kamu jarang mengetiknya, tapi kamu akan melihatnya di kode package dan pesan error dplyr.
Yang kamu bawa pulang
NAberarti "tidak diketahui", dan yang tidak diketahui itu menular: perhitungan apa pun yang menyentuh NA mengembalikan NA, memang begitu rancangannya.- Uji dengan
is.na(), jangan pernah== NA; hitung lubangnya dengansum(is.na(x)). na.rm = TRUEmembuat fungsi ringkasan melewati NA, keputusan eksplisit per pemanggilan bahwa nilai yang hilang boleh diabaikan.na.omit()membuang baris yang tidak lengkap sekaligus;complete.cases()memberimu mask-nya, yang bisa dihitung dan dibatasi pada kolom-kolom yang penting.- Ganti NA (
x[is.na(x)] <- value) hanya saat kamu bisa membenarkan berapa sebenarnya nilai yang hilang itu. - NA ≠ NULL ≠ NaN ≠ Inf: nilai yang hilang, objek yang tidak ada, perhitungan tak terdefinisi, angka tak terbatas.
Berikutnya: fungsi, membungkus logikamu menjadi bagian-bagian bernama yang bisa dipakai ulang.
Pertanyaan yang sering diajukan
Kenapa mean() mengembalikan NA di R?
Karena setidaknya satu nilai di vector itu adalah NA, dan NA itu menular: kalau ada input yang tidak diketahui, R mengatakan jawabannya juga tidak diketahui. Berikan na.rm = TRUE, yaitu mean(x, na.rm = TRUE), untuk menghitung rata-rata dari nilai yang ada. Sebagian besar fungsi ringkasan (sum, sd, median, min, max) menerima argumen yang sama.
Bagaimana cara memeriksa NA di R?
Dengan is.na(x), yang mengembalikan TRUE di mana pun nilainya hilang. Jangan pernah menguji dengan x == NA: membandingkan apa pun dengan sesuatu yang tidak diketahui menghasilkan NA, bukan TRUE atau FALSE, sehingga ujinya diam-diam gagal. sum(is.na(x)) menghitung jumlah nilai yang hilang; which(is.na(x)) menemukan posisinya.
Bagaimana cara menghapus baris yang berisi NA dari data frame di R?
na.omit(df) membuang setiap baris yang berisi setidaknya satu NA. Untuk kendali lebih, complete.cases(df) mengembalikan logical vector yang menandai baris yang lengkap, jadi df[complete.cases(df), ] melakukan hal yang sama secara eksplisit, dan kamu bisa menerapkannya hanya pada kolom yang penting, misalnya df[complete.cases(df[, c("age", "score")]), ].
Apa perbedaan NA dan NULL di R?
NA adalah nilai yang hilang: ia menempati satu slot di vector dan panjangnya 1. NULL adalah ketiadaan objek: panjangnya 0 dan lenyap saat dimasukkan ke vector, sehingga c(1, NULL, 3) hanya punya dua elemen. Pakai NA untuk titik data yang hilang; NULL muncul saat menghapus elemen list atau sebagai nilai kembalian yang kosong.