Menu

Error umum di R dan cara melakukan debug

Penerjemah pesan error klasik R (object not found, could not find function, non-numeric argument, dan kawan-kawannya), plus tryCatch, traceback(), dan debug jujur dengan print.

Halaman ini dilengkapi editor yang bisa dijalankan. Edit, jalankan, dan lihat output-nya seketika.

Membaca pesan error R

Error R punya dua bagian, dan keduanya berguna:

Error in "10" + 5 : non-numeric argument to binary operator

Setelah Error in muncul pemanggilan, yaitu potongan kode persis yang gagal ("10" + 5). Setelah titik dua muncul kondisi, yaitu apa yang salah (non-numeric argument to binary operator). Baca pemanggilannya dulu: bagian itu memberi tahu di mana, dan sering kali kamu sudah bisa melihat masalahnya langsung di kode yang dikutip. Lalu baca kondisinya untuk mengetahui mengapa.

Dua kebiasaan membedakan orang yang cepat melakukan debug dari orang yang kesulitan. Pertama, benar-benar baca pesannya: pesan R biasanya tepat, hanya ditulis dengan singkat. Kedua, debug error yang pertama, bukan yang terakhir: satu kegagalan di awal skrip bisa berantai menjadi tumpukan error "object not found" di bawahnya yang semuanya hilang saat kamu memperbaiki yang asli. Sisa halaman ini adalah penerjemah untuk pesan yang paling sering kamu temui, lalu alat-alat untuk saat membaca saja tidak cukup.

Error nama: not found

Error: object 'total' not found: R sudah menelusuri setiap environment yang diketahuinya dan tidak ada variabel dengan nama itu. Tiga penyebab mencakup hampir semua kasus:

  • Salah ketik, termasuk huruf besar dan kecil. R membedakan huruf besar dan kecil: Total, total, dan TOTAL adalah tiga nama yang berbeda, dan R tidak akan menebak mana yang kamu maksud.
  • Baris yang mendefinisikannya belum dijalankan. Kamu menulis total <- sum(x) di skrip tapi tidak pernah menjalankannya di sesi ini. Ini sering terjadi setelah R dimulai ulang: file skrip masih menampilkan barisnya, tapi sesinya belum pernah melihatnya. Jalankan skripnya dari atas.
  • Environment yang salah. Variabel yang dibuat di dalam fungsi hidup dan mati di dalam pemanggilan itu. Memakainya di luar fungsi sama dengan meminta sesuatu yang sudah tidak ada; kembalikan nilainya sebagai gantinya.

Error: could not find function "read_excel": gagasannya sama, tapi untuk nama fungsi. Sembilan dari sepuluh kali, fungsinya ada di package yang sudah kamu pasang tapi belum dimuat di sesi ini:

library(readxl)          # the fix: loading is per-session, installing is per-machine
df <- read_excel("data.xlsx")

Kalau library(readxl) sendiri error, berarti package-nya belum terpasang: jalankan install.packages("readxl") dulu. Dan kalau fungsinya bagian dari base R, kamu salah mengetiknya (lenght() adalah ritual wajib semua orang).

Error sintaks: unexpected symbol

Error: unexpected symbol in "..." (dan sepupunya unexpected ')', unexpected string constant) berarti R bahkan tidak bisa mengurai kodenya. Pesannya menunjuk ke tempat R menyadari masalahnya, yang sering kali sudah melewati tempat kesalahan sebenarnya. Tersangka yang biasa:

mean(x na.rm = TRUE)        # missing comma - should be mean(x, na.rm = TRUE)

name <- "Ada                # unclosed quote - swallows the following lines
total <- sum(c(1, 2, 3)     # unclosed paren - the error fires lines later

Saat baris yang ditandai terlihat tidak bersalah, kesalahannya hampir selalu berada di atasnya: tanda kutip, kurung, atau kurung kurawal yang tidak ditutup lebih awal di file. Editor kode yang menyorot pasangan yang cocok bisa menemukannya dalam hitungan detik.

Error tipe dan indeks, diterjemahkan

non-numeric argument to binary operator: kamu melakukan perhitungan pada sesuatu yang bukan angka, biasanya angka yang datang sebagai teks (impor adalah sumber klasiknya: kolom dengan satu kata nyasar akan masuk sebagai character, seperti dibahas di tipe data). Versi yang rusak:

x <- "10"
x + 5
# Error in x + 5 : non-numeric argument to binary operator

Dan perbaikannya, konversi dulu, baru hitung:

subscript out of bounds: kamu meminta posisi n dengan [[ ]] pada sesuatu yang elemennya kurang dari n:

scores <- list(ada = 92, grace = 88)
scores[[3]]
# Error in scores[[3]] : subscript out of bounds

Periksa length() sebelum mengakses indeks, atau lebih baik lagi, minta berdasarkan nama (scores[["grace"]]) supaya perubahan urutan tidak bisa merusak kodemu. Perhatikan ketidaksimetrisannya: kurung siku tunggal lebih pemaaf. [ ] di luar jangkauan pada vector diam-diam mengembalikan NA alih-alih error, yang menukar bug yang berisik dengan bug yang diam.

$ operator is invalid for atomic vectors: $ milik list dan data frame. Pada vector bernama, pakai kurung siku:

([[ ]] memberikan nilainya saja; [ ] tetap menyertakan namanya.) Error ini sering berarti ada sesuatu di langkah sebelumnya yang mengembalikan vector padahal kamu mengharapkan data frame. Periksa asumsi itu, jangan sekadar mengganti operatornya.

argument is of length zero: sebuah if () menerima kondisi yang isinya kosong, hampir selalu NULL yang menyusup dari elemen list yang hilang atau dari fungsi yang tidak mengembalikan apa-apa:

threshold <- NULL
if (threshold > 5) print("big")
# Error in if (threshold > 5) print("big") : argument is of length zero

Lindungi pemeriksaannya, dan perhatikan bahwa && berhenti mengevaluasi begitu jawabannya sudah diketahui, sehingga perbandingannya tidak pernah dijalankan pada NULL:

(Error yang mirip, missing value where TRUE/FALSE needed, adalah kegagalan yang sama dengan NA sebagai ganti NULL; pelindungnya di sana adalah is.na(), dibahas di nilai yang hilang.)

replacement has length zero: versi penugasan dari penyakit yang sama. x[2] <- numeric(0) mencoba mengisi satu slot dengan nol nilai. Apa pun yang menghasilkan sisi kanan ternyata kosong; debug bagian itu, bukan penugasannya.

Warning bukan error, dan justru itulah bahayanya

Error menghentikan eksekusi; warning tidak. R menyelesaikan perhitungan, memberimu hasil, lalu menyebutkan keberatannya sesudahnya. Hasil itu kadang baik-baik saja dan kadang diam-diam salah:

Kedua baris selesai dijalankan. Yang pertama mendaur ulang vector yang lebih pendek dan memberi warning longer object length is not a multiple of shorter object length, padahal mendaur ulang vector sepanjang 2 terhadap vector sepanjang 3 hampir tidak pernah dimaksudkan siapa pun. Yang kedua memberi warning NAs introduced by coercion dan menghasilkan vector yang berlubang, yang akan membuat setiap mean() berikutnya mengembalikan NA. Anggap kedua warning itu sebagai bug yang harus diselidiki, bukan derau yang dilewati begitu saja. Di skrip, kamu bisa menegakkan sikap itu dengan options(warn = 2), yang menaikkan setiap warning menjadi error supaya tidak ada yang lolos.

Menangani kegagalan dengan tryCatch()

Kadang error memang sudah diduga (satu file rusak di folder berisi ratusan file, satu baris yang buruk) dan kamu ingin menanganinya lalu lanjut, bukan berhenti. tryCatch() membungkus ekspresi yang berisiko dengan handler:

Cara kerjanya: kalau blok utama berhasil, nilainya menjadi hasil. Kalau error, handler error = dijalankan sebagai gantinya dan nilai yang ia kembalikan (di sini NA) menjadi hasil, sehingga skrip tetap berjalan. conditionMessage(e) mengambil kembali pesan aslinya untuk dicatat. finally = dijalankan dalam setiap kasus, berhasil maupun gagal, dan di situlah tempat pembersihan seperti menutup koneksi; kamu bisa melihatnya tercetak sebelum setiap hasil di atas.

Ada juga handler warning =: tryCatch(as.numeric(x), warning = function(w) NA) menangkap warning koersi dari bagian sebelumnya alih-alih membiarkannya lewat. Satu peringatan: handler yang mengembalikan nilai cadangan tanpa mencatat apa pun adalah cara menyembunyikan kegagalan, bukan menanganinya. Selalu catat conditionMessage(); dirimu di masa depan membutuhkannya.

Menemukan letak kegagalan: traceback(), browser(), dan print yang jujur

Saat error berasal dari dalam pemanggilan fungsi yang bersarang, pesannya saja tidak mengatakan rangkaian pemanggilan mana yang membawamu ke sana. Jalankan traceback() tepat setelah error:

f <- function(x) g(x)
g <- function(x) stop("boom")

f(1)
# Error in g(x) : boom
traceback()
# 2: g(x)
# 1: f(1)

Fungsi ini mencetak call stack pada saat kegagalan terjadi: pemanggilanmu di satu ujung, pemanggilan yang gagal di ujung lainnya. Ini harus jadi hal berikutnya yang kamu jalankan; stack-nya dibuang begitu error lain terjadi.

Untuk melihat secara langsung, browser() menghentikan eksekusi sementara di mana pun kamu menaruhnya dan membawamu ke prompt interaktif di dalam fungsi: periksa variabel, melangkah dengan n, lanjutkan dengan c, keluar dengan Q. debug(f) melakukan hal yang sama tanpa mengubah kode: fungsi ini menandai f sehingga pemanggilan berikutnya terbuka di browser (batalkan dengan undebug(f)).

Lalu ada teknik yang tidak pernah dipajang di slide konferensi tapi dipakai semua orang: mencetak. Taburkan print() atau cat() di titik-titik pemeriksaan, jalankan, dan lihat di mana kenyataan mulai tidak sesuai dengan harapanmu. Ini sah, cepat, dan di skrip sering kali menjadi alat yang paling praktis. Teman terbaiknya adalah str(), yang menjawab pertanyaan di balik mungkin separuh dari semua error R: "objek ini sebenarnya apa?":

Satu tampilan ringkas: ini sebuah list, dua elemen, satu integer vector, satu data frame dengan kolom dan tipe ini. Saat $ gagal atau perhitungan berperilaku aneh, jalankan str() pada objeknya sebelum berteori; jawabannya biasanya ada di sana ("...oh, ternyata ini list sepanjang 1 yang berisi data frame-ku").

Yang kamu bawa pulang

  • Baca pesannya: bagian setelah Error in mengatakan di mana, bagian setelah titik dua mengatakan mengapa. Perbaiki error yang pertama, bukan yang paling berisik.
  • object not found = salah ketik, kode yang belum dijalankan, atau variabel yang hanya ada di dalam fungsi. could not find function = pemanggilan library() yang terlewat, hampir selalu.
  • unexpected symbol berarti tata bahasa yang tidak bisa diurai, dan kesalahan sebenarnya sering kali adalah tanda kutip atau kurung yang tidak ditutup sebelum tempat yang ditandai.
  • Error klasik tipe dan indeks (non-numeric argument, subscript out of bounds, $ on atomic vectors, argument is of length zero) masing-masing menunjuk ke asumsi yang salah tentang sebuah objek; str() memeriksa asumsi itu dalam satu pemanggilan.
  • Warning tidak menghentikan eksekusi, dan justru karena itulah warning perlu diperhatikan: hasilnya mungkin diam-diam salah.
  • tryCatch(error =, warning =, finally =) menangani kegagalan yang sudah diduga tanpa berhenti (selalu catat conditionMessage()); traceback() tepat setelah error menampilkan rangkaian pemanggilan; browser()/debug() berhenti sementara di dalamnya; debug dengan print() adalah kerja yang jujur.

Berikutnya: banyak "error" yang sebenarnya bukan error berasal dari satu nilai tiga karakter, yaitu NA, dan cara nilai yang hilang mengalir ke semua yang dihitung R.

Pertanyaan yang sering diajukan

Apa arti "object 'x' not found" di R?

R mencari variabel bernama x dan nama itu tidak ada di environment mana pun yang ditelusurinya. Penyebabnya, diurutkan dari yang paling mungkin: salah ketik pada nama (R membedakan huruf besar dan kecil: Total bukan total), baris yang membuat x belum dijalankan di sesi ini, atau x dibuat di dalam fungsi dan kamu mencoba memakainya di luar.

Apa arti "could not find function" di R?

Fungsinya ada di sebuah package yang belum kamu muat di sesi ini. Memasang package cukup sekali per komputer; library() dijalankan sekali per sesi, dan lupa memanggil library() adalah penyebab yang biasa. Kalau library() sendiri gagal, package-nya belum terpasang. Salah ketik pada nama fungsi menghasilkan error yang sama.

Bagaimana cara menangani error di R dengan tryCatch?

Bungkus ekspresi yang berisiko: tryCatch(expr, error = function(e) fallback, warning = function(w) fallback, finally = cleanup). Kalau expr gagal, handler yang cocok dijalankan alih-alih skripnya berhenti, dan apa pun yang dikembalikan handler menjadi hasilnya. conditionMessage(e) di dalam handler memberimu pesan aslinya untuk dicatat.

Apa fungsi traceback() di R?

Kalau dijalankan tepat setelah error, traceback() mencetak rangkaian pemanggilan fungsi yang aktif saat error terjadi: pemanggilanmu di satu ujung, pemanggilan yang gagal di ujung lainnya. Fungsi ini tidak memperbaiki apa pun; ia memberi tahu di mana harus mencari, dan itu sudah sebagian besar perjuangan saat error berasal dari dalam fungsi yang bersarang.

Ilustrasi bahasa pemrograman di Coddy

Belajar coding dengan Coddy

Mulai