Haruskah saya menginvestasikan upaya belajar saya untuk perselisihan data dalam R, khususnya di antara dplyr
, dtplyr
dan data.table
?
Saya menggunakan
dplyr
sebagian besar, tetapi ketika data terlalu besar untuk itu saya akan gunakandata.table
, yang jarang terjadi. Jadi sekarangdtplyr
v1.0 keluar sebagai antarmuka untukdata.table
, di permukaan sepertinya saya tidak perlu khawatir menggunakandata.table
antarmuka lagi.Jadi fitur atau aspek apa yang paling berguna
data.table
yang tidak dapat dilakukan menggunakandtplyr
saat ini, dan yang kemungkinan tidak akan pernah dilakukandtplyr
?Di wajahnya,
dplyr
dengan manfaatdata.table
membuatnya terdengar sepertidtplyr
akan menyusuldplyr
. Apakah akan ada alasan untuk menggunakandplyr
setelahdtplyr
sepenuhnya matang?
Catatan: Saya tidak bertanya tentang dplyr
vs data.table
(seperti pada data.tabel vs dplyr: dapatkah seseorang melakukan sesuatu dengan baik yang lainnya tidak dapat atau melakukan dengan buruk? ), Tetapi mengingat bahwa yang satu lebih disukai daripada yang lain untuk masalah tertentu, mengapa tidak t dtplyr
menjadi alat untuk digunakan.
sumber
dplyr
sehingga Anda tidak bisa melakukannya dengan baikdata.table
? Jika tidak, beralih kedata.table
akan lebih baik daripadadtplyr
.dtplyr
readme, 'Beberapadata.table
ekspresi tidak memilikidplyr
padanan langsung . Misalnya, tidak ada cara untuk mengekspresikan cross-atau rolling-gabung dengandplyr
. ' dan 'Untuk mencocokkandplyr
semantik,mutate
() tidak diubah pada tempatnya secara default. Ini berarti bahwa sebagian besar ekspresi yang terlibatmutate()
harus membuat salinan yang tidak perlu jika Anda menggunakandata.table
secara langsung. ' Ada sedikit cara di sekitar bagian kedua itu tetapi mengingat seberapa seringmutate
digunakan, itu adalah kerugian yang cukup besar di mata saya.Jawaban:
Saya akan mencoba memberikan panduan terbaik saya tetapi tidak mudah karena kita harus terbiasa dengan semua {data.table}, {dplyr}, {dtplyr} dan juga {base R}. Saya menggunakan {data.table} dan banyak paket {tidy-world} (kecuali {dplyr}). Cinta keduanya, meskipun saya lebih suka sintaks data.tabel untuk dplyr. Saya berharap semua paket dunia-rapi akan menggunakan {dtplyr} atau {data.table} sebagai backend kapan pun diperlukan.
Seperti halnya terjemahan lain (pikirkan dplyr-to-sparkly / SQL), ada hal-hal yang dapat atau tidak dapat diterjemahkan, setidaknya untuk saat ini. Maksud saya, mungkin suatu hari {dtplyr} dapat membuatnya diterjemahkan 100%, siapa tahu. Daftar di bawah ini tidak lengkap atau 100% benar karena saya akan mencoba yang terbaik untuk menjawab berdasarkan pengetahuan saya tentang topik / paket / masalah terkait / dll.
Yang penting, untuk jawaban-jawaban yang tidak sepenuhnya akurat, saya harap ini memberi Anda beberapa panduan tentang aspek {data.table} apa yang harus Anda perhatikan dan, bandingkan dengan {dtplyr} dan temukan jawabannya sendiri. Jangan anggap remeh jawaban ini.
Dan, saya berharap posting ini dapat digunakan sebagai salah satu sumber daya untuk semua {dplyr}, {data.table} atau {dtplyr} pengguna / pembuat untuk diskusi dan kolaborasi dan menjadikan #RStats lebih baik.
{data.table} tidak hanya digunakan untuk operasi cepat & efisien memori. Ada banyak orang, termasuk saya, lebih menyukai sintaksis elegan {data.table}. Ini juga mencakup operasi cepat lainnya seperti fungsi deret waktu seperti keluarga bergulir (yaitu
frollapply
) yang ditulis dalam C. Ia dapat digunakan dengan fungsi apa pun, termasuk tidyverse. Saya banyak menggunakan {data.table} + {purrr}!Kompleksitas operasi
Ini dapat dengan mudah diterjemahkan
{data.table} sangat cepat & hemat memori karena (hampir?) semuanya dibangun dari bawah ke atas dengan konsep kunci pembaruan-per-referensi , kunci (pikirkan SQL), dan optimalisasi tanpa henti di mana-mana dalam paket (Yaitu
fifelse
,fread/fread
urutan sortir radix diadopsi oleh basis R), sambil memastikan sintaksisnya ringkas dan konsisten, itu sebabnya saya pikir itu elegan.Dari Pengantar data.tabel , operasi manipulasi data utama seperti subset, grup, pembaruan, bergabung, dll disimpan bersama untuk
sintaksis ringkas & konsisten ...
melakukan analisis dengan lancar tanpa beban kognitif karena harus memetakan setiap operasi ...
secara otomatis mengoptimalkan operasi secara internal, dan sangat efektif, dengan mengetahui secara tepat data yang diperlukan untuk setiap operasi, yang mengarah pada kode yang sangat cepat dan efisien memori
Poin terakhir, sebagai contoh,
Mengingat bahwa, untuk menuai manfaat {data.table}, terjemahan {dtplr} harus benar dalam hal itu. Semakin kompleks operasinya, semakin sulit terjemahannya. Untuk operasi sederhana seperti di atas, tentu dapat dengan mudah diterjemahkan. Untuk yang kompleks, atau yang tidak didukung oleh {dtplyr}, Anda harus mencari tahu sendiri seperti yang disebutkan di atas, Anda harus membandingkan sintaks dan tolok ukur yang diterjemahkan dan menjadi paket terkait yang familier.
Untuk operasi yang kompleks atau operasi yang tidak didukung, saya mungkin dapat memberikan beberapa contoh di bawah ini. Sekali lagi, saya hanya mencoba yang terbaik. Bersikaplah lembut padaku.
Perbarui dengan referensi
Saya tidak akan masuk ke intro / detail tetapi di sini ada beberapa tautan
Sumber daya utama: Referensi semantik
Lebih detail: Memahami kapan tepatnya data.table adalah referensi ke (vs salinan) data.table
Pembaruan-oleh-referensi , menurut saya, fitur terpenting dari {data.table} dan itulah yang membuatnya begitu cepat & hemat memori.
dplyr::mutate
tidak mendukungnya secara default. Karena saya tidak terbiasa dengan {dtplyr}, saya tidak yakin berapa banyak dan operasi apa yang dapat atau tidak dapat didukung oleh {dtplyr}. Seperti disebutkan di atas, itu juga tergantung pada kerumitan operasi, yang pada gilirannya mempengaruhi terjemahan.Ada dua cara untuk menggunakan pembaruan dengan referensi di {data.table}
operator penugasan {data.table}
:=
set
-keluarga:set
,setnames
,setcolorder
,setkey
,setDT
,fsetdiff
, dan masih banyak lagi:=
lebih umum digunakan dibandingkan denganset
. Untuk dataset yang kompleks dan besar, pembaruan dengan referensi adalah kunci untuk mendapatkan kecepatan tertinggi & efisiensi memori. Cara berpikir yang mudah (tidak 100% akurat, karena perinciannya jauh lebih rumit daripada ini karena melibatkan hard / copy dangkal dan banyak faktor lainnya), misalnya Anda berurusan dengan dataset besar 10GB, masing-masing dengan 10 kolom dan 1GB . Untuk memanipulasi satu kolom, Anda hanya perlu berurusan dengan 1GB.Kuncinya adalah, dengan pembaruan-per-referensi , Anda hanya perlu berurusan dengan data yang diperlukan. Itu sebabnya ketika menggunakan {data.table}, terutama yang berhubungan dengan dataset besar, kami menggunakan pembaruan-per-referensi setiap saat kapan pun memungkinkan. Misalnya, memanipulasi dataset pemodelan besar
Operasi bersarang
list(.SD)
mungkin tidak didukung oleh {dtlyr} karena pengguna rapi merapikantidyr::nest
? Jadi saya tidak yakin apakah operasi selanjutnya dapat diterjemahkan sebagai cara {data.table} lebih cepat & lebih sedikit memori.CATATAN: hasil data.tabel adalah dalam "milidetik", dplyr dalam "menit"
Ada banyak kasus penggunaan pembaruan-oleh-referensi dan bahkan {data.table} pengguna tidak akan menggunakan versi lanjutan sepanjang waktu karena memerlukan lebih banyak kode. Apakah {dtplyr} mendukung ini di luar kotak, Anda harus mencari tahu sendiri.
Banyak pembaruan dengan referensi untuk fungsi yang sama
Sumber daya utama: Menempatkan beberapa kolom secara elegan dalam data.tabel dengan lapply ()
Ini melibatkan yang lebih umum digunakan
:=
atauset
.Sesuai pencipta {data.table} Matt Dowle
Bergabunglah + setkey + perbarui-oleh-referensi
Saya perlu bergabung cepat dengan data yang relatif besar dan pola bergabung serupa baru-baru ini, jadi saya menggunakan kekuatan pembaruan-oleh-referensi , bukan bergabung normal. Karena mereka membutuhkan lebih banyak kode, saya membungkusnya dalam paket pribadi dengan evaluasi non-standar untuk dapat digunakan kembali dan mudah dibaca di mana saya menyebutnya
setjoin
.Saya melakukan beberapa tolok ukur di sini: data.table bergabung + perbarui-oleh-referensi + setkey
Ringkasan
CATATAN:
dplyr::left_join
juga diuji dan ini paling lambat dengan ~ 9.000 ms, gunakan lebih banyak memori daripada {data.table}update_by_reference
dansetkey_n_update
, tetapi gunakan lebih sedikit memori daripada normal_join {data.table}. Ini menghabiskan sekitar ~ 2.0GB memori. Saya tidak memasukkannya karena saya hanya ingin fokus pada {data.table}.Temuan Utama
setkey + update
danupdate
~ 11 dan ~ 6,5 kali lebih cepat daripadanormal join
masing-masingsetkey + update
mirip denganupdate
overheadsetkey
sebagian besar mengimbangi keuntungan kinerjanya sendirisetkey
tidak diperlukan,setkey + update
lebih cepat daripadaupdate
~ 1,8 kali (atau lebih cepat darinormal join
~ 11 kali)Contohnya
Untuk penggabungan yang berkinerja & efisien memori, gunakan salah satu
update
atausetkey + update
, di mana yang terakhir lebih cepat dengan mengorbankan lebih banyak kode.Mari kita lihat beberapa kode semu , untuk singkatnya. Logikanya sama.
Untuk satu atau beberapa kolom
Untuk banyak kolom
Wrapper untuk sambungan cepat & hemat memori ... banyak dari mereka ... dengan pola gabungan yang sama, bungkus seperti di
setjoin
atas - denganupdate
- dengan atau tanpasetkey
Dengan
setkey
, argumenon
bisa dihilangkan. Ini juga dapat dimasukkan untuk keterbacaan, terutama untuk berkolaborasi dengan orang lain.Operasi baris besar
set
setkey
)Sumberdaya terkait: Tambahkan baris dengan referensi di akhir objek data.table
Ringkasan pembaruan dengan referensi
Ini hanya beberapa kasus penggunaan pembaruan-oleh-referensi . Masih banyak lagi.
Seperti yang Anda lihat, untuk penggunaan lanjutan berurusan dengan data besar, ada banyak kasus dan teknik penggunaan menggunakan pembaruan-oleh-referensi untuk dataset besar. Tidak mudah digunakan di {data.table} dan apakah {dtplyr} mendukungnya, Anda bisa mengetahuinya sendiri.
Saya fokus pada pembaruan-oleh-referensi dalam posting ini karena saya pikir ini adalah fitur yang paling kuat dari {data.table} untuk operasi cepat & efisien memori. Yang mengatakan, ada banyak, banyak aspek lain yang membuatnya sangat efisien juga dan saya pikir itu tidak didukung oleh {dtplyr}.
Aspek kunci lainnya
Apa yang didukung / tidak, itu juga tergantung pada kompleksitas operasi dan apakah itu melibatkan fitur asli data.table seperti pembaruan-oleh-referensi atau
setkey
. Dan apakah kode yang diterjemahkan lebih efisien (kode yang akan ditulis oleh pengguna data) juga merupakan faktor lain (yaitu kode diterjemahkan, tetapi apakah ini versi efisien?). Banyak hal yang saling berhubungan.setkey
. Lihat Kunci dan subset berbasis pencarian biner cepatfrollapply
. fungsi bergulir, agregat bergulir, jendela geser, moving averagei
,j
atauby
operasi (Anda dapat menggunakan hampir semua ekspresi di sana), saya pikir sulit terjemahan, terutama ketika menggabungkan dengan update-by-referensi ,setkey
dan data.table asli lainnya fungsi sepertifrollapply
stringr::str_*
fungsi keluarga vs basis R dan saya menemukan basis R lebih cepat sampai batas tertentu dan menggunakannya. Intinya adalah, jangan biarkan diri Anda hanya merapikan atau data. Tabel atau ..., mengeksplorasi opsi lain untuk menyelesaikan pekerjaan.Banyak dari aspek-aspek ini saling terkait dengan poin-poin yang disebutkan di atas
kompleksitas operasi
perbarui-oleh-referensi
Anda dapat mengetahui apakah {dtplyr} mendukung operasi ini terutama ketika dikombinasikan.
Trik lain yang berguna ketika berhadapan dengan dataset kecil atau besar, selama sesi interaktif, {data.table} benar-benar memenuhi janjinya untuk mengurangi pemrograman dan menghitung waktu secara luar biasa.
Tombol pengaturan untuk variabel yang digunakan berulang untuk kedua kecepatan dan 'rownames supercharged' (subset tanpa menentukan nama variabel).
Jika operasi Anda hanya melibatkan yang sederhana seperti pada contoh pertama, {dtplyr} dapat menyelesaikan pekerjaan. Untuk yang kompleks / tidak didukung, Anda dapat menggunakan panduan ini untuk membandingkan yang diterjemahkan {dtplyr} dengan bagaimana data berpengalaman. Pengguna akan mengkodekan dengan cara cepat & efisien memori dengan sintaks elegan data.table. Penerjemahan tidak berarti itu cara yang paling efisien karena mungkin ada teknik yang berbeda untuk menangani berbagai kasus data besar. Untuk set data yang lebih besar, Anda dapat menggabungkan {data.table} dengan {disk.frame} , {fst} dan {drake} dan paket luar biasa lainnya untuk mendapatkan yang terbaik darinya. Ada juga {big.data.table} tetapi saat ini tidak aktif.
Saya harap ini membantu semua orang. Semoga harimu menyenangkan ☺☺
sumber
Bergabung non-equi dan rolling bergabung ke pikiran. Sepertinya tidak ada rencana untuk memasukkan fungsi yang setara di dplyr sehingga tidak ada yang bisa diterjemahkan oleh dtplyr.
Ada juga pembentukan kembali (optimal dcast dan mencair setara dengan fungsi yang sama dalam membentuk kembali2) yang tidak ada dalam dplyr juga.
Semua fungsi * _if dan * _at saat ini tidak dapat diterjemahkan dengan dtplyr juga, tetapi semua itu masih berfungsi.
sumber
Perbarui kolom saat bergabung dengan Beberapa. Trik SD Banyak fungsi f Dan Tuhan tahu apa lagi karena #rdatatable lebih dari sekadar perpustakaan sederhana dan tidak dapat diringkas dengan beberapa fungsi
Ini seluruh ekosistem sendiri
Saya tidak pernah membutuhkan dplyr sejak hari saya mulai R. Karena data.tabel sangat bagus
sumber