Data analisis hampir selalu tiba dalam bentuk berkas teks seperti CSV. Paket readr dari keluarga tidyverse membaca berkas teks persegi (rectangular text) seperti CSV dan TSV ke dalam tibble, yaitu data frame versi tidyverse yang penampilannya lebih ringkas. Topik ini membahas read_csv beserta pembandingnya read.csv bawaan R, penulisan berkas dengan write_csv, perilaku penentuan tipe kolom, penanganan nilai hilang, dan read_delim untuk pemisah selain koma. Setelah topik ini dipelajari, alur menulis dan membaca berkas CSV dapat dilakukan sepenuhnya dari dalam R.
Menulis dan membaca berkas CSV#
Seluruh fungsi readr menjadi tersedia begitu tidyverse dimuat. Agar contoh dapat dijalankan ulang, berkas datanya dibuat dari R sendiri. Fungsi tribble() dari tibble membangun tibble kecil secara baris per baris, kemudian write_csv() menuliskannya sebagai berkas CSV. Pembacaan balik dilakukan dengan read_csv().
library(tidyverse)── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
✔ dplyr 1.2.1 ✔ readr 2.2.0
✔ forcats 1.0.1 ✔ stringr 1.6.0
✔ ggplot2 4.0.3 ✔ tibble 3.3.1
✔ lubridate 1.9.5 ✔ tidyr 1.3.2
✔ purrr 1.2.2
── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
✖ dplyr::filter() masks stats::filter()
✖ dplyr::lag() masks stats::lag()
ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errorsnilai_siswa <- tribble(
~nama, ~kelas, ~nilai_1, ~nilai_2,
"Ali", "A", 82, 78,
"Budi", "A", 75, 81,
"Citra", "B", 88, 90,
"Dewi", "B", 79, 85
)
write_csv(nilai_siswa, "nilai-siswa.csv")
read_csv("nilai-siswa.csv")Rows: 4 Columns: 4
── Column specification ────────────────────────────────────────────────────────
Delimiter: ","
chr (2): nama, kelas
dbl (2): nilai_1, nilai_2
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
# A tibble: 4 × 4
nama kelas nilai_1 nilai_2
<chr> <chr> <dbl> <dbl>
1 Ali A 82 78
2 Budi A 75 81
3 Citra B 88 90
4 Dewi B 79 85Pesan yang muncul sebelum tibble bukan error, melainkan laporan spesifikasi kolom hasil tebakan readr. Berkasnya berisi empat kolom, dua di antaranya character dan dua lainnya double. Pesan ini muncul pada setiap pemanggilan read_csv() secara default dan dapat dibungkam dengan argumen show_col_types = FALSE, seperti yang dipakai pada blok-blok berikutnya. Keberadaan pesan semacam ini merupakan salah satu pembeda utama readr dari read.csv bawaan, yang bekerja tanpa laporan apa pun.
read.csv bawaan versus read_csv#
R bawaan menyediakan read.csv() dari paket utils. Fungsi ini sudah lama digunakan dan masih dijumpai di banyak skrip, tetapi readr menawarkan beberapa perbedaan praktis. Tabel berikut merangkum perbedaan yang paling terasa.
| Aspek | read.csv | read_csv |
|---|---|---|
| Hasil | data.frame murni | tibble |
| Kecepatan | seluruh penguraian di R, lebih lambat pada berkas besar | penguraian ditulis dalam C, jauh lebih cepat pada berkas besar |
| Nama kolom | spasi diubah menjadi titik | dipertahankan apa adanya |
| Laporan parsing | tidak ada | spesifikasi kolom dan warning masalah ditampilkan |
Kelas kembalian keduanya dapat dibandingkan langsung pada berkas yang sama.
bawaan <- read.csv("nilai-siswa.csv")
readr_hasil <- read_csv("nilai-siswa.csv", show_col_types = FALSE)
class(bawaan)
class(readr_hasil)[1] "data.frame"
[1] "spec_tbl_df" "tbl_df" "tbl" "data.frame" Hasil read.csv() adalah data.frame murni, sedangkan read_csv() mengembalikan tibble dengan kelas spec_tbl_df. Karena tibble tetap merupakan data.frame, seluruh fungsi bawaan tetap bekerja padanya. Keuntungan utama tibble ada pada tampilan cetak yang tidak membanjiri konsol dan pada pengindeksan yang selalu eksplisit.
Perilaku penentuan tipe kolom#
readr melakukan parsing, yaitu penguraian teks mentah menjadi kolom dan tipe data. Untuk setiap kolom, readr menebak tipenya dari sampel baris berkas, lalu melaporkan hasil tebakannya dalam pesan spesifikasi kolom. Banyaknya baris yang dipakai menebak diatur lewat argumen guess_max, dan guess_max = Inf mempertimbangkan seluruh baris. Apabila data yang dibaca penting, tipe tiap kolom sebaiknya ditetapkan secara eksplisit dengan argumen col_types.
Satu nilai yang mengubah seluruh kolom#
Kesalahan kecil di satu baris dapat mengubah tipe seluruh kolom. Berkas log-suhu.csv berikut berisi 1002 baris pengukuran suhu dengan satu nilai teks rusak di baris terakhir.
suhu_tabel <- tibble(
waktu = 1:1002,
suhu = c(as.character(rep(21.4, 1001)), "rusak")
)
write_csv(suhu_tabel, "log-suhu.csv")
log_suhu <- read_csv("log-suhu.csv")
log_suhuRows: 1002 Columns: 2
── Column specification ────────────────────────────────────────────────────────
Delimiter: ","
chr (1): suhu
dbl (1): waktu
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
# A tibble: 1,002 × 2
waktu suhu
<dbl> <chr>
1 1 21.4
2 2 21.4
3 3 21.4
4 4 21.4
5 5 21.4
6 6 21.4
7 7 21.4
8 8 21.4
9 9 21.4
10 10 21.4
# ℹ 992 more rowsTidak ada warning yang muncul, tetapi kolom suhu yang seharusnya angka kini bertipe character, terlihat dari baris chr (1): suhu pada pesan spesifikasi dan label
Memaksa tipe dan membaca masalah parsing#
Tipe kolom dapat dipaksakan dengan col_types. Apabila kolom suhu dipaksa menjadi double, nilai rusak tidak dapat diurai, dijadikan NA, dan readr menampilkan warning yang menjelaskan masalahnya.
log_suhu_angka <- read_csv(
"log-suhu.csv",
col_types = cols(waktu = col_integer(), suhu = col_double())
)
sum(is.na(log_suhu_angka$suhu))Warning: One or more parsing issues, call `problems()` on your data frame for details,
e.g.:
dat <- vroom(...)
problems(dat)
[1] 1Fungsi problems() dipanggil pada objek hasil membaca dan mengembalikan rincian kejadian tersebut, yaitu baris ke berapa, kolom ke berapa, tipe yang diharapkan, dan nilai aslinya. Kolom file dari tibble problems() berisi jalur berkas lengkap, sehingga hanya empat kolom pertamanya yang ditampilkan di sini.
select(problems(log_suhu_angka), -file)# A tibble: 1 × 4
row col expected actual
<int> <int> <chr> <chr>
1 1003 2 a double rusak Alternatif lain adalah membaca kolom itu sebagai character terlebih dahulu, lalu penanganannya dilakukan di dalam R, misalnya menandai baris yang rusak. Dengan tipe character tidak ada nilai yang gagal diurai. Fungsi spec() menampilkan spesifikasi kolom yang sedang berlaku pada hasil pembacaan.
log_suhu_teks <- read_csv(
"log-suhu.csv",
col_types = cols(waktu = col_integer(), suhu = col_character())
)
spec(log_suhu_teks)cols(
waktu = col_integer(),
suhu = col_character()
)Tanggal dan pemisah#
Tipe tanggal dikenali otomatis apabila ditulis dalam format ISO, yaitu tahun-bulan-tanggal seperti 2026-01-05. Format lain seperti 05/01/2026 tidak dikenali dan kolomnya dibiarkan menjadi character, sehingga formatnya harus dinyatakan lewat col_date().
penjualan <- tibble(
tanggal = c("05/01/2026", "06/01/2026", "07/01/2026"),
omzet = c(120, 135, 98)
)
write_csv(penjualan, "penjualan.csv")
penjualan_r <- read_csv("penjualan.csv", show_col_types = FALSE)
class(penjualan_r$tanggal)
penjualan_iso <- read_csv(
"penjualan.csv",
col_types = cols(tanggal = col_date(format = "%d/%m/%Y"), omzet = col_double())
)
class(penjualan_iso$tanggal)[1] "character"
[1] "Date"Tanpa argumen col_types, kolom tanggal terbaca sebagai character. Setelah col_date() diberi format %d/%m/%Y, kolom yang sama terbaca sebagai Date dan dapat diolah lebih lanjut. Urutan format mengikuti konvensi strptime bawaan R, yaitu %d untuk tanggal, %m untuk bulan, dan %Y untuk tahun empat digit.
Mengatur nilai hilang dengan na#
Teks yang menandai kekosongan diterjemahkan menjadi NA oleh readr. Secara default, string kosong dan teks NA dianggap nilai hilang. Sentinel lain, yaitu teks penanda kekosongan seperti tanda hubung atau kata tertentu, harus didaftarkan lewat argumen na agar tidak terbaca sebagai teks biasa.
presensi <- tibble(
nama = c("Ali", "Budi", "Citra", "Dewi", "Eka"),
status = c("hadir", "NA", "hadir", "-", "izin")
)
write_csv(presensi, "presensi.csv")
read_csv("presensi.csv", show_col_types = FALSE)
read_csv("presensi.csv", na = c("NA", "-", ""), show_col_types = FALSE)# A tibble: 5 × 2
nama status
<chr> <chr>
1 Ali hadir
2 Budi <NA>
3 Citra hadir
4 Dewi -
5 Eka izin
# A tibble: 5 × 2
nama status
<chr> <chr>
1 Ali hadir
2 Budi <NA>
3 Citra hadir
4 Dewi <NA>
5 Eka izin Pada pembacaan pertama, tanda hubung masih berupa teks biasa, sedangkan pembacaan kedua menghasilkan NA sungguhan pada baris yang sama, ditandai tampilan
Pemisah lain dengan read_delim dan read_csv2#
Tidak semua berkas teks berpemisah koma. read_delim() menerima pemisah apa pun lewat argumen delim, sedangkan read_csv2() khusus menangani konvensi Eropa, yaitu titik koma sebagai pemisah kolom dan koma sebagai pemisah desimal.
write_delim(nilai_siswa, "nilai-titik-koma.csv", delim = ";")
read_delim("nilai-titik-koma.csv", delim = ";", show_col_types = FALSE)
omzet_csv <- "bulan;omzet\nJanuari;1.250,50\nFebruari;990,00\n"
writeLines(omzet_csv, "omzet-eropa.csv")
read_csv2("omzet-eropa.csv", show_col_types = FALSE)# A tibble: 4 × 4
nama kelas nilai_1 nilai_2
<chr> <chr> <dbl> <dbl>
1 Ali A 82 78
2 Budi A 75 81
3 Citra B 88 90
4 Dewi B 79 85
ℹ Using "','" as decimal and "'.'" as grouping mark. Use `read_delim()` for more control.
# A tibble: 2 × 2
bulan omzet
<chr> <dbl>
1 Januari 1250.
2 Februari 990 Keluaran tersebut memperlihatkan dua hal sekaligus. Berkas berpemisah titik koma terbaca identik dengan tabel asalnya, dan pesan pada read_csv2() mengonfirmasi pemetaan koma desimal serta titik penanda ribuan yang dipakainya. Nilai omzet kini berupa angka, bukan teks, sehingga langsung dapat dihitung.
Kesalahan umum#
Pola kesalahan berikut paling sering muncul saat bekerja dengan readr.
- Pesan spesifikasi kolom dianggap error. Pesan berawalan Rows dan Column specification beserta dua baris berawalan ℹ hanyalah laporan tebakan tipe, bukan tanda kegagalan. Bila mengganggu, bungkam dengan show_col_types = FALSE.
- Kolom angka berubah menjadi character tanpa disadari. Penyebabnya adalah satu nilai yang tidak dapat diurai, misalnya teks tersisip atau koma desimal. Perbaikannya dengan membaca pesan spesifikasi kolom, lalu menetapkan col_types secara eksplisit atau membersihkan sumber datanya.
- Tanggal terbaca sebagai character. Format non-ISO seperti 05/01/2026 tidak ditebak oleh readr. Tetapkan col_date(format = “%d/%m/%Y”) pada argumen col_types, atau rapikan berkas sumbernya ke format ISO terlebih dahulu.
- Nilai hilang berupa sentinel tetap menjadi teks. Tanda hubung atau kata tertentu hanyalah string biasa bagi parser. Daftarkan sentinel tersebut pada argumen na saat membaca berkas.
Ringkasan#
- read_csv() membaca CSV menjadi tibble dan melaporkan spesifikasi kolom hasil tebakannya, sedangkan write_csv() menulis tibble kembali sebagai berkas CSV.
- Satu nilai yang tidak dapat diurai dapat mengubah seluruh kolom menjadi character, sehingga tipe kolom yang penting ditetapkan lewat col_types dan masalahnya diperiksa lewat problems().
- Nilai hilang dikendalikan lewat argumen na, sedangkan read_delim() dan read_csv2() menangani pemisah titik koma serta koma desimal.
Referensi#
- readr: Read Rectangular Text Data — tidyverse — Dokumentasi resmi fungsi pembaca, penulis, dan spesifikasi tipe kolom readr.
- R for Data Science, edisi ke-2 — Wickham, Çetinkaya-Rundel, Grolemund — Bab data import membahas read_csv, col_types, dan penanganan nilai hilang.