Cara Mengganti Nilai yang Hilang (NA) di R: na.omit & na.rm

โšก Ringkasan Cerdas

Panduan Mengganti Nilai yang Hilang di R membahas cara mendeteksi nilai NA, menghapus baris yang tidak lengkap dengan na.omit(), dan mengisinya dengan nilai rata-rata atau median melalui mutate(). Panduan ini menggunakan dataset Titanic, di mana usia dan tarif sama-sama memiliki pengamatan yang hilang.

  • ๐Ÿ”Ž Deteksi Pertama: colSums(is.na(df)) menghitung nilai yang hilang per kolom sebelum mengambil keputusan tentang cara menanganinya.
  • ๏ธ Penghapusan Baris: na.omit() menghapus setiap baris yang berisi NA, mengurangi data Titanic dari 1,309 baris menjadi 1,045 baris.
  • ๐Ÿ“ Imputasi Rata-rata: apply() dengan na.rm = TRUE menghitung rata-rata kolom, dan mutate() dengan ifelse() menuliskannya ke kolom baru.
  • ๐Ÿ“Š Alternatif Median: Median cenderung mengabaikan nilai-nilai ekstrem, sehingga menjadikannya pilihan yang lebih aman untuk variabel yang miring seperti tarif.
  • โšก Imputasi Massal: sapply() atau across() menerapkan aturan yang sama ke setiap kolom numerik dalam satu pernyataan.
  • โš ๏ธ Kompromi yang Diketahui: Imputasi rata-rata mengurangi varians dan melemahkan korelasi, jadi metode ini tidak boleh diterapkan secara membabi buta.

Ganti Nilai yang Hilang NA di R

Apa itu nilai yang hilang (missing values) di R?

Nilai yang hilang muncul ketika suatu observasi tidak memiliki nilai yang tercatat dalam sebuah kolom, atau ketika placeholder non-numerik berada di tempat seharusnya ada angka. Nilai yang hilang harus dihapus atau diganti sebelum perhitungan apa pun, karena sebagian besar fungsi R mengembalikan NA begitu nilai tersebut ada.

Tutorial ini menunjukkan cara menangani nilai yang hilang dengan pustaka dplyr, bagian dari ekosistem tidyverse untuk analisis data.

Ganti Nilai yang Hilang di R

Langkah pertama selalu mencari tahu berapa banyak nilai yang hilang dan di mana letaknya.

Cara Mendeteksi dan Menghitung Nilai yang Hilang di R

Sebelum memutuskan apa yang harus dilakukan terhadap nilai yang hilang, Anda perlu mengetahui berapa banyak nilai yang hilang dan di mana letaknya. R menawarkan empat cara pengecekan, mulai dari jawaban ya atau tidak tunggal hingga penghitungan lengkap per kolom.

# 1. Is there any NA at all?
anyNA(df_titanic)

# 2. How many in total?
sum(is.na(df_titanic))

# 3. How many per column, the most useful view
colSums(is.na(df_titanic))

# 4. Percentage missing per column
round(colMeans(is.na(df_titanic)) * 100, 1)

Dalam praktiknya, colSums() adalah fungsi yang tepat untuk digunakan. Fungsi ini mengembalikan vektor bernama dengan satu hitungan per kolom, yang langsung menunjukkan apakah suatu variabel kehilangan sejumlah nilai atau sebagian besar kosong.

Menghitung baris lengkap. complete.cases() mengembalikan TRUE untuk baris yang tidak memiliki nilai yang hilang di mana pun, yang memberi tahu Anda sebelumnya berapa banyak data yang akan dibuang oleh na.omit():

sum(complete.cases(df_titanic))       # rows that would survive
sum(!complete.cases(df_titanic))      # rows that would be dropped

Peringatan tentang placeholder. R hanya mengenali NA. Dataset sering kali mengkodekan nilai yang hilang sebagai string kosong, spasi, โ€œN/Aโ€, โ€œ-โ€, atau angka sentinel seperti -99 atau 999. Nilai-nilai tersebut lolos dari semua pemeriksaan di atas tanpa terdeteksi. Konversikan nilai-nilai tersebut saat impor agar alur kerja selanjutnya berfungsi dengan baik:

df <- read.csv(PATH, na.strings = c("", " ", "NA", "N/A", "-", "-99"))

Selalu periksa rentang setiap kolom numerik setelah impor. Usia -99 atau tarif 9999 jauh lebih berbahaya daripada NA yang sebenarnya, karena tidak ada fungsi yang akan memperingatkan Anda tentang hal itu.

Jenis Data yang Hilang: MCAR, MAR, dan MNAR

Alasan mengapa suatu nilai hilang menentukan apakah pengisian nilai tersebut aman dilakukan. Para ahli statistik mengenali tiga mekanisme.

  • MCAR, hilang sepenuhnya secara acak. Probabilitas hilang tidak terkait dengan apa pun, baik yang teramati maupun tidak, misalnya sensor yang rusak secara acak. Jatuhping atau memasukkan data dari baris-baris ini tidak menimbulkan bias, hanya mengurangi ketelitian.
  • MAR, hilang secara acak. Probabilitasnya bergantung pada variabel teramati lainnya, tetapi tidak pada nilai yang hilang itu sendiri. Jika penumpang yang lebih tua cenderung kurang tercatat usianya, maka usia tersebut bersifat MAR (Missing At Random) berdasarkan kolom-kolom lainnya. Imputasi yang menggunakan kolom-kolom tersebut dapat menangani hal ini dengan baik.
  • MNAR, hilang bukan secara acak. Probabilitasnya bergantung pada nilai yang tidak teramati itu sendiri, misalnya, mereka yang berpenghasilan tinggi menolak untuk menyatakan pendapatan mereka. Tidak ada metode imputasi yang dapat memperbaiki hal ini hanya dari data saja, dan data yang hilang itu sendiri mengandung informasi yang layak dicatat dalam kolom penanda.

Imputasi rata-rata, seperti yang digunakan dalam tutorial ini, hanya dapat dibenarkan dalam kondisi MCAR dan MAR sederhana. Bahkan dalam kondisi tersebut, metode ini memiliki biaya yang diketahui: mengisi setiap celah dengan angka yang sama akan mengurangi varians kolom dan melemahkan korelasinya dengan semua hal lainnya. Untuk pekerjaan yang serius, gunakan metode berbasis model seperti paket mice, dan selalu simpan kolom penanda yang menunjukkan nilai mana yang telah diimputasi.

mengubah()

mutate() adalah dplyr Kata kerja yang membuat variabel baru atau menimpa variabel yang sudah ada, sehingga menjadikannya alat yang tepat untuk membuat salinan kolom yang sudah dibersihkan.

Kami akan melanjutkan dalam dua bagian. Kita akan belajar bagaimana:

  • mengecualikan nilai yang hilang dari bingkai data
  • menghubungkan nilai yang hilang dengan mean dan median

Kata kerja mutate() sangat mudah digunakan. Kita dapat membuat variabel baru dengan mengikuti sintaks berikut:

mutate(df, name_variable_1 = condition, ...)
arguments:
-df: Data frame used to create a new variable
-name_variable_1: Name and the formula to create the new variable
-...: No limit constraint. Possibility to create more than one variable inside mutate()

Kecualikan nilai yang hilang (NA)

na.omit() adalah fungsi dasar R, bukan kata kerja dplyr, tetapi tetap berfungsi dengan baik. Fungsi ini menghapus setiap baris yang berisi setidaknya satu nilai NA. Ini adalah pilihan tercepat dan jarang menjadi pilihan terbaik, karena satu nilai yang hilang akan menghapus seluruh observasi.

Untuk mengatasi masalah observasi yang hilang, kami akan menggunakan dataset Titanic. Dalam kumpulan data ini, kami memiliki akses terhadap informasi penumpang di pesawat saat tragedi tersebut. Dataset ini memiliki banyak NA yang perlu diperhatikan.

Unduh file CSV dari internet, lalu sebutkan kolom-kolom yang berisi NA:

PATH <- "https://raw.githubusercontent.com/guru99-edu/R-Programming/master/test.csv"
df_titanic <- read.csv(PATH, sep = ",")
# Return the column names containing missing observations
list_na <- colnames(df_titanic)[ apply(df_titanic, 2, anyNA) ]
list_na

Keluaran:

## [1] "age"  "fare"

Di sini,

colnames(df_titanic)[apply(df_titanic, 2, anyNA)]

Mengembalikan nama-nama kolom yang berisi setidaknya satu nilai yang hilang.

Kolom age dan fare memiliki nilai yang hilang.

Kita bisa membuangnya dengan na.omit().

library(dplyr)
# Exclude the missing observations
df_titanic_drop <-df_titanic %>%
na.omit()		
dim(df_titanic_drop)

Keluaran:

## [1] 1045   13

Dataset baru berisi 1045 baris dibandingkan 1309 dengan dataset asli.

Kecualikan Nilai yang Hilang

Isi data yang hilang dengan nilai rata-rata dan median.

Anda juga dapat mengisi nilai yang hilang dengan nilai rata-rata atau median. Praktik yang baik adalah membuat dua variabel terpisah untuk rata-rata dan median. Setelah dibuat, kita dapat mengganti nilai yang hilang dengan variabel yang baru dibuat.

Kami akan menggunakan metode apply untuk menghitung mean kolom dengan NA. Mari kita lihat sebuah contoh

Langkah 1) Sebelumnya di tutorial, kita menyimpan nama kolom dengan nilai yang hilang dalam daftar yang disebut list_na. Kami akan menggunakan daftar ini

Langkah 2) Hitung nilai rata-rata dengan argumen na.rm = TRUE. Argumen ini wajib karena kolom-kolom tersebut memiliki data yang hilang, dan ini memberi tahu R untuk mengabaikannya.

# Create mean
average_missing <- apply(df_titanic[,colnames(df_titanic) %in% list_na],
      2,
      mean,
      na.rm =  TRUE)
average_missing

Code Penjelasan:

Kami meneruskan 4 argumen dalam metode penerapan.

  • df: df_titanic[,nama kolom(df_titanic) %dalam% list_na]. Kode ini akan mengembalikan nama kolom dari objek list_na (yaitu โ€œusiaโ€ dan โ€œtarifโ€)
  • 2: Hitung fungsi pada kolom
  • mean: Hitung meannya
  • na.rm = TRUE: Abaikan nilai yang hilang

Keluaran:

##      age     fare 
## 29.88113 33.29548

Kami berhasil membuat mean kolom yang berisi observasi yang hilang. Kedua nilai ini akan digunakan untuk menggantikan observasi yang hilang.

Langkah 3) Ganti Nilai NA

Kata kerja mutate dari perpustakaan dplyr berguna dalam membuat variabel baru. Kita tidak serta merta ingin mengubah kolom asli sehingga kita bisa membuat variabel baru tanpa NA. mutate mudah digunakan, kita tinggal memilih nama variabel dan menentukan cara membuat variabel ini. Berikut kode lengkapnya

# Create a new variable with the mean and median
df_titanic_replace <- df_titanic %>%
   mutate(replace_mean_age  = ifelse(is.na(age), average_missing[1], age),
   replace_mean_fare = ifelse(is.na(fare), average_missing[2], fare))

Code Penjelasan:

Kami membuat dua variabel, replace_mean_age dan replace_mean_fare sebagai berikut:

  • replace_mean_age = ifelse(is.na(usia), rata-rata_hilang[1], usia)
  • replace_mean_fare = ifelse(is.na(tarif), rata-rata_hilang[2],tarif)

Jika kolom age memiliki nilai yang hilang, ganti dengan elemen pertama rata-rata_hilang (rata-rata usia), jika tidak pertahankan nilai aslinya. Logika yang sama untuk tarif

sum(is.na(df_titanic_replace$age))

Keluaran:

## [1] 263

Setelah penggantian, kolom baru tersebut tidak mengandung nilai yang hilang sama sekali:

sum(is.na(df_titanic_replace$replace_mean_age))

Keluaran:

## [1] 0

Kolom usia asli berisi 263 nilai yang hilang, sedangkan kolom replace_mean_age yang baru telah mengisi setiap nilai yang hilang tersebut dengan usia rata-rata.

Langkah 4) Kita juga bisa mengganti observasi yang hilang dengan median.

median_missing <- apply(df_titanic[,colnames(df_titanic) %in% list_na],
      2,
      median,
      na.rm =  TRUE)
df_titanic_replace <- df_titanic %>%
            mutate(replace_median_age  = ifelse(is.na(age), median_missing[1], age), 
            replace_median_fare = ifelse(is.na(fare), median_missing[2], fare))
head(df_titanic_replace)

Keluaran:

Perhitungkan data yang Hilang dengan Mean dan Median

Langkah 5) Pada dataset yang besar, metode langkah demi langkah menjadi membosankan. sapply() meringkas seluruh prosedur menjadi satu pernyataan, dengan konsekuensi tidak pernah melihat nilai yang diimputasi.

sapply tidak membuat a bingkai data, sehingga kita dapat menggabungkan fungsi sapply() di dalam data.frame() untuk membuat objek bingkai data.

# Quick code to replace missing values with the mean
df_titanic_impute_mean <- data.frame(
    sapply(
        df_titanic,
        function(x) ifelse(is.na(x),
            mean(x, na.rm = TRUE),
            x)))

Imputasi Modern dengan replace_na() dan across()

Pendekatan apply() dan sapply() di atas masih berfungsi, tetapi tidyr dan dplyr sekarang mengekspresikan operasi yang sama dengan lebih aman dan lebih mudah dibaca.

replace_na() untuk nilai tetap. tidyr::replace_na() menerima daftar bernama yang berisi kolom dan penggantinya:

library(tidyr)

df_titanic %>%
    replace_na(list(age = 29.88, fare = 33.30))

across() untuk setiap kolom numerik. Ini adalah pengganti langsung dan aman tipe untuk perintah sapply() yang dijalankan sekali baris, dan tidak seperti sapply(), perintah ini tidak pernah menyentuh kolom karakter atau faktor:

library(dplyr)

# Mean-impute every numeric column
df_titanic %>%
    mutate(across(where(is.numeric),
                  ~ ifelse(is.na(.x), mean(.x, na.rm = TRUE), .x)))

# Median-impute instead
df_titanic %>%
    mutate(across(where(is.numeric),
                  ~ ifelse(is.na(.x), median(.x, na.rm = TRUE), .x)))

โš ๏ธ Mengapa pintasan sapply() berisiko: Contoh sapply() satu baris berjalan lebih dari setiap kolom, termasuk kolom karakter dan faktor. Memanggil mean() pada kolom tersebut akan mengembalikan NA dengan peringatan, dan sapply() kemudian akan mengubah seluruh hasilnya menjadi karakter. Versi across(where(is.numeric), โ€ฆ) di atas sepenuhnya menghindari hal ini.

coalesce() untuk kolom cadangan. Ketika kolom kedua dapat memberikan nilai yang hilang, coalesce() mengembalikan entri pertama yang tidak hilang di antara argumennya:

df %>% mutate(age_final = coalesce(age, age_estimated, 0))

Catatlah perubahan apa saja yang Anda lakukan. Tambahkan sebuah flag sebelum memasukkan nilai, agar model selanjutnya dapat belajar dari fakta bahwa suatu nilai hilang:

df_titanic %>%
    mutate(age_was_missing = is.na(age),
           age = ifelse(is.na(age), mean(age, na.rm = TRUE), age))

Menangani Nilai yang Hilang di R: Referensi Metode

Tutorial ini membahas tiga pendekatan:

  • Kecualikan semua pengamatan yang hilang
  • Menyalahkan dengan maksudnya
  • Perhitungkan dengan median

Tabel di bawah ini merangkum deteksi dan penghapusan:

Perpustakaan Tujuan Code
mendasarkan Buat daftar pengamatan yang hilang
colnames(df)[apply(df, 2, anyNA)]
mendasarkan Hapus setiap baris yang berisi NA
na.omit(df)

Imputasi dengan mean atau median dapat dilakukan dengan dua cara

  • Menggunakan terapkan
  • Menggunakan aplikasi
metode Detail Kelebihan Kekurangan
Langkah demi langkah dengan melamar Periksa kolom yang hilang, hitung mean/median, simpan nilainya, ganti dengan mutate() Anda dapat melihat nilai rata-rata atau median yang dihitung. Waktu eksekusi lebih lama. Bisa lambat dengan kumpulan data besar
Cara cepat dengan sapply Gunakan sapply() dan data.frame() untuk secara otomatis mencari dan mengganti nilai yang hilang dengan mean/median Kode pendek dan cepat Nilai yang dimasukkan tidak pernah ditampilkan.

Pertanyaan Umum Demo Slot

NA menandai nilai yang hilang di dalam sebuah vektor. NULL mewakili ketiadaan suatu objek dan memiliki panjang nol. NaN adalah hasil dari operasi numerik yang tidak terdefinisi, seperti membagi nol dengan nol.

Gunakan median untuk variabel yang miring (skewed) seperti tarif atau pendapatan, karena nilai ekstrem (outlier) akan menaikkan nilai rata-rata. Gunakan rata-rata hanya jika kolom tersebut kurang lebih simetris dan bebas dari nilai ekstrem.

Mengisi setiap celah dengan nilai yang sama akan mengurangi varians kolom dan melemahkan korelasinya dengan variabel lain. Metode berbasis model seperti paket mice mempertahankan hubungan tersebut dengan jauh lebih baik.

Sebagian besar algoritma tidak dapat menerima NA dan akan menghasilkan kesalahan atau menghapus baris secara diam-diam. Imputasi yang ceroboh dapat menyebabkan kebocoran informasi antara set pelatihan dan set pengujian, jadi selalu hitung nilai imputasi hanya pada pembagian data pelatihan saja.

Ya. Asisten AI dapat menyarankan metode berdasarkan pola data yang hilang dan membuat draf kode dplyr. Verifikasi pilihan tersebut dengan output colSums(is.na()) Anda sendiri dan pengetahuan domain tentang mengapa data tersebut hilang.

Ringkaslah postingan ini dengan: