2012-07-18 18 views
59

मुझे लगता है कि मैं गलत तरीके से प्लीयर का उपयोग कर रहा हूं। क्या कोई मुझे बता सकता है कि यह 'कुशल' प्लीयर कोड है या नहीं?प्लीयर इतनी धीमी क्यों है?

require(plyr) 
plyr <- function(dd) ddply(dd, .(price), summarise, ss=sum(volume)) 

थोड़ा संदर्भ: मेरे पास कुछ बड़ी समेकन समस्याएं हैं और मैंने ध्यान दिया है कि वे प्रत्येक कुछ समय ले रहे थे। मुद्दों को हल करने की कोशिश में, मैं आर

में विभिन्न समेकन प्रक्रियाओं के प्रदर्शन में रूचि बन गया, मैंने कुछ समेकन विधियों का परीक्षण किया - और मुझे पूरे दिन इंतजार कर रहा था।

जब मुझे अंत में परिणाम मिल गए, तो मुझे प्लीयर विधि और दूसरों के बीच एक बड़ा अंतर मिला - जो मुझे लगता है कि मैंने कुछ गलत गलत किया है।

मैं कोड निम्नलिखित (मैंने सोचा था कि जब मैं उस पर था मैं नए dataframe पैकेज की जाँच चाहते हैं) भाग गया:

require(plyr) 
require(data.table) 
require(dataframe) 
require(rbenchmark) 
require(xts) 

plyr <- function(dd) ddply(dd, .(price), summarise, ss=sum(volume)) 
t.apply <- function(dd) unlist(tapply(dd$volume, dd$price, sum)) 
t.apply.x <- function(dd) unlist(tapply(dd[,2], dd[,1], sum)) 
l.apply <- function(dd) unlist(lapply(split(dd$volume, dd$price), sum)) 
l.apply.x <- function(dd) unlist(lapply(split(dd[,2], dd[,1]), sum)) 
b.y <- function(dd) unlist(by(dd$volume, dd$price, sum)) 
b.y.x <- function(dd) unlist(by(dd[,2], dd[,1], sum)) 
agg <- function(dd) aggregate(dd$volume, list(dd$price), sum) 
agg.x <- function(dd) aggregate(dd[,2], list(dd[,1]), sum) 
dtd <- function(dd) dd[, sum(volume), by=(price)] 

obs <- c(5e1, 5e2, 5e3, 5e4, 5e5, 5e6, 5e6, 5e7, 5e8) 
timS <- timeBasedSeq('20110101 083000/20120101 083000') 

bmkRL <- list(NULL) 

for (i in 1:5){ 
    tt <- timS[1:obs[i]] 

    for (j in 1:8){ 
    pxl <- seq(0.9, 1.1, by= (1.1 - 0.9)/floor(obs[i]/(11-j))) 
    px <- sample(pxl, length(tt), replace=TRUE) 
    vol <- rnorm(length(tt), 1000, 100) 

    d.df <- base::data.frame(time=tt, price=px, volume=vol) 
    d.dfp <- dataframe::data.frame(time=tt, price=px, volume=vol) 
    d.matrix <- as.matrix(d.df[,-1]) 
    d.dt <- data.table(d.df) 

    listLabel <- paste('i=',i, 'j=',j) 

    bmkRL[[listLabel]] <- benchmark(plyr(d.df), plyr(d.dfp), t.apply(d.df),  
         t.apply(d.dfp), t.apply.x(d.matrix), 
         l.apply(d.df), l.apply(d.dfp), l.apply.x(d.matrix), 
         b.y(d.df), b.y(d.dfp), b.y.x(d.matrix), agg(d.df), 
         agg(d.dfp), agg.x(d.matrix), dtd(d.dt), 
      columns =c('test', 'elapsed', 'relative'), 
      replications = 10, 
      order = 'elapsed') 
    } 
} 

परीक्षण 5e8 अप करने के लिए जाँच करने के लिए चाहिए था, लेकिन यह बहुत समय लगा - ज्यादातर प्लीयर के कारण। अंतिम तालिका 5e5 समस्या दिखाती है:

$`i= 5 j= 8` 
        test elapsed relative 
15   dtd(d.dt) 4.156 1.000000 
6  l.apply(d.df) 15.687 3.774543 
7  l.apply(d.dfp) 16.066 3.865736 
8 l.apply.x(d.matrix) 16.659 4.008422 
4  t.apply(d.dfp) 21.387 5.146054 
3  t.apply(d.df) 21.488 5.170356 
5 t.apply.x(d.matrix) 22.014 5.296920 
13   agg(d.dfp) 32.254 7.760828 
14  agg.x(d.matrix) 32.435 7.804379 
12   agg(d.df) 32.593 7.842397 
10   b.y(d.dfp) 98.006 23.581809 
11  b.y.x(d.matrix) 98.134 23.612608 
9   b.y(d.df) 98.337 23.661453 
1   plyr(d.df) 9384.135 2257.972810 
2   plyr(d.dfp) 9384.448 2258.048123 

क्या यह सही है? data.table से प्लीयर 2250x धीमी क्यों है? और नए डेटा फ्रेम पैकेज का उपयोग क्यों नहीं किया?

सत्र जानकारी है:

> sessionInfo() 
R version 2.15.1 (2012-06-22) 
Platform: x86_64-apple-darwin9.8.0/x86_64 (64-bit) 

locale: 
[1] en_US.UTF-8/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8 

attached base packages: 
[1] stats  graphics grDevices utils  datasets methods base  

other attached packages: 
[1] xts_0.8-6  zoo_1.7-7  rbenchmark_0.3 dataframe_2.5 data.table_1.8.1  plyr_1.7.1  

loaded via a namespace (and not attached): 
[1] grid_2.15.1 lattice_0.20-6 tools_2.15.1 
+3

अपेक्षाकृत सरल डेटा हेरफेर/एकत्रीकरण समस्याओं के लिए, मैं पाया है डेटा तालिका बहुत तेज किया जाना है। अगर यह ऐसा कर सकता है, तो मुझे आश्चर्य नहीं है कि यह स्पष्ट विजेता है। मैं इस पर टिप्पणी करने के लिए 'प्लीयर' के साथ पर्याप्त परिचित नहीं हूं। – Joshua

+1

क्या आपने 'plyr' और' data.table' के लिए प्रलेखन देखा है? अगर मुझे सही याद है, 'plyr' आधार-'R' 'data.frame के साथ काम करता है। 'data.table' कुंजी कॉलम का उपयोग करके, और संपूर्ण रेडिक्स सॉर्टिंग का उपयोग करके एक संपूर्ण भिन्न प्रतिनिधित्व का उपयोग करता है। यह इस तरह से डेटाबेस की तरह है। –

+0

मैंने देखा है - लेकिन इसे समझ नहीं सका। प्लीयर थोड़ा धीमा से अधिक है ... लागू परिवार, एजीजी, और बहुत जल्दी हैं - और वे आधार हैं। यही कारण है कि मुझे लगा कि मुझे प्लीयर के साथ कुछ रूकी त्रुटि करनी होगी। – ricardo

उत्तर

51

क्यों यह इतनी धीमी गति से है? एक छोटे से अनुसंधान एक अगस्त 2011 जहां @hadley, पैकेज लेखक, states

इस तरह कि ddply हमेशा डेटा फ्रेम के साथ काम करता है की एक खामी है से एक मेल समूह पोस्टिंग स्थित है। यदि आप डेटा.फ्रेम (क्योंकि डेटा.फ्रेम बहुत धीमी है) के बजाय सारांश का उपयोग करते हैं तो यह थोड़ा तेज़ होगा, लेकिन मैं अभी भी सोच रहा हूं कि ddply दृष्टिकोण की इस मौलिक सीमा को कैसे दूर किया जाए।


कुशल plyr कोड मैं या तो पता नहीं था जा रहा है के रूप में। परम परीक्षण और बेंच-मार्किंग के गुच्छा के बाद ऐसा लगता है कि हम बेहतर कर सकते हैं।

summarize() आपके आदेश में एक साधारण सहायक कार्य, शुद्ध और सरल है। हम इसे अपने स्वयं के योग समारोह से प्रतिस्थापित कर सकते हैं क्योंकि यह ऐसी किसी भी चीज़ की सहायता नहीं कर रहा है जो पहले से ही सरल नहीं है और .data और .(price) तर्क अधिक स्पष्ट किए जा सकते हैं। परिणाम

ddply(dd[, 2:3], ~price, function(x) sum(x$volume)) 

summarize अच्छा लग सकता है, लेकिन यह सिर्फ एक सरल समारोह कॉल की तुलना में तेज नहीं है। यह समझ में आता है; summarize के लिए code बनाम हमारे छोटे कार्य को देखें। संशोधित सूत्र के साथ अपने मानक को चलाने से एक उल्लेखनीय लाभ मिलता है। इसका अर्थ यह न लें कि आपने गलत तरीके से प्लीयर का उपयोग किया है, आपने नहीं किया है, यह केवल कुशल नहीं है; इसके साथ आप कुछ भी नहीं कर सकते हैं जितना इसे अन्य विकल्पों के रूप में तेज़ कर देगा।

मेरी राय में अनुकूलित फ़ंक्शन अभी भी चिपक गया है क्योंकि यह स्पष्ट नहीं है और डेटाटेबल (यहां तक ​​कि 60% लाभ के साथ) की तुलना में हास्यास्पद रूप से धीमा होने के साथ मानसिक रूप से पार्स किया जाना चाहिए।


ही thread ऊपर उल्लेख किया है, plyr की सुस्ती के बारे में, एक plyr2 परियोजना उल्लेख किया है। प्रश्न के मूल उत्तर के समय से प्लीयर लेखक ने dplyr को प्लीयर के उत्तराधिकारी के रूप में जारी किया है। जबकि दोनों प्लीयर और डिपर को डेटा मैनिपुलेशन टूल के रूप में बिल किया जाता है और आपकी प्राथमिक ब्याज ब्याज एकत्रीकरण है, फिर भी आप तुलना के लिए नए पैकेज के अपने बेंचमार्क परिणामों में दिलचस्पी ले सकते हैं क्योंकि इसमें प्रदर्शन में सुधार के लिए एक पुनर्वित्त बैकएंड है।

plyr_Original <- function(dd) ddply(dd, .(price), summarise, ss=sum(volume)) 
plyr_Optimized <- function(dd) ddply(dd[, 2:3], ~price, function(x) sum(x$volume)) 

dplyr <- function(dd) dd %.% group_by(price) %.% summarize(sum(volume))  

data_table <- function(dd) dd[, sum(volume), keyby=price] 

dataframe पैकेज परीक्षणों से क्रैन से और बाद में हटा दिया गया है, मैट्रिक्स समारोह संस्करणों के साथ।

यहाँ i=5, j=8 बेंचमार्क परिणाम है:

$`obs= 500,000 unique prices= 158,286 reps= 5` 
        test elapsed relative 
9  data_table(d.dt) 0.074 1.000 
4   dplyr(d.dt) 0.133 1.797 
3   dplyr(d.df) 1.832 24.757 
6  l.apply(d.df) 5.049 68.230 
5  t.apply(d.df) 8.078 109.162 
8   agg(d.df) 11.822 159.757 
7   b.y(d.df) 48.569 656.338 
2 plyr_Optimized(d.df) 148.030 2000.405 
1 plyr_Original(d.df) 401.890 5430.946 

कोई संदेह नहीं है अनुकूलन थोड़ा मदद की। d.df कार्यों पर एक नज़र डालें; वे सिर्फ प्रतिस्पर्धा नहीं कर सकते हैं।

डेटा.फ्रेम संरचना की धीमी गति पर थोड़ा परिप्रेक्ष्य के लिए यहां डेटा_टेबल के एकत्रीकरण समय और एक बड़े परीक्षण डेटासेट (i=8,j=8) का उपयोग करके dplyr के माइक्रो-बेंचमार्क हैं।

$`obs= 50,000,000 unique prices= 15,836,476 reps= 5` 
Unit: seconds 
      expr min  lq median  uq max neval 
data_table(d.dt) 1.190 1.193 1.198 1.460 1.574 10 
     dplyr(d.dt) 2.346 2.434 2.542 2.942 9.856 10 
     dplyr(d.df) 66.238 66.688 67.436 69.226 86.641 10 

data.frame अभी भी धूल में छोड़ दिया है। इतना ही नहीं, लेकिन यहाँ परीक्षण डाटा के साथ डाटा संरचनाओं को भरने के लिए बीता system.time है:

`d.df` (data.frame) 3.181 seconds. 
`d.dt` (data.table) 0.418 seconds. 

दोनों निर्माण और data.frame के एकत्रीकरण data.table की तुलना में धीमी है।

आर में data.frame के साथ कार्य करना कुछ विकल्प की तुलना में धीमी है, लेकिन जैसा कि बेंचमार्क दिखाने आर कार्यों में बनाया गया पानी से बाहर plyr उड़ा। यहां तक ​​कि डेटा.फ्रेम को डीप्लर के रूप में प्रबंधित करना, जो अंतर्निर्मित पर सुधार करता है, इष्टतम गति नहीं देता है; जहां डेटा.table तेजी से दोनों सृजन और एकत्रीकरण और डेटा.table डेटा/फ्रेम पर काम करते समय यह करता है।

अंत में ...

Plyr क्योंकि जिस तरह से यह साथ काम करता है और data.frame हेरफेर का प्रबंधन धीमी है।

[पंट :: मूल प्रश्नों पर टिप्पणियां देखें]।


## R version 3.0.2 (2013-09-25) 
## Platform: x86_64-pc-linux-gnu (64-bit) 
## 
## attached base packages: 
## [1] stats  graphics grDevices utils  datasets methods base  
## 
## other attached packages: 
## [1] microbenchmark_1.3-0 rbenchmark_1.0.0  xts_0.9-7   
## [4] zoo_1.7-11   data.table_1.9.2  dplyr_0.1.2   
## [7] plyr_1.8.1   knitr_1.5.22   
## 
## loaded via a namespace (and not attached): 
## [1] assertthat_0.1 evaluate_0.5.2 formatR_0.10.4 grid_3.0.2  
## [5] lattice_0.20-27 Rcpp_0.11.0  reshape2_1.2.2 stringr_0.6.2 
## [9] tools_3.0.2 

Data-Generating gist .rmd

+0

+1। अच्छे सुझाव धन्यवाद दोस्त। मैं आज आपके सुझाए गए 'प्लीयर' और 'डीसी' कोड के साथ परीक्षण फिर से चला रहा हूं। जब वे पूरा कर लेंगे तो मैं एक उत्तर पोस्ट करूंगा। मैंने थोड़ा सा चीजों को गति देने के लिए मैट्रिक्स बिट को छोड़ने का फैसला किया (जैसे कि मैट्रिक्स में डीएफ को ले जाना किसी भी तरह से जोड़ने वाला प्रतीत नहीं होता)। – ricardo

+0

मैंने यह जवाब स्वीकार कर लिया, जैसा कि ऐसा लगता है कि हम जहां तक ​​जा रहे हैं - जब तक हैडली चेक नहीं करना चाहता और 'प्लीर' के आंतरिक कार्यों को समझाता है। – ricardo

+3

@Thell चूंकि आपने आसानी से उपयोग का उल्लेख किया है, मैंने जोड़ा है कि 'dtd() वास्तव में क्या है, iiuc। कोई भी कैसे कह सकता है कि मुझे आसान नहीं है। लेकिन डेटाटेबल बैक एंड का उपयोग करके dplyr सीधे डेटा.table का उपयोग करने से धीमा है, तो? कैसे? –

संबंधित मुद्दे