data.table बनाम dplyr: क्या कोई कुछ अच्छी तरह से कर सकता है अन्य कोई खराब नहीं कर सकता या करता है?




(3)

प्रश्न शीर्षक के सीधी प्रतिक्रिया में ...

dplyr निश्चित रूप से चीजें करता है कि data.table . data.table नहीं कर सकते हैं।

आपका बिंदु # 3

dplyr abstracts (या इच्छा) संभावित डीबी इंटरैक्शन

आपके अपने प्रश्न का सीधा जवाब है लेकिन इसे उच्च स्तर तक नहीं बढ़ाया गया है। dplyr वास्तव में एक से अधिक डेटा भंडारण तंत्र के लिए एक विस्तारणीय फ्रंट एंड है जहां डेटा. data.table एक के लिए एक विस्तार है।

एक ही व्याकरण का उपयोग कर सभी लक्ष्यों के साथ, बैक-एंड अज्ञेय इंटरफ़ेस के रूप में dplyr को देखें, जहां आप dplyr लक्ष्य और हैंडलर का विस्तार कर सकते हैं। data.table is, from the dplyr perspective, one of those targets.

You will never (I hope) see a day that data.table attempts to translate your queries to create SQL statements that operate with on-disk or networked data stores.

dplyr can possibly do things data.table will not or might not do as well.

Based on the design of working in-memory, data.table could have a much more difficult time extending itself into parallel processing of queries than dplyr .

In response to the in-body questions...

प्रयोग

Are there analytical tasks that are a lot easier to code with one or the other package for people familiar with the packages (ie some combination of keystrokes required vs. required level of esotericism, where less of each is a good thing).

This may seem like a punt but the real answer is no. People familiar with tools seem to use the either the one most familiar to them or the one that is actually the right one for the job at hand. With that being said, sometimes you want to present a particular readability, sometimes a level of performance, and when you have need for a high enough level of both you may just need another tool to go along with what you already have to make clearer abstractions.

प्रदर्शन

Are there analytical tasks that are performed substantially (ie more than 2x) more efficiently in one package vs. another.

Again, no. data.table excels at being efficient in everything it does where dplyr gets the burden of being limited in some respects to the underlying data store and registered handlers.

This means when you run into a performance issue with data.table you can be pretty sure it is in your query function and if it is actually a bottleneck with data.table then you've won yourself the joy of filing a report. This is also true when dplyr is using data.table as the back-end; you may see some overhead from dplyr but odds are it is your query.

When dplyr has performance issues with back-ends you can get around them by registering a function for hybrid evaluation or (in the case of databases) manipulating the generated query prior to execution.

Also see the accepted answer to when is plyr better than data.table?

अवलोकन

मैं dplyr . dplyr साथ अपेक्षाकृत परिचित हूँ, data.table साथ इतना ज्यादा नहीं। मैंने कुछ dplyr विगेट्स और उदाहरणों के माध्यम से पढ़ा है जो SO पर पॉप अप हो गए हैं, और अब तक मेरे निष्कर्ष यह हैं कि:

  1. data.table और dplyr गति में तुलनीय हैं, सिवाय इसके कि जब कई (यानी> 10-100 के) समूह होते हैं, और कुछ अन्य परिस्थितियों में (नीचे बेंचमार्क देखें)
  2. dplyr अधिक सुलभ वाक्यविन्यास है
  3. dplyr abstracts (या इच्छा) संभावित डीबी इंटरैक्शन
  4. कुछ मामूली कार्यक्षमता अंतर हैं (नीचे "उदाहरण / उपयोग" देखें)

मेरे दिमाग में 2. बहुत अधिक भार नहीं लेता है क्योंकि मैं data.table साथ काफी परिचित data.table , हालांकि मैं समझता हूं कि उपयोगकर्ताओं के लिए यह नया एक बड़ा कारक होगा। मैं इस बारे में एक तर्क से बचना चाहता हूं कि अधिक सहज ज्ञान युक्त है, क्योंकि यह मेरे विशिष्ट प्रश्न के लिए अप्रासंगिक है जिसे data.table पहले से परिचित किसी के परिप्रेक्ष्य से पूछा गया है। मैं इस बारे में एक चर्चा से बचना चाहता हूं कि कैसे "अधिक अंतर्ज्ञानी" तेजी से विश्लेषण की ओर जाता है (निश्चित रूप से सच है, लेकिन फिर से, जो मुझे यहां सबसे ज्यादा दिलचस्पी नहीं है)।

सवाल

मैं क्या जानना चाहता हूं:

  1. क्या ऐसे विश्लेषणात्मक कार्य हैं जो संकुल से परिचित लोगों के लिए एक या दूसरे पैकेज के साथ कोड करना बहुत आसान होते हैं (यानी कुंजीस्ट्रोक के कुछ संयोजन बनाम अनिवार्यता के आवश्यक स्तर बनाम, जहां प्रत्येक में से कम एक अच्छी बात है)।
  2. क्या विश्लेषणात्मक कार्य हैं जो एक पैकेज बनाम एक दूसरे में काफी कुशलतापूर्वक (यानी 2x से अधिक) प्रदर्शन किए जाते हैं।

हाल ही में एक सवाल ने मुझे इसके बारे में कुछ और सोचने के लिए dplyr किया, क्योंकि उस बिंदु तक मुझे नहीं लगता था कि dplyr में पहले से ही क्या कर सकता है उससे काफी कुछ प्रदान करेगा। यहां dplyr समाधान (क्यू के अंत में डेटा) है:

dat %.%
  group_by(name, job) %.%
  filter(job != "Boss" | year == min(year)) %.%
  mutate(cumu_job2 = cumsum(job2))

जो data.table समाधान पर मेरे हैक प्रयास से काफी बेहतर था। उस ने कहा, अच्छे data.table समाधान भी बहुत अच्छे हैं (धन्यवाद जीन-रॉबर्ट, अरुण, और यहां ध्यान दें कि मैंने कड़ाई से सबसे इष्टतम समाधान पर एकल कथन का पक्ष लिया है):

setDT(dat)[,
  .SD[job != "Boss" | year == min(year)][, cumjob := cumsum(job2)], 
  by=list(id, job)
]

उत्तरार्द्ध के लिए वाक्यविन्यास बहुत गूढ़ प्रतीत हो सकता है, लेकिन यदि आप data.table (यानी कुछ अधिक गूढ़ चाल का उपयोग नहीं करते हैं) का उपयोग किया जाता है तो यह वास्तव में बहुत सरल है।

आदर्श रूप से मैं जो देखना चाहता हूं वह कुछ अच्छे उदाहरण हैं जो dplyr या data.table तरीका काफी अधिक संक्षिप्त है या काफी बेहतर प्रदर्शन करता है।

उदाहरण

प्रयोग
  • dplyr समूहबद्ध संचालन की अनुमति नहीं देता है जो पंक्तियों की मनमानी संख्या ( eddi के प्रश्न से , नोट: ऐसा लगता है कि यह dplyr 0.5 में लागू किया जाएगा, @beginneR @ eddi के प्रश्न के उत्तर में एक संभावित कार्य-आसपास दिखाता है) ।
  • data.table रोलिंग data.table का समर्थन करता है (धन्यवाद @ डोलस्टियस) साथ ही ओवरलैप ओवरलैप करता है
  • data.table आंतरिक इंडेक्सिंग के माध्यम से गति के लिए आंतरिक रूप से DT[col == value] या DT[col %in% values] अभिव्यक्ति को अनुकूलित करता है जो समान आधार आर सिंटैक्स का उपयोग करते समय बाइनरी खोज का उपयोग करता है। कुछ और विवरण और एक छोटे बेंचमार्क के लिए यहां देखें
  • dplyr कार्यों के मानक मूल्यांकन संस्करण प्रदान करता है (उदाहरण के लिए dplyr , summarize_each_ ) जो dplyr के प्रोग्रामेटिक उपयोग को सरल बना सकता है ( dplyr नोट प्रोग्रामेटिक उपयोग निश्चित रूप से संभव है, कम से कम मेरे ज्ञान के लिए कुछ सावधान विचार, प्रतिस्थापन / उद्धरण आदि की आवश्यकता है )
मानक

डेटा

प्रश्न अनुभाग में दिखाए गए पहले उदाहरण के लिए यह है।

dat <- structure(list(id = c(1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 2L, 2L, 
2L, 2L, 2L, 2L, 2L, 2L), name = c("Jane", "Jane", "Jane", "Jane", 
"Jane", "Jane", "Jane", "Jane", "Bob", "Bob", "Bob", "Bob", "Bob", 
"Bob", "Bob", "Bob"), year = c(1980L, 1981L, 1982L, 1983L, 1984L, 
1985L, 1986L, 1987L, 1985L, 1986L, 1987L, 1988L, 1989L, 1990L, 
1991L, 1992L), job = c("Manager", "Manager", "Manager", "Manager", 
"Manager", "Manager", "Boss", "Boss", "Manager", "Manager", "Manager", 
"Boss", "Boss", "Boss", "Boss", "Boss"), job2 = c(1L, 1L, 1L, 
1L, 1L, 1L, 0L, 0L, 1L, 1L, 1L, 0L, 0L, 0L, 0L, 0L)), .Names = c("id", 
"name", "year", "job", "job2"), class = "data.frame", row.names = c(NA, 
-16L))

अरुण के उत्तर की विस्तृत रूपरेखा के बाद, लेकिन अलग-अलग प्राथमिकताओं के आधार पर कुछ हद तक पुन: व्यवस्थित होने के बाद, dplyr परिप्रेक्ष्य से व्यापक उत्तर पर मेरा प्रयास यहां दिया गया है।

वाक्य - विन्यास

सिंटैक्स के लिए कुछ विषय-वस्तु है, लेकिन मैं अपने बयान से खड़ा हूं कि डेटाटेबल की सहमति से सीखना मुश्किल हो जाता है और पढ़ने में मुश्किल होती है। यह आंशिक रूप से है क्योंकि dplyr एक बहुत ही आसान समस्या हल कर रहा है!

एक वास्तव में महत्वपूर्ण बात यह है कि आपके लिए dplyr करता है कि यह आपके विकल्पों को बाधित करता है। मेरा दावा है कि "एकल समूह" adverb के साथ-साथ, केवल एक ही तालिका की समस्याओं को हल करने के लिए केवल पांच कुंजी क्रियाएं फ़िल्टर, चयन, उत्परिवर्तन, व्यवस्था और संक्षेप में हल किया जा सकता है। जब आप डेटा हेरफेर सीख रहे हों तो यह बाधा एक बड़ी मदद है, क्योंकि इससे समस्या के बारे में आपकी सोच को ऑर्डर करने में मदद मिलती है। Dplyr में, इन क्रियाओं में से प्रत्येक एक समारोह में मैप किया गया है। प्रत्येक कार्य एक नौकरी करता है, और अलगाव में समझना आसान है।

आप इन साधारण परिचालनों को %>% साथ एक साथ पाइप करके जटिलता बनाते हैं। अरुण से जुड़े पदों में से एक का उदाहरण यहां दिया गया है :

diamonds %>%
  filter(cut != "Fair") %>%
  group_by(cut) %>%
  summarize(
    AvgPrice = mean(price),
    MedianPrice = as.numeric(median(price)),
    Count = n()
  ) %>%
  arrange(desc(Count))

भले ही आपने कभी पहले (या यहां तक ​​कि आर!) को कभी भी नहीं देखा है, फिर भी आप क्या हो रहा है इसके बारे में जानकारी प्राप्त कर सकते हैं क्योंकि कार्य सभी अंग्रेजी क्रियाएं हैं। अंग्रेजी क्रियाओं का नुकसान यह है कि उन्हें [ से अधिक टाइपिंग की आवश्यकता होती है, लेकिन मुझे लगता है कि इसे बेहतर स्वतः पूर्ण करके कम किया जा सकता है।

समकक्ष डेटाटेबल कोड यहां दिया गया है:

diamondsDT <- data.table(diamonds)
diamondsDT[
  cut != "Fair", 
  .(AvgPrice = mean(price),
    MedianPrice = as.numeric(median(price)),
    Count = .N
  ), 
  by = cut
][ 
  order(-Count) 
]

जब तक आप डेटा.table से पहले से परिचित नहीं हैं, तब तक इस कोड का पालन करना कठिन होता है। (मैं यह भी नहीं समझ सका कि बार-बार कैसे इंडेंट करना है [ जिस तरह से मेरी आंखों के लिए अच्छा लग रहा है)। निजी तौर पर, जब मैं 6 महीने पहले लिखा था कोड को देखता हूं, तो यह एक अजनबी द्वारा लिखे गए कोड को देखने जैसा है, इसलिए यदि वर्बोज़, कोड है तो मैं सीधा पसंद करता हूं।

दो अन्य मामूली कारक जो मुझे लगता है कि थोड़ा कम पठनीयता:

  • चूंकि लगभग हर डेटा टेबल ऑपरेशन का उपयोग करता है [ आपको यह पता लगाने के लिए अतिरिक्त संदर्भ की आवश्यकता है कि क्या हो रहा है। उदाहरण के लिए, x[y] दो डेटा तालिकाओं में शामिल होना या डेटा फ्रेम से कॉलम निकालना है? यह केवल एक छोटा मुद्दा है, क्योंकि अच्छी तरह से लिखित कोड में वेरिएबल नामों का सुझाव देना चाहिए कि क्या हो रहा है।

  • मुझे लगता है कि group_by() में एक अलग ऑपरेशन है। यह मौलिक रूप से गणना को बदलता है, इसलिए मुझे लगता है कि कोड को group_by() करते समय स्पष्ट होना चाहिए, और [.data.table तर्क के मुकाबले group_by() को स्थान group_by() आसान है।

मुझे यह भी पसंद है कि पाइप सिर्फ एक पैकेज तक ही सीमित नहीं है। आप अपने डेटा को tidyr साथ tidyr शुरू कर सकते हैं, और ggvis में एक साजिश के साथ खत्म हो सकता है । और आप मेरे द्वारा लिखे गए संकुल तक सीमित नहीं हैं - कोई भी एक फ़ंक्शन लिख सकता है जो डेटा मैनिपुलेशन पाइप का एक निर्बाध हिस्सा बनाता है। असल में, मैं पिछले डेटा.table कोड को %>% साथ फिर से लिखना पसंद करता हूं:

diamonds %>% 
  data.table() %>% 
  .[cut != "Fair", 
    .(AvgPrice = mean(price),
      MedianPrice = as.numeric(median(price)),
      Count = .N
    ), 
    by = cut
  ] %>% 
  .[order(-Count)]

और %>% साथ पाइपिंग का विचार केवल डेटा फ्रेम तक सीमित नहीं है और आसानी से अन्य संदर्भों के लिए सामान्यीकृत किया जाता है: इंटरैक्टिव वेब ग्राफिक्स , वेब स्क्रैपिंग , gists , रन-टाइम अनुबंध , ...)

मेमोरी और प्रदर्शन

मैंने इन्हें एक साथ लम्बा कर दिया है, क्योंकि, मेरे लिए, वे महत्वपूर्ण नहीं हैं। अधिकांश आर उपयोगकर्ता डेटा के 1 मिलियन पंक्तियों के साथ अच्छी तरह से काम करते हैं, और dplyr डेटा के उस आकार के लिए पर्याप्त तेज़ पर्याप्त है जिसे आप समय प्रसंस्करण के बारे में नहीं जानते हैं। हम मध्यम डेटा पर अभिव्यक्ति के लिए dplyr अनुकूलित करते हैं; बड़े डेटा पर कच्चे गति के लिए डेटा.table का उपयोग करने के लिए स्वतंत्र महसूस करें।

Dplyr की लचीलापन का भी अर्थ है कि आप एक ही वाक्यविन्यास का उपयोग करके प्रदर्शन विशेषताओं को आसानी से बदल सकते हैं। यदि डेटा फ्रेम बैकएंड के साथ dplyr का प्रदर्शन आपके लिए पर्याप्त नहीं है, तो आप डेटा.table बैकएंड का उपयोग कर सकते हैं (यद्यपि कार्यक्षमता के कुछ सीमित सेट के साथ)। यदि आप जिस डेटा के साथ काम कर रहे हैं वह स्मृति में फिट नहीं है, तो आप डेटाबेस बैकएंड का उपयोग कर सकते हैं।

जो कुछ भी कहा गया है, लंबे समय तक प्रदर्शन का प्रदर्शन बेहतर होगा। हम निश्चित रूप से डेटा के कुछ महान विचारों को लागू करेंगे जैसे रैडिक्स ऑर्डरिंग और जॉइन और फ़िल्टर के लिए एक ही इंडेक्स का उपयोग करना। हम समांतरता पर भी काम कर रहे हैं ताकि हम कई कोर का लाभ उठा सकें।

विशेषताएं

कुछ चीजें जिन्हें हम 2015 में काम करने की योजना बना रहे हैं:

  • readr पैकेज, फ़ाइलों को डिस्क से और मेमोरी में प्राप्त करना आसान बनाता है, जो readr fread() समान होता है।

  • गैर-इक्विटी-जॉइन के लिए समर्थन सहित अधिक लचीला जुड़ता है।

  • बूटस्ट्रैप नमूने, रोलअप और अधिक जैसे अधिक लचीला समूह

मैं आर के डेटाबेस कनेक्टर , वेब एपिस से बात करने की क्षमता, और एचटीएमएल पृष्ठों को स्क्रैप करना आसान बनाने में भी समय निवेश कर रहा हूं।


हमें व्यापक उत्तर / तुलना (महत्व के किसी विशेष क्रम में) प्रदान करने के लिए कम से कम इन पहलुओं को कवर करने की आवश्यकता नहीं है: Speed , Memory usage , Syntax और Features

मेरा इरादा डेटाटेबल परिप्रेक्ष्य से यथासंभव स्पष्ट रूप से इनमें से प्रत्येक को कवर करना है।

नोट: जब तक स्पष्ट रूप से अन्यथा स्पष्ट रूप से उल्लेख नहीं किया जाता है, तो dplyr का जिक्र करते हुए, हम dplyr के डेटा.फ्रेम इंटरफ़ेस का संदर्भ लेते हैं जिसका आंतरिक आरसीपीपी का उपयोग कर सी ++ में होता है।

डेटाटेबल सिंटैक्स इसके रूप में सुसंगत है - DT[i, j, by]i रखने के लिए, j और एक साथ डिजाइन द्वारा है। संबंधित परिचालनों को एक साथ रखते हुए, यह आसानी से गति के लिए संचालन को अनुकूलित करने और अधिक महत्वपूर्ण रूप से स्मृति उपयोग को अनुकूलित करने की अनुमति देता है, और सिंटैक्स में स्थिरता बनाए रखने के दौरान कुछ शक्तिशाली सुविधाएं भी प्रदान करता है।

1. गति

काफी हद तक कुछ बेंचमार्क (हालांकि ज्यादातर समूह संचालन पर) को पहले से ही डेटाटेबल को तेजी से दिखाया गया है, जो समूह और / या पंक्तियों के समूह में बढ़ोतरी के साथ तेजी से बढ़ता है, जिसमें मैट द्वारा 10 मिलियन से ग्रुपिंग में बेंचमार्क शामिल हैं। 100 - 10 मिलियन समूहों और विभिन्न समूह कॉलम पर 2 बिलियन पंक्तियां (रैम में 100 जीबी), जो pandas तुलना भी करती है।

बेंचमार्क पर, इन शेष पहलुओं को भी कवर करना बहुत अच्छा होगा:

  • समूहों के संचालन में पंक्तियों का एक सबसेट शामिल है - यानी, DT[x > val, sum(y), by = z] प्रकार के संचालन।

  • अपडेट और जुड़ने जैसे अन्य ऑपरेशंस बेंचमार्क।

  • रनटाइम के अलावा प्रत्येक ऑपरेशन के लिए मेमोरी पदचिह्न भी बेंचमार्क करें।

2. मेमोरी उपयोग

  1. Dplyr में filter() या slice() से जुड़े संचालन स्मृति अक्षम हैं (डेटा.फ्रेम और डेटाटेबल दोनों पर)। यह पोस्ट देखें ।

    ध्यान दें कि हैडली की टिप्पणी गति के बारे में बात करती है (वह डिपर उसके लिए काफी तेज़ है), जबकि यहां प्रमुख चिंता स्मृति है

  2. इस समय डेटाटेबल इंटरफ़ेस संदर्भ में कॉलम को संशोधित / अपडेट करने की अनुमति देता है (ध्यान दें कि हमें परिणाम को एक चर में फिर से असाइन करने की आवश्यकता नहीं है)।

    # sub-assign by reference, updates 'y' in-place
    DT[x >= 1L, y := NA]
    

    लेकिन dplyr संदर्भ द्वारा कभी अद्यतन नहीं होगा । द्विपक्षीय समकक्ष होगा (ध्यान दें कि परिणाम फिर से सौंपा जाना आवश्यक है):

    # copies the entire 'y' column
    ans <- DF %>% mutate(y = replace(y, which(x >= 1L), NA))
    

    इसके लिए एक चिंता पारदर्शी पारदर्शिता है । संदर्भ द्वारा डेटाटेबल ऑब्जेक्ट को अपडेट करना, खासकर किसी फ़ंक्शन के भीतर हमेशा वांछनीय नहीं हो सकता है। लेकिन यह एक अविश्वसनीय रूप से उपयोगी विशेषता है: दिलचस्प और मामलों के लिए this पोस्ट देखें। और हम इसे रखना चाहते हैं।

    इसलिए हम डेटा.table में shallow() फ़ंक्शन को निर्यात करने की दिशा में काम कर रहे हैं जो उपयोगकर्ता को दोनों संभावनाओं के साथ प्रदान करेगा। उदाहरण के लिए, यदि किसी फ़ंक्शन के भीतर इनपुट डेटा.table को संशोधित करना वांछनीय है, तो कोई भी ऐसा कर सकता है:

    foo <- function(DT) {
        DT = shallow(DT)          ## shallow copy DT
        DT[, newcol := 1L]        ## does not affect the original DT 
        DT[x > 2L, newcol := 2L]  ## no need to copy (internally), as this column exists only in shallow copied DT
        DT[x > 2L, x := 3L]       ## have to copy (like base R / dplyr does always); otherwise original DT will 
                                  ## also get modified.
    }
    

    shallow() का उपयोग न करके, पुरानी कार्यक्षमता बरकरार रखी जाती है:

    bar <- function(DT) {
        DT[, newcol := 1L]        ## old behaviour, original DT gets updated by reference
        DT[x > 2L, x := 3L]       ## old behaviour, update column x in original DT.
    }
    

    shallow() का उपयोग करके एक उथली प्रतिलिपि बनाकर, हम समझते हैं कि आप मूल वस्तु को संशोधित नहीं करना चाहते हैं। हम यह सुनिश्चित करने के लिए आंतरिक रूप से सब कुछ का ख्याल रखते हैं कि कॉलम कॉपी करने के दौरान भी आप केवल तभी संशोधित करते हैं जब यह बिल्कुल जरूरी हो । कार्यान्वित होने पर, उपयोगकर्ता को दोनों संभावनाओं के साथ प्रदान करते समय संदर्भित पारदर्शिता समस्या को पूरी तरह से व्यवस्थित करना चाहिए।

    इसके अलावा, एक बार shallow() को निर्यात किया जाता है dplyr का डेटा.table इंटरफेस लगभग सभी प्रतियों से बचना चाहिए। तो जो लोग dplyr के वाक्यविन्यास पसंद करते हैं, वे डेटा.tables के साथ इसका उपयोग कर सकते हैं।

    लेकिन इसमें अभी भी कई विशेषताओं की कमी होगी जो डेटाटेबल प्रदान करता है, जिसमें संदर्भ (उप) - संदर्भ द्वारा असाइनमेंट शामिल है।

  3. शामिल होने के दौरान कुल:

    मान लें कि आपके पास दो डेटाटेबल्स हैं:

    DT1 = data.table(x=c(1,1,1,1,2,2,2,2), y=c("a", "a", "b", "b"), z=1:8, key=c("x", "y"))
    #    x y z
    # 1: 1 a 1
    # 2: 1 a 2
    # 3: 1 b 3
    # 4: 1 b 4
    # 5: 2 a 5
    # 6: 2 a 6
    # 7: 2 b 7
    # 8: 2 b 8
    DT2 = data.table(x=1:2, y=c("a", "b"), mul=4:3, key=c("x", "y"))
    #    x y mul
    # 1: 1 a   4
    # 2: 2 b   3
    

    और कॉलम x,y द्वारा DT2 समय आप DT2 में प्रत्येक पंक्ति के लिए sum(z) * mul प्राप्त करना चाहते हैं। हम या तो कर सकते हैं:

    • 1) योग प्राप्त करने के लिए कुल DT1 1 sum(z) , 2) एक जॉइन करें और 3) गुणा करें (या)

      # data.table way
      DT1[, .(z = sum(z)), keyby = .(x,y)][DT2][, z := z*mul][]
      
      # dplyr equivalent
      DF1 %>% group_by(x, y) %>% summarise(z = sum(z)) %>% 
          right_join(DF2) %>% mutate(z = z * mul)
      
    • 2) यह सब एक ही में करें ( by = .EACHI सुविधा by = .EACHI उपयोग by = .EACHI ):

      DT1[DT2, list(z=sum(z) * mul), by = .EACHI]
      

    क्या फायदा है?

    • हमें मध्यवर्ती परिणाम के लिए स्मृति आवंटित करने की आवश्यकता नहीं है।

    • हमें दो बार समूह / हैश नहीं करना है (एकत्रीकरण के लिए एक और दूसरे शामिल होने के लिए)।

    • और सबसे महत्वपूर्ण बात यह है कि हम जो ऑपरेशन करना चाहते थे वह j (2) में देखकर स्पष्ट है।

    by = .EACHI विस्तृत स्पष्टीकरण के लिए इस पोस्ट को by = .EACHI । कोई मध्यवर्ती परिणाम भौतिक नहीं होते हैं, और शामिल + कुल योग एक ही समय में किया जाता है।

    वास्तविक उपयोग परिदृश्यों के लिए this और this पोस्ट देखें।

    dplyr आपको पहले शामिल होना और एकत्र करना या एकत्र करना होगा और फिर मेमोरी के मामले में, जिनमें से कोई भी कुशल नहीं है, में शामिल होना होगा (जो बदले में गति में अनुवाद करता है)।

  4. अपडेट करें और जुड़ें:

    नीचे दिखाए गए डेटाटेबल कोड पर विचार करें:

    DT1[DT2, col := i.mul]
    

    DT2 कॉलम col को उन पंक्तियों पर DT2 से mul साथ जोड़ता है जहां DT2 का मुख्य कॉलम DT2 मेल खाता है। मुझे नहीं लगता कि dplyr में इस ऑपरेशन का सटीक समतुल्य है, यानि, *_join ऑपरेशन से बचने के बिना, जिसे पूरे DT1 को कॉपी करने के लिए सिर्फ एक नया कॉलम जोड़ना होगा, जो अनावश्यक है।

    वास्तविक उपयोग परिदृश्य के लिए इस पोस्ट को देखें।

सारांशित करने के लिए, यह जानना महत्वपूर्ण है कि ऑप्टिमाइज़ेशन के हर बिट मायने रखता है। जैसा कि ग्रेस हूपर कहेंगे, अपने नैनोसेकंड को याद रखें !

3. सिंटेक्स

आइए अब वाक्यविन्यास देखें । हैडली ने here टिप्पणी की:

डेटा टेबल बेहद तेज़ हैं, लेकिन मुझे लगता है कि उनकी सहमति से सीखना मुश्किल हो जाता है और कोड का उपयोग करने के बाद इसे पढ़ना कठिन होता है ...

मुझे यह टिप्पणी व्यर्थ लगता है क्योंकि यह बहुत ही व्यक्तिपरक है। हम शायद कोशिश कर सकते हैं वाक्यविन्यास में स्थिरता के विपरीत है। हम डेटाटेबल और डिपर सिंटैक्स की तरफ से तुलना करेंगे।

हम नीचे दिखाए गए डमी डेटा के साथ काम करेंगे:

DT = data.table(x=1:10, y=11:20, z=rep(1:2, each=5))
DF = as.data.frame(DT)
  1. मूल एकत्रीकरण / अद्यतन संचालन।

    # case (a)
    DT[, sum(y), by = z]                       ## data.table syntax
    DF %>% group_by(z) %>% summarise(sum(y)) ## dplyr syntax
    DT[, y := cumsum(y), by = z]
    ans <- DF %>% group_by(z) %>% mutate(y = cumsum(y))
    
    # case (b)
    DT[x > 2, sum(y), by = z]
    DF %>% filter(x>2) %>% group_by(z) %>% summarise(sum(y))
    DT[x > 2, y := cumsum(y), by = z]
    ans <- DF %>% group_by(z) %>% mutate(y = replace(y, which(x > 2), cumsum(y)))
    
    # case (c)
    DT[, if(any(x > 5L)) y[1L]-y[2L] else y[2L], by = z]
    DF %>% group_by(z) %>% summarise(if (any(x > 5L)) y[1L] - y[2L] else y[2L])
    DT[, if(any(x > 5L)) y[1L] - y[2L], by = z]
    DF %>% group_by(z) %>% filter(any(x > 5L)) %>% summarise(y[1L] - y[2L])
    
    • data.table वाक्यविन्यास कॉम्पैक्ट और dplyr काफी verbose है। मामले (ए) में चीजें कम या ज्यादा बराबर होती हैं।

    • यदि (बी), संक्षेप में हमें dplyr में filter() का उपयोग करना पड़ा। लेकिन अद्यतन करते समय, हमें तर्क को mutate() अंदर ले जाना पड़ा। डेटाटेबल में हालांकि, हम दोनों परिचालनों को एक ही तर्क के साथ व्यक्त करते हैं - पंक्तियों पर काम करते हैं जहां x > 2 , लेकिन पहले मामले में, sum(y) , जबकि दूसरे मामले में उन पंक्तियों को अपने संचयी योग के साथ अद्यतन करें।

      जब हम कहते हैं कि DT[i, j, by] फ़ॉर्म सुसंगत है तो हमारा यही मतलब है

    • इसी प्रकार मामले में (सी), जब हमारे पास if-else शर्त है, तो हम डेटा.table और dplyr दोनों में "as-is" तर्क व्यक्त करने में सक्षम हैं। हालांकि, अगर हम केवल उन पंक्तियों को वापस करना चाहते हैं जहां if स्थिति अन्यथा संतुष्ट होती है और छोड़ती है, तो हम summarise() सीधे (AFAICT) का उपयोग नहीं कर सकते हैं। हमें पहले filter() पहले filter() और फिर सारांशित करना होगा क्योंकि summarise() हमेशा एक मान की अपेक्षा करता है।

      हालांकि यह वही परिणाम देता है, यहां filter() का उपयोग करके वास्तविक ऑपरेशन कम स्पष्ट होता है।

      पहले मामले में filter() का उपयोग करना भी संभव हो सकता है filter() साथ ही मुझे स्पष्ट नहीं लगता है), लेकिन मेरा मुद्दा यह है कि हमें यह नहीं करना चाहिए।

  2. एकाधिक कॉलम पर एकत्रीकरण / अद्यतन

    # case (a)
    DT[, lapply(.SD, sum), by = z]                     ## data.table syntax
    DF %>% group_by(z) %>% summarise_each(funs(sum)) ## dplyr syntax
    DT[, (cols) := lapply(.SD, sum), by = z]
    ans <- DF %>% group_by(z) %>% mutate_each(funs(sum))
    
    # case (b)
    DT[, c(lapply(.SD, sum), lapply(.SD, mean)), by = z]
    DF %>% group_by(z) %>% summarise_each(funs(sum, mean))
    
    # case (c)
    DT[, c(.N, lapply(.SD, sum)), by = z]     
    DF %>% group_by(z) %>% summarise_each(funs(n(), mean))
    
    • मामले में (ए), कोड कम या ज्यादा बराबर हैं। data.table परिचित बेस फ़ंक्शन lapply() का उपयोग करता है, जबकि dplyr funs() के कार्यों के समूह के साथ *_each() प्रस्तुत करता है।

    • data.table's := कॉलम नाम प्रदान किए जाने की आवश्यकता है, जबकि dplyr इसे स्वचालित रूप से उत्पन्न करता है।

    • मामले में (बी), dplyr का वाक्यविन्यास अपेक्षाकृत सरल है। एकाधिक कार्यों पर समेकन / अपडेट में सुधार डेटा.table की सूची पर है।

    • मामले में (सी) हालांकि, dplyr एक बार के बजाय, कई स्तंभों के रूप में कई बार n() वापस लौटाएगा। डेटाटेबल में, हमें केवल j में एक सूची वापस करने की ज़रूरत है। सूची का प्रत्येक तत्व परिणाम में एक कॉलम बन जाएगा। इसलिए, हम एक बार फिर से परिचित बेस फ़ंक्शन c() को एक साथ list करने के लिए परिचित बेस फ़ंक्शन c() का उपयोग कर सकते हैं।

    नोट: एक बार फिर, डेटा.table में, हमें केवल j में एक सूची वापस करने की ज़रूरत है। सूची का प्रत्येक तत्व परिणामस्वरूप एक कॉलम बन जाएगा। आप c() , as.list() , lapply() , list() आदि का उपयोग कर सकते हैं ... इसे पूरा करने के लिए आधार फ़ंक्शंस, बिना किसी नए फ़ंक्शन सीखने के।

    आपको केवल विशेष चर - .N और .N कम से कम सीखना होगा। Dplyr में समकक्ष n() और हैं .

  3. में शामिल

    dplyr प्रत्येक प्रकार के जॉइन के लिए अलग-अलग फ़ंक्शंस प्रदान करता है जहां डेटाटेबल एक ही वाक्यविन्यास DT[i, j, by] (और कारण के साथ) का उपयोग करने में शामिल हो जाता है। यह एक विकल्प के रूप में समतुल्य merge.data.table() फ़ंक्शन भी प्रदान करता है।

    setkey(DT1, x, y)
    
    # 1. normal join
    DT1[DT2]            ## data.table syntax
    left_join(DT2, DT1) ## dplyr syntax
    
    # 2. select columns while join    
    DT1[DT2, .(z, i.mul)]
    left_join(select(DT2, x, y, mul), select(DT1, x, y, z))
    
    # 3. aggregate while join
    DT1[DT2, .(sum(z) * i.mul), by = .EACHI]
    DF1 %>% group_by(x, y) %>% summarise(z = sum(z)) %>% 
        inner_join(DF2) %>% mutate(z = z*mul) %>% select(-mul)
    
    # 4. update while join
    DT1[DT2, z := cumsum(z) * i.mul, by = .EACHI]
    ??
    
    # 5. rolling join
    DT1[DT2, roll = -Inf]
    ??
    
    # 6. other arguments to control output
    DT1[DT2, mult = "first"]
    ??
    
    • कुछ लोगों के लिए एक अलग फ़ंक्शन मिल सकता है जो प्रत्येक में बहुत अच्छे (बाएं, दाएं, आंतरिक, विरोधी, अर्द्ध इत्यादि) शामिल होते हैं, जबकि अन्य डेटाटेबल के DT[i, j, by] , या merge() को आधार के समान हो सकते हैं आर

    • हालांकि dplyr बस यही करता है। और कुछ नहीं। कुछ भी कम नहीं।

    • data.tables (2) में शामिल होने के दौरान कॉलम का चयन कर सकते हैं, और dplyr में आपको ऊपर दिखाए गए अनुसार शामिल होने से पहले डेटा.फ्रेम दोनों पर पहले select() होगा। अन्यथा आप अनावश्यक कॉलम के साथ जुड़ने के लिए केवल बाद में उन्हें निकालने के लिए सामग्री का उपयोग करेंगे और यह अक्षम है।

    • डेटा.tables (3) में शामिल होने के दौरान एकत्र हो सकते हैं और by = .EACHI सुविधा by = .EACHI उपयोग (4) में शामिल होने के दौरान भी अपडेट कर सकते हैं। पूरे कॉलम को केवल कुछ कॉलम जोड़ने / अपडेट करने का परिणाम क्यों मिलता है?

    • data.table जुड़ने (5) रोल रोल करने में सक्षम है - रोल आगे, LOCF , रोल पिछड़ा, एनओसीबी , nearest ।

    • data.table में mult = तर्क भी है जो पहले , अंतिम या सभी मैचों का चयन करता है (6)।

    • data.table में आकस्मिक अमान्य allow.cartesian = TRUE से बचाने के लिए allow.cartesian = TRUE तर्क है।

एक बार फिर, वाक्यविन्यास DT[i, j, by] साथ संगत है जो अतिरिक्त तर्कों के साथ आउटपुट को नियंत्रित करने की अनुमति देता है।

  1. do() ...

    dplyr का संक्षेप विशेष रूप से उन कार्यों के लिए डिज़ाइन किया गया है जो एक एकल मान लौटाते हैं। यदि आपका फ़ंक्शन एकाधिक / असमान मान देता है, तो आपको करना होगा do() । आपको अपने सभी कार्यों के वापसी मूल्य के बारे में पहले से ही जानना होगा।

    DT[, list(x[1], y[1]), by = z]                 ## data.table syntax
    DF %>% group_by(z) %>% summarise(x[1], y[1]) ## dplyr syntax
    DT[, list(x[1:2], y[1]), by = z]
    DF %>% group_by(z) %>% do(data.frame(.$x[1:2], .$y[1]))
    
    DT[, quantile(x, 0.25), by = z]
    DF %>% group_by(z) %>% summarise(quantile(x, 0.25))
    DT[, quantile(x, c(0.25, 0.75)), by = z]
    DF %>% group_by(z) %>% do(data.frame(quantile(.$x, c(0.25, 0.75))))
    
    DT[, as.list(summary(x)), by = z]
    DF %>% group_by(z) %>% do(data.frame(as.list(summary(.$x))))
    
    • .SD के बराबर है .

    • डेटाटेबल में, आप j में बहुत कुछ फेंक सकते हैं - याद रखने वाली एकमात्र चीज़ यह है कि सूची को वापस लौटाएं ताकि सूची के प्रत्येक तत्व को कॉलम में परिवर्तित कर दिया जा सके।

    • Dplyr में, ऐसा नहीं कर सकता। यह सुनिश्चित करने के लिए कि आपका फ़ंक्शन हमेशा एक मान वापस करेगा या नहीं, इस पर निर्भर करता है कि आप do() का सहारा लेना चाहते हैं। और यह काफी धीमी है।

एक बार फिर, डेटाटेबल का वाक्यविन्यास DT[i, j, by] अनुरूप है। हम इन चीजों के बारे में चिंता किए बिना j में फेंकने की अभिव्यक्ति कर सकते हैं।

इस एसओ सवाल और इस पर एक नज़र डालें। मुझे आश्चर्य है कि उत्तर को dplyr के वाक्यविन्यास का उपयोग करके सीधा के रूप में व्यक्त करना संभव होगा ...

संक्षेप में, मैंने विशेष रूप से कई उदाहरणों को हाइलाइट किया है जहां ड्लीर का सिंटैक्स या तो अक्षम है, सीमित है या संचालन को सरल बनाने में विफल रहता है। यह विशेष रूप से इसलिए है क्योंकि डेटाटेबल को "पढ़ने के लिए कठिन / सीखना" वाक्यविन्यास (जैसा कि चिपकाया / ऊपर लिंक किया गया है) के बारे में काफी कुछ मिलता है। अधिकतर पोस्ट जो सबसे सरल संचालन के बारे में डिप्रर टॉक को कवर करते हैं। और यह बहुत अच्छा है। लेकिन इसके वाक्यविन्यास और फीचर सीमाओं को भी समझना महत्वपूर्ण है, और मुझे अभी तक एक पोस्ट देखने को मिला है।

data.table में इसके quirks भी हैं (जिनमें से कुछ मैंने इंगित किया है कि हम ठीक करने का प्रयास कर रहे हैं)। हम डेटाटेबल के जुड़ने में भी सुधार करने का प्रयास कर रहे हैं जैसा कि मैंने यहां हाइलाइट किया here ।

लेकिन किसी को डेटा.table की तुलना में dplyr की कमी की विशेषताओं पर भी विचार करना चाहिए।

4. विशेषताएं

मैंने यहां और यहां तक ​​कि इस पोस्ट में अधिकांश सुविधाओं की ओर इशारा किया है। के अतिरिक्त:

  • फ्रेड - फास्ट फाइल रीडर अब लंबे समय से उपलब्ध है।

  • fwrite - वर्तमान devel में v, v1.9.7, एक समानांतर फास्ट फ़ाइल लेखक अब उपलब्ध है। आगे के विकास को ट्रैक रखने के लिए कार्यान्वयन और #1664 पर विस्तृत स्पष्टीकरण के लिए इस पोस्ट को देखें।

  • स्वचालित अनुक्रमण - आधार आर सिंटैक्स को आंतरिक रूप से अनुकूलित करने के लिए एक और आसान सुविधा।

  • विज्ञापन-समूह समूह : summarise() , जो हमेशा वांछित नहीं हो सकता है, के दौरान चर को समूहीकृत करके स्वचालित रूप से परिणाम dplyr है।

  • डेटाटेबल में कई फायदे ऊपर वर्णित गति (स्मृति / स्मृति दक्षता और वाक्यविन्यास के लिए) शामिल हैं।

  • गैर- इक्की जुड़ता है : v1.9.7 + से उपलब्ध एक नई सुविधा है। यह डेटा ऑपरेट करने योग्य अन्य सभी फायदों के साथ अन्य ऑपरेटरों <=, <, >, >= का उपयोग करने में शामिल होने की अनुमति देता है।

  • ओवरलैपिंग रेंज जॉइन को हाल ही में डेटाटेबल में लागू किया गया था। बेंचमार्क के साथ एक सिंहावलोकन के लिए इस पोस्ट को देखें।

  • setorder() फ़ंक्शन जो संदर्भ द्वारा डेटा.tables की वास्तव में तेज़ी से पुन: समन्वय की अनुमति देता है।

  • dplyr उसी वाक्यविन्यास का उपयोग कर डेटाबेस में इंटरफ़ेस प्रदान करता है , जो डेटा.table इस समय नहीं है।

  • data.table v1.9.7 + (जेन गोरेकी द्वारा लिखित) से सेट ऑपरेशंस के तेज़ समकक्ष प्रदान करता है - अतिरिक्त all तर्क (जैसे SQL में) के साथ fsetdiff , fintersect , funion और fsetequal

  • डेटाटेबल बिना मास्किंग चेतावनियों के स्पष्ट रूप से लोड करता है और किसी भी आर पैकेज में पास होने पर [.data.frame संगतता के लिए here वर्णित एक तंत्र है। dplyr आधार कार्यों filter , lag और [ जो समस्याओं का कारण बन सकता है बदलता है; उदाहरण के लिए here और here ।

आखिरकार:

  • डेटाबेस पर - कोई कारण नहीं है कि डेटा.table समान इंटरफ़ेस प्रदान नहीं कर सकता है, लेकिन अब यह प्राथमिकता नहीं है। यदि उपयोगकर्ता उस सुविधा को बहुत पसंद करेंगे तो यह बंप हो सकता है .. सुनिश्चित नहीं है।

  • समांतरता पर - सबकुछ मुश्किल है, जब तक कोई आगे नहीं जाता और करता है। बेशक यह प्रयास करेगा (थ्रेड सुरक्षित होना)।

    • ओपनएमपी का उपयोग करके वृद्धिशील प्रदर्शन लाभ के लिए समय-समय पर ज्ञात भागों की समानांतरता की दिशा में प्रगति (v1.9.7 डेवेल में) की जा रही है।




dplyr