8 minute read

Di suatu Senin, masuk satu chat di laptop dari salah seorang rekan kerja yang berasal dari divisi e-commerce. Sudah setahun ini, beliau dan timnya selalu menggunakan R untuk melakukan data carpentry (data manipulation - data preparation) memanfaatkan prinsip tidy (%>%) dari library(dplyr).

Mas, saya ke tempatmu ya. Ada yang mau saya tanyakan tentang skrip R. Ini mau run dulu sebentar, nanti kalau sudah selesai, saya ke sana.

Begitu isi chat-nya pada pukul jam 1 siang tepat.

Setengah jam kemudian beliau datang ke tempat kerja saya dan mulai berdiskusi.


Ternyata, rekan kerja saya tersebut sedang mengolah banyak dataset berukuran jumbo (jutaan baris) dengan tidy. Butuh waktu sekitar 30 menit untuk mengeksekusi skripnya hingga selesai.

Lama banget nih…

Begitu pikir saya.

Salah satu dugaan saya adalah karena rekan kerja saya menggunakan Windows OS di laptopnya sehingga R-nya seolah-olah bekerja dengan tangan terikat.

Sampai akhirnya saya coba lihat dengan detail proses komputasi yang terjadi. Saya dapatkan proses running tersebut memakan RAM yang sangat besar.

Wajar saja butuh waktu lama… Tapi apa ada alternatif lain yang bisa lebih cepat dan lebih hemat RAM?

Pertanyaan dalam kepala ini cukup mengganggu dan membuat saya gusar. Qodarullah, tak lama setelah berdiskusi dengan rekan kerja saya, grup telegram R-Indo sedang membahas tema yang serupa.


Prinsip Ngoding Data Carpentry di R

Setidaknya ada dua mazhab besar dalam membuat skrip data carpentry di R, yakni:

  1. tidy, yakni memanfaatkan pipe (%>%). Saya pribadi selalu mengajak rekan-rekan di kantor untuk menggunakan prinsip tidy agar lebih mudah untuk saling cross check.
  2. data.table, yakni dengan formula bertingkat.

Usut punya usut, ternyata data.table memberikan kemampuan komputasi yang lebih cepat. Selain itu, muncul satu framework baru bernama polars yang memiliki kemampuan komputasi (secara teori) lebih cepat lagi.

Lantas bagaimana? Apaka saya harus mengubah cara ngoding yang sudah terbiasa selama ini?

Tentu tidak!

Terima kasih kepada para maestro data scientist di luar sana yang telah mengembangkan library(dtplyr) dan library(tidypolars) yang berfungsi untuk menggunakan framework data.table dan polars dengan gaya ngoding ala tidy.

  • dtplyr bisa dilihat di sini.
  • tidypolars bisa dilihat di sini.

Pada bagian ini, saya akan coba melakukan tiga simulasi untuk membandingkan kemampuan komputasi mengolah data 10 juta baris dengan:

  1. Skrip dplyr,
  2. Skrip dtplyr, dan
  3. Skrip tidypolars.

Berikut adalah data dummy yang saya gunakan:

# membuat data frame
n_generate = 10^7
df_input = data.frame(
    grup  = sample(LETTERS[1:6], 
                   n_generate, 
                   replace = TRUE),
    nilai = rnorm(n_generate)
  )

Berikut adalah skrip versi dplyr:

# definisikan proses dengan dplyr
proses_dplyr <- function(data) {
  data %>%
    group_by(grup) %>%
    summarize(
      rata_rata = mean(nilai)
    ) %>% 
    ungroup()
}

Berikut adalah skrip versi dtplyr:

# definisikan proses dengan dtplyr
proses_dtplyr <- function(data) {
  data |>
    dtplyr::lazy_dt() |> 
    group_by(grup) |>
    summarise(
      rata_rata = mean(nilai)
    ) %>% 
    ungroup() 
}

Berikut adalah skrip versi tidypolars:

# definisikan proses dengan tidypolars
proses_tidypolars <- function(data) {
  data |>
    as_polars_df() |> 
    group_by(grup) |>
    summarise(
      rata_rata = mean(nilai)
    ) %>% 
    ungroup() 
}

Berikut adalah simulasi yang saya lakukan:

bench::mark(
  proses_dplyr(df_input),
  proses_tidypolars(df_input),
  proses_dtplyr(df_input),
  iterations = 5,
  check = F,
)

Hasilnya adalah sebagai berikut:

  • Function yang menggunakan prinsip dtplyr memiliki total runtime selama 264.73 milisec dan memory allocation sebesar 153 MB. Dari lima kali percobaan, waktu median untuk sekali runtime processing adalah sebesar 46.2 milisec.
  • Function yang menggunakan prinsip dplyr memiliki total runtime selama 1.42 sec dan memory allocation sebesar 239 MB. Dari lima kali percobaan, waktu median untuk sekali runtime processing adalah sebesar 455.7 milisec.
  • Function yang menggunakan prinsip tidypolars memiliki total runtime selama 3.74 sec dan memory allocation sebesar 116 KB. Dari lima kali percobaan, waktu median untuk sekali runtime processing adalah sebesar 738.7 milisec.

Kesimpulan

Prinsip dtplyr memberikan waktu tercepat dengan konsumsi memory yang lebih kecil dibandingkan dplyr sedangkan tidypolars walau memiliki waktu yang paling lama tapi memiliki konsumsi memory yang paling irit.


Action Plan

Dari hasil di atas, setidaknya ada beberapa action plan yang hendak saya lakukan ke tim di kantor:

  1. Untuk pengolahan data yang kecil: tetap menggunakan dplyr dan tidak diwajibkan untuk mengubah ke dtplyr atau tidypolars.
  2. Untuk pengolahan data yang jumbo, harus memetakan cases kapan menggunakan:
    • Komputasi yang lebih irit memory dengan tidypolars.
    • Komputasi yang lebih cepat dengan konsumsi memory yang masih bisa diterima (dtplyr).

if you find this article helpful, support this blog by clicking the ads.