क्यों purrr :: lapply के बजाय मानचित्र का उपयोग करें?


171

क्या कोई कारण है कि मुझे इसका उपयोग करना चाहिए

map(<list-like-object>, function(x) <do stuff>)

के बजाय

lapply(<list-like-object>, function(x) <do stuff>)

आउटपुट समान होना चाहिए और मेरे द्वारा बनाए गए बेंचमार्क यह दिखाते हैं कि lapplyयह थोड़ा तेज़ है (यह mapसभी गैर-मानक-मूल्यांकन इनपुट का मूल्यांकन करने की आवश्यकता होनी चाहिए )।

तो क्या कोई कारण है कि ऐसे साधारण मामलों के लिए मुझे वास्तव में स्विच करने पर विचार करना चाहिए purrr::map? मैं यहाँ वाक्य रचना के बारे में किसी की पसंद या नापसंद के बारे में नहीं पूछ रहा हूँ, purrr आदि द्वारा प्रदान की गई अन्य कार्यक्षमताएं, लेकिन मानक मूल्यांकन का उपयोग करने के purrr::mapसाथ तुलना करने के बारे में सख्ती से । क्या प्रदर्शन, अपवाद से निपटने आदि के संदर्भ में कोई लाभ है ? नीचे दी गई टिप्पणियां बताती हैं कि ऐसा नहीं है, लेकिन हो सकता है कि कोई व्यक्ति थोड़ा अधिक विस्तार कर सके?lapplymap(<list-like-object>, function(x) <do stuff>)purrr::map


8
वास्तव में सरल उपयोग के मामलों के लिए, बेस आर के साथ बेहतर छड़ी और निर्भरता से बचें। यदि आप पहले से ही लोड करते हैं tidyverse, तो आप पाइप %>%और बेनामी फ़ंक्शंस ~ .x + 1सिंटैक्स
ऑरले जूल

49
यह बहुत शैली का सवाल है। आपको पता होना चाहिए कि बेस आर फ़ंक्शन क्या करता है, क्योंकि यह सभी सुव्यवस्थित सामान इसके ऊपर सिर्फ एक शेल है। कुछ बिंदु पर, वह खोल टूट जाएगा।
हांग ओई

9
~{}शॉर्टकट लैम्ब्डा (के साथ या बिना {}सादे के लिए मेरे लिए सौदा सील purrr::map()। के प्रकार प्रवर्तन purrr::map_…()काम और कम कुंठित से कर रहे हैं vapply()purrr::map_df()एक सुपर महंगा समारोह है, लेकिन इसे को सरल बनाने के कोड। वहाँ आधार आर के साथ चिपके हुए के साथ कुछ भी नहीं गलत बिल्कुल है [lsv]apply(), हालांकि ।
hrbrmstr

4
सवाल के लिए धन्यवाद - जिस तरह का सामान मैंने भी देखा। मैं 10 से अधिक वर्षों से आर का उपयोग कर रहा हूं और निश्चित रूप से purrrसामान का उपयोग नहीं करूंगा । मेरी बात निम्नलिखित है: tidyverseविश्लेषण / इंटरैक्टिव / रिपोर्ट सामान के लिए शानदार है, प्रोग्रामिंग के लिए नहीं। यदि आप उपयोग कर रहे हैं lapplyया mapफिर आप प्रोग्रामिंग कर रहे हैं और पैकेज बनाने के साथ एक दिन समाप्त हो सकता है। फिर कम निर्भरता सबसे अच्छा। प्लस: मैं कुछ समय mapबाद काफी अस्पष्ट वाक्यविन्यास के साथ लोगों को देखता हूं । और अब जब मैं प्रदर्शन परीक्षण देखता हूं: यदि आप applyपरिवार के अभ्यस्त हैं: तो उससे चिपके रहें।
एरिक लेकौत्रे

4
टिम ने लिखा है: "मैं यहाँ किसी की पसंद या नापसंद के बारे में नहीं पूछ रहा हूँ, वाक्यविन्यास, purrr आदि द्वारा प्रदान की गई अन्य कार्यक्षमताएँ, लेकिन कड़ाई से purrr की तुलना के बारे में :: मानक मूल्यांकन का उपयोग करते हुए lapply मान के साथ मानचित्र" और उत्तर स्वीकृत है। जो आपने कहा था, वह ठीक है कि आप नहीं चाहते थे कि लोग खत्म हो जाएं।
कार्लोस सिनेली

जवाबों:


232

यदि आप केवल purrr से उपयोग कर रहे हैं map(), तो नहीं, लाभ पर्याप्त नहीं हैं। जैसा कि रिच पॉलू बताते हैं, मुख्य लाभ map()उन सहायकों का है जो आपको सामान्य विशेष मामलों के लिए कॉम्पैक्ट कोड लिखने की अनुमति देते हैं:

  • ~ . + 1 के बराबर है function(x) x + 1

  • list("x", 1)के बराबर है function(x) x[["x"]][[1]]। इन सहायकों की तुलना में थोड़ा अधिक सामान्य हैं [[- ?pluckविवरण के लिए देखें। के लिए डेटा rectangling , .defaultतर्क विशेष रूप से उपयोगी है।

लेकिन अधिकांश समय आप एक एकल *apply()/ map() फ़ंक्शन का उपयोग नहीं कर रहे हैं , आप उनमें से एक गुच्छा का उपयोग कर रहे हैं, और purrr का लाभ फ़ंक्शंस के बीच बहुत अधिक स्थिरता है। उदाहरण के लिए:

  • पहला तर्क lapply() डेटा है; mapply()फ़ंक्शन का पहला तर्क है । सभी मानचित्र कार्यों के लिए पहला तर्क हमेशा डेटा होता है।

  • के साथ vapply(), sapply()और mapply()आप आउटपुट पर नामों को दबाने का विकल्प चुन सकते हैंUSE.NAMES = FALSE ; लेकिन lapply()उस तर्क नहीं है।

  • मैपर फ़ंक्शन पर लगातार तर्क पास करने का कोई सुसंगत तरीका नहीं है। अधिकांश फ़ंक्शंस उपयोग करते हैं, ...लेकिन mapply()उपयोग करते हैं MoreArgs(जिसे आप कॉल करने की उम्मीद करेंगे MORE.ARGS), और Map();Filter() और Reduce()आप एक नई अज्ञात समारोह बनाने की उम्मीद है। मानचित्र कार्यों में, फ़ंक्शन नाम के बाद निरंतर तर्क हमेशा आते हैं।

  • लगभग हर purrr फ़ंक्शन स्थिर होता है: आप विशेष रूप से फ़ंक्शन नाम से आउटपुट प्रकार का अनुमान लगा सकते हैं। यह sapply()या के लिए सच नहीं है mapply()। हाँ, वहाँ है vapply(); लेकिन इसके लिए कोई समकक्ष नहीं हैmapply()

आप सोच सकते हैं कि ये सभी मामूली अंतर महत्वपूर्ण नहीं हैं (जैसा कि कुछ लोग सोचते हैं कि आधार आर नियमित अभिव्यक्ति पर स्ट्रिंग करने का कोई लाभ नहीं है), लेकिन मेरे अनुभव में वे अनावश्यक घर्षण का कारण बनते हैं जब प्रोग्रामिंग (अलग-अलग तर्क आदेश हमेशा यात्रा करने के लिए उपयोग किए जाते हैं) मुझे), और वे सीखने के लिए कार्यात्मक प्रोग्रामिंग तकनीकों को कठिन बनाते हैं क्योंकि बड़े विचारों के साथ-साथ आपको आकस्मिक विवरणों का एक समूह भी सीखना होगा।

Purrr बेस आर से अनुपस्थित कुछ आसान मैप वेरिएंट में भी भरता है:

  • modify()[[<-"जगह में" को संशोधित करने के लिए डेटा के प्रकार को संरक्षित करता है । _ifवैरिएंट के साथ संयोजन में यह (IMO सुंदर) कोड की तरह अनुमति देता हैmodify_if(df, is.factor, as.character)

  • map2()आप एक साथ खत्म करने के लिए नक्शा करने की अनुमति देता है xऔर y। इससे विचारों को व्यक्त करना आसान हो जाता है map2(models, datasets, predict)

  • imap()आपको एक साथ xऔर इसके सूचकांकों (या तो नाम या स्थान) पर मैप करने की अनुमति देता है । यह csvनिर्देशिका में सभी फ़ाइलों को लोड करना आसान बनाता है (जैसे) filenameप्रत्येक निर्देशिका में एक कॉलम जोड़कर ।

    dir("\\.csv$") %>%
      set_names() %>%
      map(read.csv) %>%
      imap(~ transform(.x, filename = .y))
  • walk()इसके इनपुट को अदृश्य रूप से लौटाता है; और तब उपयोगी होता है जब आप इसके साइड-इफेक्ट्स के लिए एक फंक्शन बुला रहे होते हैं (यानी डिस्क पर फाइल लिखना)।

जैसे अन्य सहायकों का उल्लेख नहीं है safely()और partial()

व्यक्तिगत रूप से, मुझे लगता है कि जब मैं purrr का उपयोग करता हूं, तो मैं कम घर्षण और अधिक आसानी के साथ कार्यात्मक कोड लिख सकता हूं; यह एक विचार को सोचने और इसे लागू करने के बीच की खाई को कम करता है। लेकिन आपका माइलेज अलग-अलग हो सकता है; Purrr का उपयोग करने की कोई आवश्यकता नहीं है जब तक कि यह वास्तव में आपकी मदद न करे।

Microbenchmarks

हाँ, map()की तुलना में थोड़ा धीमा है lapply()। लेकिन उपयोग करने की लागत map()या lapply()आप जो मैपिंग कर रहे हैं, उसके द्वारा संचालित है, लूप के प्रदर्शन का ओवरहेड नहीं। नीचे दिए गए माइक्रोबैन्चमार्क से पता चलता है कि map()तुलना की लागत lapply()लगभग 40 एनएम प्रति तत्व है, जो कि अधिकांश आर कोड को भौतिक रूप से प्रभावित करने की संभावना नहीं है।

library(purrr)
n <- 1e4
x <- 1:n
f <- function(x) NULL

mb <- microbenchmark::microbenchmark(
  lapply = lapply(x, f),
  map = map(x, f)
)
summary(mb, unit = "ns")$median / n
#> [1] 490.343 546.880

2
क्या आप उस उदाहरण में परिवर्तन () का उपयोग करने के लिए थे? जैसा कि बेस आर ट्रांसफॉर्म () में है, या मैं कुछ याद कर रहा हूं? परिवर्तन () आपको एक कारक के रूप में फ़ाइल नाम देता है, जो चेतावनी देता है जब आप (स्वाभाविक रूप से) एक साथ पंक्तियों को बांधना चाहते हैं। mutate () मुझे उन फ़ाइलनामों के चरित्र कॉलम देता है जो मुझे चाहिए। क्या वहाँ इसका उपयोग न करने का कोई कारण है?
डॉक्टर जी

2
हां, उपयोग करने के लिए बेहतर है mutate(), मैं सिर्फ एक सरल उदाहरण चाहता था जिसमें कोई अन्य डिप्स नहीं था।
हैडले

क्या इस उत्तर में टाइप-विशिष्टता नहीं दिखाई जानी चाहिए? map_*है जो मुझे purrrकई लिपियों में लोड हो रहा है। इसने मेरे कोड के कुछ 'नियंत्रण प्रवाह' पहलुओं के साथ मेरी मदद की ( stopifnot(is.data.frame(x)))।
Fr.

2
ggplot और data.table महान हैं, लेकिन क्या हमें वास्तव में R में हर एक फ़ंक्शन के लिए एक नए पैकेज की आवश्यकता है?
adn bps

58

तुलना purrrऔर सुविधा और गति केlapply लिए फोड़े ।


1. purrr::maplapply की तुलना में वाक्यात्मक रूप से अधिक सुविधाजनक है

सूची का दूसरा तत्व निकालें

map(list, 2)  

जो @F के रूप में। प्रिवी ने बताया, जैसा है:

map(list, function(x) x[[2]])

साथ में lapply

lapply(list, 2) # doesn't work

हमें एक अनाम फ़ंक्शन पास करना होगा ...

lapply(list, function(x) x[[2]])  # now it works

... या @RichScriven ने बताया, हम [[एक तर्क के रूप में पास होते हैंlapply

lapply(list, `[[`, 2)  # a bit more simple syntantically

तो अगर अपने आप को कई सूचियों का उपयोग करने के लिए कार्यों को लागू करने lapply, और एक कस्टम फ़ंक्शन को परिभाषित करने या किसी अनाम फ़ंक्शन को लिखने के लिए सुविधा मिलती है , तो सुविधा पक्ष का एक कारण हैpurrr

2. प्रकार-विशिष्ट मानचित्र केवल कोड की कई पंक्तियों को कार्य करता है

  • map_chr()
  • map_lgl()
  • map_int()
  • map_dbl()
  • map_df()

इन विशेष प्रकार के मानचित्र कार्यों में से प्रत्येक एक वेक्टर देता है, सूचियों के बजाय द्वारा लौटाए गए map()और lapply()। यदि आप वैक्टरों की नेस्टेड सूचियों के साथ काम कर रहे हैं, तो आप सीधे वैक्टर को बाहर निकालने के लिए इन प्रकार-विशिष्ट मानचित्र फ़ंक्शंस का उपयोग कर सकते हैं, और वैक्टर को सीधे int, dbl, chr vectors में ले जा सकते हैं। बेस आर संस्करण कुछ इस तरह दिखेगा as.numeric(sapply(...)),as.character(sapply(...)) आदि

map_<type>कार्य भी उपयोगी गुणवत्ता है कि अगर वे संकेत प्रकार के एक परमाणु वेक्टर वापस नहीं लौट सकते, वे विफल है। यह सख्त नियंत्रण प्रवाह को परिभाषित करते समय उपयोगी होता है, जहां आप एक फ़ंक्शन को विफल करना चाहते हैं यदि यह [किसी तरह] गलत वस्तु प्रकार उत्पन्न करता है।

3. एक तरफ सुविधा, lapplyकी तुलना में [थोड़ा] तेज हैmap

purrr@F के रूप में सुविधा कार्यों का उपयोग करना । प्रिवी ने बताया कि प्रोसेसिंग थोड़ा धीमा हो जाता है। चलो ऊपर प्रस्तुत 4 मामलों में से प्रत्येक की दौड़।

# devtools::install_github("jennybc/repurrrsive")
library(repurrrsive)
library(purrr)
library(microbenchmark)
library(ggplot2)

mbm <- microbenchmark(
lapply       = lapply(got_chars[1:4], function(x) x[[2]]),
lapply_2     = lapply(got_chars[1:4], `[[`, 2),
map_shortcut = map(got_chars[1:4], 2),
map          = map(got_chars[1:4], function(x) x[[2]]),
times        = 100
)
autoplot(mbm)

यहां छवि विवरण दर्ज करें

और विजेता है....

lapply(list, `[[`, 2)

संक्षेप में, यदि कच्ची गति वह हो जो आप के बाद हो: base::lapply (हालांकि यह उतना तेज़ नहीं है)

सरल वाक्यविन्यास और अभिव्यक्ति के लिए: purrr::map


यह उत्कृष्ट purrrट्यूटोरियल स्पष्ट रूप से उपयोग करते समय अनाम कार्यों को स्पष्ट रूप से नहीं लिखने की सुविधा पर प्रकाश डालता है purrr, और प्रकार-विशिष्ट mapकार्यों के लाभ ।


2
ध्यान दें कि यदि आप function(x) x[[2]]बस के बजाय उपयोग करते हैं 2, तो यह कम धीमा होगा। यह सब अतिरिक्त समय चेक के कारण lapplyहोता है जो ऐसा नहीं करता है।
एफ। प्रिवीप

17
आपको अनाम कार्यों की "आवश्यकता" नहीं है। [[एक समारोह है। आप कर सकते हैं lapply(list, "[[", 3)
रिच स्क्रिप्‍ट

@RichSvenven जो समझ में आता है। यह purrr पर lapply का उपयोग करने के लिए वाक्य रचना को सरल करता है।
रिच पॉलू

37

यदि हम स्वाद के पहलुओं पर विचार नहीं करते हैं (अन्यथा यह प्रश्न बंद होना चाहिए) या वाक्यविन्यास संगतता, शैली आदि, उत्तर नहीं है, तो आवेदन करने वाले परिवार के अन्य वेरिएंट जैसे स्ट्रिकटर के mapबजाय उपयोग करने का कोई विशेष कारण नहीं है ।lapplyvapply

पुनश्च: उन लोगों को कृतज्ञतापूर्वक अपमानित करने के लिए, बस ओपी ने लिखा याद रखें:

मैं यहाँ वाक्य रचना के बारे में किसी की पसंद या नापसंद के बारे में नहीं पूछ रहा हूँ, purrr आदि द्वारा प्रदान की गई अन्य कार्यक्षमताएं, लेकिन कड़ाई से purrr की तुलना के बारे में :: मानक मूल्यांकन का उपयोग करते हुए lapply मान के साथ नक्शा

यदि आप वाक्यविन्यास और न ही अन्य कार्यक्षमताओं पर विचार नहीं करते हैं purrr, तो उपयोग करने का कोई विशेष कारण नहीं है map। मैं purrrखुद का उपयोग करता हूं और हेडली के जवाब से ठीक हूं, लेकिन यह विडंबना है कि ओपी ने कहा कि वह नहीं पूछ रहा है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.