2015-06-23 15 views
5

कैसे समझा जा सकता है पहले से समेकित डेटा के लिए कुछ नमूनाकरण कार्यों को बनाने की प्रक्रिया में मैंने पाया कि तालिका उस आकार डेटा पर धीमी थी जो मैं काम कर रहा हूं। मैं के रूप मेंटैबलेट का आरसीपीपी संस्करण धीमा है; यह कहां से है,

// [[Rcpp::export]] 
IntegerVector getcts(NumericVector x, int m) { 
    IntegerVector cts(m); 
    int t; 
    for (int i = 0; i < x.length(); i++) { 
    t = x[i] - 1; 
    if (0 <= t && t < m) 
     cts[t]++; 
    } 
    return cts; 
} 

इस प्रकार है और फिर समझने के लिए क्यों तालिका बल्कि मैंने पाया यह सारणीबद्ध के आधार पर की जा रही धीमी गति से किया गया था की कोशिश कर रहा है, जबकि दोनों के सुधार, पहले एक Rcpp समारोह की कोशिश की। Tabulate मेरे लिए अच्छी तरह से काम करता है, और आरसीपीपी संस्करण से तेज है। सारणीबद्ध के लिए कोड है पर:

https://github.com/wch/r-source/blob/545d365bd0485e5f0913a7d609c2c21d1f43145a/src/main/util.c#L2204

कुंजी लाइन किया जा रहा है के साथ

:

for(R_xlen_t i = 0 ; i < n ; i++) 
    if (x[i] != NA_INTEGER && x[i] > 0 && x[i] <= nb) y[x[i] - 1]++; 

अब सारणीबद्ध के मुख्य भागों और मेरे Rcpp संस्करण बहुत करीब लगते हैं (मैं एनए के साथ काम कर परेशान नहीं है)।

प्रश्न 1: मेरा आरसीपीपी संस्करण 3 गुना धीमा क्यों है?

प्रश्न 2: मैं यह कहां जा सकता हूं कि यह समय कहां जाता है?

मुझे यह जानने की बहुत सराहना होगी कि समय कहां गया, लेकिन कोड को प्रोफ़ाइल करने का एक अच्छा तरीका भी बेहतर होगा। मेरे सी ++ कौशल केवल इतना ही हैं, लेकिन यह इतना आसान लगता है कि मुझे (मेरी उंगलियों को पार करना) किसी भी मूर्खतापूर्ण सामान से बचने में सक्षम रहा है जो मेरे समय को तीन गुना करेगा।

मेरे समय कोड:

max_x <- 100 
xs <- sample(seq(max_x), size = 50000000, replace = TRUE) 
system.time(getcts(xs, max_x)) 
system.time(tabulate(xs)) 

यह सारणीबद्ध के लिए getcts के लिए 0.318 और 0.126 देता है।

+2

लेखन आर एक्सटेंशन मैनुअल में प्रोफाइलिंग के बारे में कुछ नोट हैं जो आपकी मदद कर सकते हैं। –

उत्तर

4

आपका फ़ंक्शन प्रत्येक लूप पुनरावृत्ति में length विधि को कॉल करता है। लगता है संकलक इसे कैश नहीं करते हैं। वेक्टर के इस स्टोर आकार को एक अलग चर में या श्रेणी आधारित लूप का उपयोग करने के लिए। यह भी ध्यान रखें कि हमें वास्तव में स्पष्ट लापता मूल्यों की जांच की आवश्यकता नहीं है क्योंकि C++ में NaN से संबंधित सभी तुलनाओं में हमेशा false वापस आते हैं।

के प्रदर्शन की तुलना करते हैं:

#include <Rcpp.h> 
using namespace Rcpp; 

// [[Rcpp::export]] 
IntegerVector tabulate1(const IntegerVector& x, const unsigned max) { 
    IntegerVector counts(max); 
    for (std::size_t i = 0; i < x.size(); i++) { 
     if (x[i] > 0 && x[i] <= max) 
      counts[x[i] - 1]++; 
    } 
    return counts; 
} 

// [[Rcpp::export]] 
IntegerVector tabulate2(const IntegerVector& x, const unsigned max) { 
    IntegerVector counts(max); 
    std::size_t n = x.size(); 
    for (std::size_t i = 0; i < n; i++) { 
     if (x[i] > 0 && x[i] <= max) 
      counts[x[i] - 1]++; 
    } 
    return counts; 
} 

// [[Rcpp::plugins(cpp11)]] 
// [[Rcpp::export]] 
IntegerVector tabulate3(const IntegerVector& x, const unsigned max) { 
    IntegerVector counts(max); 
    for (auto& now : x) { 
     if (now > 0 && now <= max) 
      counts[now - 1]++; 
    } 
    return counts; 
} 

// [[Rcpp::plugins(cpp11)]] 
// [[Rcpp::export]] 
IntegerVector tabulate4(const IntegerVector& x, const unsigned max) { 
    IntegerVector counts(max); 
    for (auto it = x.begin(); it != x.end(); it++) { 
     if (*it > 0 && *it <= max) 
      counts[*it - 1]++; 
    } 
    return counts; 
} 

/***R 
library(microbenchmark) 
x <- sample(10, 1e5, rep = TRUE) 
microbenchmark(
    tabulate(x, 10), tabulate1(x, 10), 
    tabulate2(x, 10), tabulate3(x, 10), tabulate4(x, 10) 
) 
x[sample(10e5, 10e3)] <- NA 
microbenchmark(
    tabulate(x, 10), tabulate1(x, 10), 
    tabulate2(x, 10), tabulate3(x, 10), tabulate4(x, 10) 
) 
*/ 

tabulate1 मूल संस्करण है।

बेंचमार्क परिणाम:

NA के बिना:

Unit: microseconds 
      expr  min  lq  mean median  uq  max neval 
tabulate(x, 10) 143.557 146.8355 169.2820 156.1970 177.327 286.370 100 
tabulate1(x, 10) 390.706 392.6045 437.7357 416.5655 443.065 748.767 100 
tabulate2(x, 10) 108.149 111.4345 139.7579 118.2735 153.118 337.647 100 
tabulate3(x, 10) 107.879 111.7305 138.2711 118.8650 139.598 300.023 100 
tabulate4(x, 10) 391.003 393.4530 436.3063 420.1915 444.048 777.862 100 

NA के साथ:

Unit: microseconds 
      expr  min  lq  mean median  uq  max neval 
tabulate(x, 10) 943.555 1089.5200 1614.804 1333.806 2042.320 3986.836 100 
tabulate1(x, 10) 4523.076 4787.3745 5258.490 4929.586 5624.098 7233.029 100 
tabulate2(x, 10) 765.102 931.9935 1361.747 1113.550 1679.024 3436.356 100 
tabulate3(x, 10) 773.358 914.4980 1350.164 1140.018 1642.354 3633.429 100 
tabulate4(x, 10) 4241.025 4466.8735 4933.672 4717.016 5148.842 8603.838 100 

tabulate4 समारोह जो पुनरावर्तक भी tabulate की तुलना में धीमी उपयोग करता है। हम इसे सुधार सकते हैं:

// [[Rcpp::plugins(cpp11)]] 
// [[Rcpp::export]] 
IntegerVector tabulate4(const IntegerVector& x, const unsigned max) { 
    IntegerVector counts(max); 
    auto start = x.begin(); 
    auto end = x.end(); 
    for (auto it = start; it != end; it++) { 
     if (*(it) > 0 && *(it) <= max) 
      counts[*(it) - 1]++; 
    } 
    return counts; 
} 
संबंधित मुद्दे