Apakah ada alasan mengapa saya harus menggunakannya
map(<list-like-object>, function(x) <do stuff>)
dari pada
lapply(<list-like-object>, function(x) <do stuff>)
outputnya harus sama dan tolok ukur yang saya buat nampaknya menunjukkan bahwa lapply
sedikit lebih cepat (harus sesuai dengan map
kebutuhan untuk mengevaluasi semua input non-standar-evaluasi).
Jadi apakah ada alasan mengapa untuk kasus sederhana seperti itu saya benar-benar harus mempertimbangkan untuk beralih ke purrr::map
? Saya tidak bertanya di sini tentang suka atau tidak suka seseorang tentang sintaks, fungsi lain yang disediakan oleh purrr dll, tetapi hanya tentang perbandingan purrr::map
dengan lapply
asumsi menggunakan evaluasi standar, yaitu map(<list-like-object>, function(x) <do stuff>)
. Apakah ada kelebihan yang purrr::map
dimiliki dalam hal kinerja, penanganan pengecualian, dll.? Komentar di bawah ini menunjukkan bahwa tidak, tetapi mungkin seseorang dapat menguraikan sedikit lebih banyak?
tidyverse
, Anda mungkin mendapat manfaat dari sintaksis%>%
fungsi pipa dan anonim~ .x + 1
~{}
pintas lambda (dengan atau tanpa{}
segel kesepakatan bagi saya untuk polospurrr::map()
. Jenis-penegakanpurrr::map_…()
yang berguna dan kurang tumpul darivapply()
.purrr::map_df()
adalah fungsi super mahal tetapi juga menyederhanakan kode. Sama sekali tidak ada yang salah dengan bertahan dengan basis R[lsv]apply()
, meskipun .purrr
barang. Maksud saya adalah sebagai berikut:tidyverse
luar biasa untuk analisis / interaktif / melaporkan barang, bukan untuk pemrograman. Jika Anda harus menggunakanlapply
ataumap
kemudian Anda sedang pemrograman dan mungkin berakhir suatu hari dengan membuat paket. Maka semakin sedikit ketergantungan yang terbaik. Plus: Saya kadang-kadang melihat orang menggunakanmap
sintaks yang tidak jelas setelahnya. Dan sekarang saya melihat pengujian kinerja: jika Anda terbiasa denganapply
keluarga: patuhi itu.Jawaban:
Jika satu-satunya fungsi yang Anda gunakan dari purr adalah
map()
, maka tidak, keuntungannya tidak besar. Seperti yang ditunjukkan oleh Rich Pauloo, keuntungan utamamap()
adalah bantuan yang memungkinkan Anda menulis kode ringkas untuk kasus khusus umum:~ . + 1
setara denganfunction(x) x + 1
list("x", 1)
setara denganfunction(x) x[["x"]][[1]]
. Pembantu ini sedikit lebih umum daripada[[
- lihat?pluck
detailnya. Untuk persegi panjang data ,.default
argumen ini sangat membantu.Tetapi sebagian besar waktu Anda tidak menggunakan satu
*apply()
/map()
fungsi, Anda menggunakan banyak dari mereka, dan keuntungan dari purrr adalah konsistensi yang jauh lebih besar antara fungsi. Sebagai contoh:Argumen pertama
lapply()
adalah data; argumen pertamamapply()
adalah fungsi. Argumen pertama untuk semua fungsi peta selalu data.Dengan
vapply()
,,sapply()
danmapply()
Anda dapat memilih untuk menekan nama pada output denganUSE.NAMES = FALSE
; tetapilapply()
tidak memiliki argumen itu.Tidak ada cara yang konsisten untuk meneruskan argumen yang konsisten ke fungsi mapper. Sebagian besar fungsi menggunakan
...
tetapimapply()
menggunakanMoreArgs
(yang Anda harapkan dipanggilMORE.ARGS
), danMap()
,Filter()
danReduce()
berharap Anda membuat fungsi anonim baru. Dalam fungsi peta, argumen konstan selalu muncul setelah nama fungsi.Hampir setiap fungsi purrr adalah tipe stabil: Anda dapat memprediksi tipe output secara eksklusif dari nama fungsi. Ini tidak benar untuk
sapply()
ataumapply()
. Ya adavapply()
; tapi tidak ada padanan untukmapply()
.Anda mungkin berpikir bahwa semua perbedaan kecil ini tidak penting (seperti beberapa orang berpikir bahwa tidak ada keuntungan untuk merangkai ekspresi reguler basis R), tetapi dalam pengalaman saya mereka menyebabkan gesekan yang tidak perlu saat pemrograman (perintah argumen yang berbeda selalu digunakan untuk trip saya), dan mereka membuat teknik pemrograman fungsional lebih sulit untuk dipelajari karena juga ide-ide besar, Anda juga harus belajar banyak detail insidental.
Purrr juga mengisi beberapa varian peta praktis yang tidak ada di basis R:
modify()
mempertahankan tipe data yang digunakan[[<-
untuk memodifikasi "di tempat". Sehubungan dengan_if
varian ini memungkinkan untuk kode (IMO indah) sepertimodify_if(df, is.factor, as.character)
map2()
memungkinkan Anda untuk memetakan sekaligusx
dany
. Ini membuatnya lebih mudah untuk mengekspresikan ide-ide sepertimap2(models, datasets, predict)
imap()
memungkinkan Anda untuk memetakan secara bersamaanx
dan indeksnya (baik nama atau posisi). Ini memudahkan (misalnya) memuat semuacsv
file dalam direktori, menambahkanfilename
kolom ke masing-masing file .walk()
mengembalikan inputnya tanpa terlihat; dan berguna ketika Anda memanggil fungsi untuk efek sampingnya (yaitu menulis file ke disk).Belum lagi pembantu lainnya seperti
safely()
danpartial()
.Secara pribadi, saya menemukan bahwa ketika saya menggunakan purrr, saya dapat menulis kode fungsional dengan lebih sedikit gesekan dan kemudahan yang lebih besar; itu mengurangi kesenjangan antara memikirkan ide dan mengimplementasikannya. Tetapi jarak tempuh Anda mungkin berbeda; tidak perlu menggunakan purrr kecuali itu benar-benar membantu Anda.
Microbenchmark
Ya,
map()
sedikit lebih lambat darilapply()
. Tetapi biaya menggunakanmap()
ataulapply()
didorong oleh apa yang Anda pemetaan, bukan biaya overhead untuk melakukan loop. Microbenchmark di bawah ini menunjukkan bahwa biayamap()
dibandingkan denganlapply()
sekitar 40 ns per elemen, yang tampaknya tidak berdampak material terhadap sebagian besar kode R.sumber
mutate()
, saya hanya ingin contoh sederhana tanpa deps lain.map_*
adalah apa yang membuat saya memuatpurrr
banyak skrip. Ini membantu saya dengan beberapa aspek 'aliran kendali' dari kode saya (stopifnot(is.data.frame(x))
).Membandingkan
purrr
danlapply
bermuara pada kenyamanan dan kecepatan .1.
purrr::map
secara sintaksis lebih nyaman daripada lapplyekstrak elemen kedua dari daftar
yang sebagai @F. Privé tunjukkan, sama dengan:
dengan
lapply
kita harus melewati fungsi anonim ...
... atau seperti yang ditunjukkan @RichScriven, kami memberikan
[[
argumenlapply
Jadi jika menemukan diri Anda menerapkan fungsi ke banyak daftar menggunakan
lapply
, dan bosan mendefinisikan fungsi kustom atau menulis fungsi anonim, kenyamanan adalah salah satu alasan untuk memilihpurrr
.2. Jenis-fungsi peta spesifik hanya banyak baris kode
map_chr()
map_lgl()
map_int()
map_dbl()
map_df()
Masing-masing fungsi peta tipe spesifik ini mengembalikan vektor, bukan daftar yang dikembalikan oleh
map()
danlapply()
. Jika Anda berurusan dengan daftar vektor bersarang, Anda dapat menggunakan fungsi peta khusus ini untuk menarik vektor secara langsung, dan memaksa vektor langsung ke vektor int, dbl, chr. Versi dasar R akan terlihat sepertias.numeric(sapply(...))
,as.character(sapply(...))
, dllmap_<type>
Fungsi - fungsinya juga memiliki kualitas yang berguna bahwa jika mereka tidak dapat mengembalikan vektor atom dari tipe yang ditunjukkan, mereka gagal. Ini berguna ketika mendefinisikan aliran kontrol yang ketat, di mana Anda ingin fungsi gagal jika [entah bagaimana] menghasilkan tipe objek yang salah.3. Kesamping kenyamanan,
lapply
adalah [sedikit] lebih cepat daripadamap
Menggunakan
purrr
fungsi kenyamanan, sebagai @F. Privé menunjukkan memperlambat pemrosesan sedikit. Mari kita berlomba masing-masing dari 4 kasus yang saya disajikan di atasDan pemenangnya adalah....
Singkatnya, jika kecepatan mentah adalah yang Anda cari:
base::lapply
(meskipun itu tidak jauh lebih cepat)Untuk sintaks dan ekspresi yang sederhana:
purrr::map
purrr
Tutorial yang sangat baik ini menyoroti kenyamanan tidak harus secara eksplisit menulis fungsi anonim saat menggunakanpurrr
, dan manfaat darimap
fungsi tipe-spesifik .sumber
function(x) x[[2]]
bukan hanya2
, itu akan kurang lambat. Semua waktu tambahan ini disebabkan oleh cek yanglapply
tidak berfungsi.[[
adalah suatu fungsi. Anda bisa melakukannyalapply(list, "[[", 3)
.Jika kita tidak mempertimbangkan aspek selera (kalau tidak pertanyaan ini harus ditutup) atau konsistensi sintaksis, gaya dll. Jawabannya tidak, tidak ada alasan khusus untuk digunakan
map
sebagai gantilapply
atau varian lain dari keluarga yang berlaku, seperti yang lebih ketatvapply
.PS: Kepada orang-orang itu dengan sembrono downvoting, ingat saja OP menulis:
Jika Anda tidak mempertimbangkan sintaks atau fungsi lain dari
purrr
, tidak ada alasan khusus untuk digunakanmap
. Saya menggunakanpurrr
diri saya sendiri dan saya baik-baik saja dengan jawaban Hadley, tetapi ironisnya hal itu lebih penting daripada yang dikatakan OP di muka bahwa ia tidak bertanya.sumber