Topik ini membahas pipe, yaitu operator |> yang meneruskan hasil sebuah ekspresi menjadi argumen pertama pemanggilan fungsi berikutnya. Pembahasan dimulai dari masalah yang mendorong kemunculannya, yaitu ekspresi bersarang yang sulit dibaca, kemudian dilanjutkan dengan aturan penulisan rantai yang rapi, pemakaian pipe bersama verba dplyr (fungsi transformasi data seperti filter() dan arrange()), serta batasan pipe beserta cara mengatasinya. Sebagai bahan kerja, satu tibble kecil berisi nilai delapan siswa didefinisikan dan dipakai sepanjang modul ini. Setelah membacanya, transformasi data bertingkat dapat ditulis sebagai rangkaian langkah yang urutan bacanya sama dengan urutan eksekusinya.
library(tidyverse)
nilai <- tibble::tibble(
nama = c("Ali", "Budi", "Citra", "Dewi", "Eka", "Fajar", "Gita", "Hana"),
kelas = c("7A", "7B", "7A", "7B", "7A", "7B", "7A", "7B"),
nilai = c(88, 74, 92, 65, 81, 79, 95, 70),
kehadiran = c(0.95, 0.88, 1.00, 0.75, 0.92, 0.85, 0.98, 0.80)
)
nilai── 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 errors
# A tibble: 8 × 4
nama kelas nilai kehadiran
<chr> <chr> <dbl> <dbl>
1 Ali 7A 88 0.95
2 Budi 7B 74 0.88
3 Citra 7A 92 1
4 Dewi 7B 65 0.75
5 Eka 7A 81 0.92
6 Fajar 7B 79 0.85
7 Gita 7A 95 0.98
8 Hana 7B 70 0.8 Masalah ekspresi bersarang#
Satu perhitungan sering memerlukan beberapa fungsi yang diterapkan berurutan pada satu nilai. Contoh berikut menghitung akar kuadrat dari rata-rata kolom nilai, dengan pembulatan satu angka desimal pada tahap terakhirnya.
round(sqrt(mean(nilai$nilai)), 1)[1] 9Cara membaca ekspresi di atas berlawanan dengan arah eksekusinya. Fungsi yang dijalankan lebih dahulu adalah mean() yang berada paling dalam, dilanjutkan sqrt(), dan terakhir round(). Semakin banyak langkahnya, semakin sulit memastikan fungsi mana yang menerima hasil fungsi mana, apalagi ketika setiap pemanggilan memuat argumen tambahan. Kesalahan penempatan kurung juga mudah terjadi karena seluruh argumen saling berimpit dalam satu ekspresi.
Alternatifnya adalah menyimpan hasil antara ke dalam variabel, lalu melanjutkan perhitungan pada variabel berikutnya.
rata <- mean(nilai$nilai)
akar <- sqrt(rata)
round(akar, 1)[1] 9Urutan membaca kini searah dengan urutan eksekusi. Kerugiannya, dua variabel antara hanya dipakai satu kali, tetapi tetap menempati nama dan membebani lingkungan kerja. Pipe menawarkan jalan tengah, yaitu alur baca yang searah tanpa variabel antara.
Pipe bawaan |>#
Pipe bawaan R ditulis sebagai operator |> dan tersedia sejak R 4.1. Operator ini mengambil nilai di sisi kiri, lalu menyisipkannya sebagai argumen pertama pemanggilan fungsi di sisi kanan. Ekspresi x |> f(y) dihitung sebagai f(x, y), sehingga rantai panjang dapat dibaca dari kiri ke kanan sesuai urutan eksekusinya. Ekspresi bersarang pada awal topik dapat ditulis ulang menjadi berikut.
nilai$nilai |> mean() |> sqrt() |> round(digits = 1)[1] 9Setiap tahap menerima hasil tahap sebelumnya. mean() menerima kolom nilai, sqrt() menerima rata-rata yang dihasilkan mean(), dan round() menerima akar kuadrat tersebut. Argumen tambahan seperti digits tetap dituliskan sebagaimana biasa di dalam pemanggilan fungsinya, sedangkan posisi argumen pertama diisi otomatis oleh pipe.
Menyusun rantai yang mudah dibaca#
Rantai pipe yang panjang ditulis dengan satu langkah per baris, dan tanda |> diletakkan di akhir baris. Baris-baris lanjutannya diberi indentasi agar tahapannya tampak sejajar. R melanjutkan ekspresi ke baris berikutnya selama ekspresi itu belum lengkap, sehingga pemenggalan baris tidak mengubah makna kode.
nilai$nilai |>
mean() |> # rata-rata kelas
sqrt() |> # akar kuadrat
round(digits = 1) # pembulatan satu desimal[1] 9Komentar singkat pada setiap baris membantu menyatakan maksud langkahnya. Prinsip yang dijaga adalah satu baris memuat satu transformasi, sehingga penambahan, pembuangan, atau penyusunan ulang langkah cukup dilakukan pada satu baris. Rantai yang dipadatkan dalam satu baris tetap sah, tetapi lebih sulit diperiksa ketika salah satu tahapnya perlu disunting.
Pipe dengan verba dplyr#
Fungsi-fungsi dplyr disebut verba (verb) karena masing-masing menyatakan satu aksi pada data, seperti mengambil baris tertentu, memilih kolom, atau mengurutkannya. Semua verba menerima data frame sebagai argumen pertamanya dan mengembalikan data frame baru, sehingga hasil satu verba langsung dapat diteruskan ke verba berikutnya melalui pipe. Rantai berikut mengambil baris siswa kelas 7A, memilih tiga kolomnya, lalu mengurutkan baris menurut nilai dari yang tertinggi.
nilai |>
filter(kelas == "7A") |>
select(nama, kelas, nilai) |>
arrange(desc(nilai))# A tibble: 4 × 3
nama kelas nilai
<chr> <chr> <dbl>
1 Gita 7A 95
2 Citra 7A 92
3 Ali 7A 88
4 Eka 7A 81Verba filter() mengambil baris yang kondisinya terpenuhi, select() memilih kolom yang disebutkan, dan arrange(desc(nilai)) mengurutkan baris menurut kolom nilai dari yang terbesar. Hasil akhir rantai adalah tabel baru, sedangkan nilai sebagai data asalnya tidak berubah sama sekali. Rantai semacam ini adalah bentuk pemakaian dplyr yang paling umum, dan setiap verba di dalamnya masing-masing memiliki aturan yang lebih rinci.
Batasan pipe dan placeholder _#
Pipe selalu menyisipkan nilai kiri sebagai argumen pertama pemanggilan di kanannya. Batasan ini tampak ketika posisi yang tepat bukan argumen pertama. Fungsi seq(from, to) menghasilkan deret dari from sampai to, sedangkan nilai yang diteruskan pipe seharusnya menempati argumen to, bukan from.
10 |> seq(1) [1] 10 9 8 7 6 5 4 3 2 1Pemanggilan itu tidak menghasilkan error, melainkan deret yang urutannya terbalik, karena seq(10, 1) sah sebagai deret menurun. Contoh semacam ini menunjukkan pentingnya memeriksa posisi argumen setiap kali pipe dipakai pada fungsi yang baru. Sejak R 4.2, tersedia placeholder _ yang menyatakan posisi nilai kiri secara eksplisit sebagai argumen bernama.
10 |> seq(1, to = _) [1] 1 2 3 4 5 6 7 8 9 10Placeholder _ pada argumen to menandai tempat nilai kiri disisipkan, sehingga ekspresi di atas dihitung sebagai seq(1, 10). Tanpa placeholder, urutan pemanggilan hanya dapat ditegakkan dengan menuliskan pemanggilan fungsi secara biasa, yaitu seq(1, 10) tanpa pipe sama sekali.
Selain pipe bawaan, paket magrittr yang menjadi dependensi tidyverse menyediakan pipe %>%, dan dplyr mengekspor ulang operator tersebut sehingga dapat dipakai begitu dplyr dimuat. Pipe %>% lebih tua daripada |> karena mendahuluinya bertahun-tahun, sehingga masih banyak dijumpai pada kode dan dokumentasi yang ditulis sebelum R 4.1. Keduanya serupa untuk pemakaian umum, dengan perbedaan yang mudah dijumpai pada placeholder dan bentuk sisi kanannya. Placeholder %>% adalah tanda titik ., sedangkan sisi kanan %>% juga menerima nama fungsi tanpa kurung, sebagaimana 5 %>% sin yang sah. Untuk kode baru, pipe bawaan |> menjadi pilihan yang disarankan karena tidak bergantung pada paket tambahan. Perbedaan keduanya terlihat pada pemanggilan berikut.
5 |> sinError: The pipe operator requires a function call as RHS (<input>:1:6)Pesan The pipe operator requires a function call as RHS menyatakan bahwa sisi kanan |> wajib berupa pemanggilan fungsi, sehingga sin harus ditulis dengan kurung menjadi sin(). Aturan yang lebih ketat ini membuat sisi kanan pipe bawaan selalu diperlakukan dengan cara yang sama.
Ringkasan#
- Pipe bawaan
|>menyisipkan nilai sisi kiri sebagai argumen pertama pemanggilan di sisi kanan, sehinggax |> f(y)dihitung sebagaif(x, y). - Rantai panjang ditulis satu langkah per baris dengan
|>di akhir baris, sehingga urutan membaca sama dengan urutan eksekusi. - Verba dplyr menerima data frame sebagai argumen pertama dan mengembalikan data frame baru, sehingga cocok disambung menjadi rantai pipe.
- Apabila posisi yang tepat bukan argumen pertama, gunakan placeholder
_pada argumen bernama sejak R 4.2, karena pemindahan yang keliru bisa tetap menghasilkan keluaran yang tampak sah. - Pipe
%>%dari magrittr masih banyak dijumpai pada kode lama dan memakai.sebagai placeholder.
Referensi#
- dplyr: A Grammar of Data Manipulation — tidyverse — dokumentasi resmi dplyr yang menyusun seluruh contohnya sebagai rantai pipe antarverba.
- R for Data Science, edisi ke-2 — Wickham, Çetinkaya-Rundel, Grolemund — buku sumber tidyverse yang menjelaskan pipe dan gaya penulisan rantainya pada bab alur kerja.