धीमे आर कार्यों को गति देने के लिए मैं सी कोड कैसे लिख सकता हूं? [बन्द है]


115

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

स्पष्ट करने के लिए, मैं सी कोड लिखना नहीं सीखना चाहता, मैं सीखना चाहता हूं कि आर और सी को बेहतर तरीके से कैसे एकीकृत किया जाए। उदाहरण के लिए, मैं एक पूर्णांक वेक्टर से एक आर पूर्णांक वेक्टर (या इसके विपरीत) में कैसे परिवर्तित करूं या C स्केलर से R वेक्टर तक?

जवाबों:


71

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

लेकिन जैसा कि जोश को संदेह था, मैं सी ++ की ओर अधिक झुक गया और इसलिए आरसीपीपी । इसके बहुत सारे उदाहरण भी हैं।

संपादित करें: दो किताबें थीं जो मुझे उपयोगी लगीं:

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

उस ने कहा, जॉन आरसीपी (और योगदान) के शौकीन हैं क्योंकि वह आर वस्तुओं और सी ++ वस्तुओं ( आरसीपीपी के माध्यम से ) के बीच मैच को बहुत स्वाभाविक मानते हैं - और रेफरेंसक्लास वहां मदद करते हैं।

संपादित करें 2: हैडली के परिष्कृत प्रश्न के साथ, मैं आपको C ++ पर विचार करने के लिए बहुत जोर देता हूं। वहाँ बहुत बॉयलरप्लेन बकवास है जो आपको सी के साथ करना है --- बहुत थकाऊ और बहुत परिहार्यRcpp- परिचय विगनेट पर एक नजर है । एक और सरल उदाहरण यह ब्लॉग पोस्ट है, जहां मैं दिखाता हूं कि 10% अंतर (रेडफोर्ड नील उदाहरणों में से एक) में चिंता करने के बजाय हम C ++ के साथ अस्सी गुना बढ़ सकते हैं (जो निश्चित रूप से एक आकस्मिक उदाहरण है)।

संपादित करें 3: इसमें जटिलता है कि आप C ++ त्रुटियों में भाग सकते हैं, जो कि इसे हल्का करने के लिए है, मुश्किल से इसे करना है। लेकिन इसका विस्तार करने के बजाय केवल Rcpp का उपयोग करने के लिए, आपको शायद ही कभी इसकी आवश्यकता होनी चाहिए। और जबकि यह लागत निर्विवाद है, इसे सरल कोड, कम बॉयलरप्लेट, कोई PROTECT / UNPROTECT, कोई स्मृति प्रबंधन आदि पीपी के लाभ से ग्रहण नहीं किया गया है । डौग बेट्स ने कल ही कहा था कि वह ++ और Rcpp को R लिखने की तरह बहुत अधिक मानते हैं। C ++ लिखने से। YMMV और वह सब।


मुझे उम्मीद है कि मुझे "Rcpp का उपयोग करें" उत्तर मिल जाएगा;) यह वास्तव में उपयोगी होगा यदि आप सी के बजाय सी ++ का उपयोग करने के नुकसान को समझ सकते हैं। यह उपयोग करने के लिए कठिन है? (या व्यवहार में, क्या आप C ++ कोड लिख सकते हैं जो C के समान है?) मैं नए उपयोगकर्ताओं के लिए अधिक संदर्भ सामग्री की भी सराहना करूंगा, जो मौजूदा C api से परिचित नहीं हैं।
हैडले

2
संपादित करें 3 देखें और हाँ, आप कर सकते हैं । मेयर्स C ++ को 'चार प्रतिमान' भाषा कहते हैं और आपको इन चारों का उपयोग करने की आवश्यकता नहीं है। इसे 'सिर्फ एक बेहतर सी' के रूप में उपयोग करना और आरसीपी को गोंद के रूप में आर का उपयोग करना पूरी तरह से ठीक है। कोई भी आप पर एक शैली के लिए मजबूर नहीं करता है - यह जावा ;-) नहीं है
डिर्क एडल्डबुलेटेल

@Dirk: विस्तार के लिए thx। इसने हमारे कार्यालय में पहले भी सवाल उठाया था, क्योंकि आमतौर पर C ++ के बजाय यहाँ C का उपयोग किया जाता है। C ++ से अधिक C का उपयोग कब फायदेमंद होगा, या आप बस "कभी C, हमेशा C ++" कहते हैं?
जोरिस मेय्स

हैडली: कूल। हमें आपकी प्रतिक्रिया में बहुत रुचि होगी। कृपया rcpp-devel में शामिल हों और पीछे न हटें। हम जानते हैं कि हम संक्षिप्त दस्तावेज हैं - लेकिन आँखों का एक नया सेट काफी मदद कर सकता है।
डिर्क एडल्डबुलेटेल

6
@ अहदले का मतलब है कि हम कुछ गति में सुधार की उम्मीद कर सकते हैं ggplot?
एएल

56

हेडली

आप निश्चित रूप से C ++ कोड लिख सकते हैं जो C कोड के समान है।

मैं समझता हूं कि आप C ++ के बारे में सी से अधिक जटिल होने के बारे में क्या कहते हैं। यह है कि यदि आप हर चीज में महारत हासिल करना चाहते हैं: ऑब्जेक्ट, टेम्प्लेट, एसटीएल, टेम्प्लेट मेटा प्रोग्रामिंग, आदि ... ज्यादातर लोगों को इन चीजों की आवश्यकता नहीं है और बस दूसरों पर भरोसा कर सकते हैं यह करने के लिए। Rcpp का कार्यान्वयन बहुत जटिल है, लेकिन सिर्फ इसलिए कि आप नहीं जानते कि आपका फ्रिज कैसे काम करता है, इसका मतलब यह नहीं है कि आप दरवाजा नहीं खोल सकते हैं और ताजा दूध नहीं ले सकते हैं ...

R के लिए आपके कई योगदानों से, जो मुझे प्रभावित करता है वह यह है कि आप R को कुछ थकाऊ (डेटा हेरफेर, ग्राफिक्स, स्ट्रिंग मैनिपुलेटिव, आदि ...) पाते हैं। खैर आर के आंतरिक सी एपीआई के साथ और अधिक आश्चर्य के लिए तैयार हो जाओ। यह बहुत थकाऊ है।

समय-समय पर, मैं आर-एक्सटीएस या आर-इन्ट्स मैनुअल पढ़ता हूं। इससे मदद मिलती है। लेकिन ज्यादातर समय, जब मैं वास्तव में किसी चीज के बारे में पता लगाना चाहता हूं, तो मैं आर स्रोत में जाता हूं, और उदाहरण के लिए साइमन द्वारा लिखे गए पैकेजों के स्रोत में भी (वहां आमतौर पर सीखने के लिए बहुत कुछ है)।

Rcpp को एपीआई के इन थकाऊ पहलुओं को दूर करने के लिए डिज़ाइन किया गया है।

आप स्वयं के लिए न्याय कर सकते हैं कि आपको कुछ उदाहरणों के आधार पर और अधिक जटिल, अस्पष्ट, आदि क्या मिला ... यह फ़ंक्शन C API का उपयोग करके एक वर्ण वेक्टर बनाता है:

SEXP foobar(){
  SEXP ab;
  PROTECT(ab = allocVector(STRSXP, 2));
  SET_STRING_ELT( ab, 0, mkChar("foo") );
  SET_STRING_ELT( ab, 1, mkChar("bar") );
  UNPROTECT(1);
}

Rcpp का उपयोग करते हुए, आप समान फ़ंक्शन लिख सकते हैं:

SEXP foobar(){
   return Rcpp::CharacterVector::create( "foo", "bar" ) ;
}

या:

SEXP foobar(){
   Rcpp::CharacterVector res(2) ;
   res[0] = "foo" ;
   res[1] = "bar" ;
   return res ;
}

जैसा कि डिर्क ने कहा, कई विगनेट्स पर अन्य उदाहरण हैं। हम आमतौर पर लोगों को अपनी इकाई परीक्षणों की ओर भी इशारा करते हैं क्योंकि उनमें से प्रत्येक कोड के एक बहुत विशिष्ट हिस्से का परीक्षण करते हैं और कुछ हद तक आत्म व्याख्यात्मक हैं।

मैं स्पष्ट रूप से यहाँ पक्षपाती हूँ, लेकिन मैं R के C API को सीखने के बजाय Rcpp के बारे में परिचित होने की सलाह दूंगा, और यदि कुछ अस्पष्ट है या Rcpp के साथ उचित नहीं लगता है, तो मेलिंग सूची में आएं।

वैसे भी, बिक्री पिच का अंत।

मुझे लगता है कि यह सब निर्भर करता है कि आप आखिरकार किस तरह का कोड लिखना चाहते हैं।

रोमेन


2
"Rcpp को एपीआई के इन थकाऊ पहलुओं को बनाने के लिए डिज़ाइन किया गया है" = ठीक वही है जो मैं देख रहा हूँ। धन्यवाद! जो वास्तव में उपयोगी होगा, वह v। संक्षिप्त C ++ प्राइमर होगा जो C से परिचित है और Rcpp का उपयोग करना चाहता है।
हैडले

अच्छा, Rcpp का वह संक्षिप्त उदाहरण मुझे बेच दिया गया। मैं आबंटित एक्सएक्सएक्स और UNPROTECT (1) को संभाल रहा हूं, जैसे कि स्मार्ट संकेत संसाधन का प्रबंधन करते हैं। यानी RAII। क्या वेनिला सी आपी पर Rcpp का उपयोग करके कोई उल्लेखनीय प्रदर्शन जुर्माना है?
jbremnant

हम पता करते हैं कि आरसीपीपी-परिचय में एक बेंचमार्क उदाहरण के साथ (जो कि स्रोतों / स्थापित पैकेज में भी है)। संक्षेप में, कोई जुर्माना नहीं।
डिर्क एडल्डबुलेटेल

29

@ खादी: दुर्भाग्य से, आपके पास C ++ को शुरू करने में मदद करने के लिए मेरे पास विशिष्ट संसाधन नहीं हैं। मैंने इसे स्कॉट मेयर्स की पुस्तकों (प्रभावी सी ++, अधिक प्रभावी सी ++, आदि ...) से उठाया था, लेकिन ये वास्तव में नहीं हैं जिसे कोई परिचयात्मक कह सकता है।

C ++ कोड को कॉल करने के लिए हम लगभग विशेष रूप से .Call इंटरफ़ेस का उपयोग करते हैं। नियम काफी आसान है:

  • C ++ फ़ंक्शन को R ऑब्जेक्ट वापस करना होगा। सभी R ऑब्जेक्ट SEXP हैं।
  • C ++ फ़ंक्शन इनपुट के रूप में 0 और 65 आर ऑब्जेक्ट्स के बीच लेता है (फिर से SEXP)
  • यह (वास्तव में नहीं है, लेकिन हम इसे बाद के लिए बचा सकते हैं) सी लिंकेज के साथ घोषित किया जा सकता है, या तो एक्सटर्नल "सी" या आरसीपीएक्सपोर्ट उर्फ कि आरसीपी को परिभाषित करता है।

तो .Call फ़ंक्शन को कुछ हेडर फ़ाइल में इस तरह घोषित किया जाता है:

#include <Rcpp.h>

RcppExport SEXP foo( SEXP x1, SEXP x2 ) ;

और एक .cpp फ़ाइल में इस तरह लागू किया गया:

SEXP foo( SEXP x1, SEXP x2 ){
   ...
}

Rcpp का उपयोग करने के लिए R API के बारे में जानने के लिए बहुत कुछ नहीं है।

ज्यादातर लोग केवल Rcpp में संख्यात्मक वैक्टर से निपटना चाहते हैं। आप इसे NumericVector वर्ग के साथ करते हैं। संख्यात्मक वेक्टर बनाने के कई तरीके हैं:

किसी मौजूदा ऑब्जेक्ट से जो आप R से नीचे जाते हैं:

 SEXP foo( SEXP x_) {
    Rcpp::NumericVector x( x_ ) ;
    ...
 }

दिए गए मानों के साथ :: स्थैतिक समारोह बनाएँ:

 Rcpp::NumericVector x = Rcpp::NumericVector::create( 1.0, 2.0, 3.0 ) ;
 Rcpp::NumericVector x = Rcpp::NumericVector::create( 
    _["a"] = 1.0, 
    _["b"] = 2.0, 
    _["c"] = 3
 ) ;

दिए गए आकार में से:

 Rcpp::NumericVector x( 10 ) ;      // filled with 0.0
 Rcpp::NumericVector x( 10, 2.0 ) ; // filled with 2.0

फिर एक बार जब आपके पास एक वेक्टर होता है, तो सबसे उपयोगी चीज इसमें से एक तत्व निकालना है। यह 0-आधारित अनुक्रमण के साथ ऑपरेटर [] के साथ किया जाता है, इसलिए उदाहरण के लिए एक संख्यात्मक वेक्टर का मान कुछ इस तरह से होता है:

SEXP sum( SEXP x_ ){
   Rcpp::NumericVector x(x_) ;
   double res = 0.0 ;
   for( int i=0; i<x.size(), i++){
      res += x[i] ;
   }
   return Rcpp::wrap( res ) ;
}

लेकिन Rcpp चीनी के साथ हम इसे अभी और अच्छी तरह से कर सकते हैं:

using namespace Rcpp ;
SEXP sum( SEXP x_ ){
   NumericVector x(x_) ;
   double res = sum( x ) ;
   return wrap( res ) ;
}

जैसा कि मैंने पहले कहा था, यह सब इस बात पर निर्भर करता है कि आप किस तरह का कोड लिखना चाहते हैं। देखें कि लोग Rcpp पर भरोसा करने वाले पैकेजों में क्या करते हैं, विगनेट्स, यूनिट परीक्षणों की जांच करें, मेलिंग सूची पर हमारे पास वापस आएं। हमें हमेशा मदद करके खुशी होती हैं।


20

@jbremnant: यह सही है। आरसीपी कक्षाएं आरएआई पैटर्न के करीब कुछ लागू करती हैं। जब एक आरसीपी ऑब्जेक्ट बनाया जाता है, तो निर्माणकर्ता यह सुनिश्चित करने के लिए उचित उपाय करता है कि अंतर्निहित आर ऑब्जेक्ट (एसईएक्सपी) कचरा कलेक्टर से सुरक्षित है। विध्वंसक सुरक्षा वापस ले लेता है। इसे Rcpp-intrduction vignette में समझाया गया है । अंतर्निहित कार्यान्वयन R API फ़ंक्शन R_PreserveObject और R_ReleaseObject पर निर्भर करता है

C ++ एन्कैप्सुलेशन के कारण वास्तव में प्रदर्शन जुर्माना है। हम इसे कम से कम इनलाइनिंग के साथ रखने की कोशिश करते हैं, आदि ... जुर्माना छोटा है, और जब आप कोड लिखने और बनाए रखने में लगने वाले समय के लाभ को ध्यान में रखते हैं, तो यह उतना प्रासंगिक नहीं है।

Rcpp वर्ग फ़ंक्शन से R फ़ंक्शन को कॉल करना C api के साथ सीधे कॉलिंग की तुलना में धीमा है। ऐसा इसलिए है क्योंकि हम सावधानी बरतते हैं और फ़ंक्शन कॉल को एक tryCatch ब्लॉक में लपेटते हैं ताकि हम R त्रुटियों को पकड़ें और उन्हें C ++ अपवादों में बढ़ावा दें, ताकि उन्हें C ++ में मानक कोशिश / कैच का उपयोग करके निपटा जा सके।

अधिकांश लोग वैक्टर (विशेष रूप से न्यूमेरिकवेक्टर) का उपयोग करना चाहते हैं, और इस वर्ग के साथ दंड बहुत छोटा है। उदाहरण / ConvolveBenchmark निर्देशिका में R-exts से कुख्यात कनवल्शन फंक्शन के कई वेरिएंट हैं और विग्नेट में बेंचमार्क परिणाम हैं। यह पता चला है कि Rcpp इसे बेंचमार्क कोड की तुलना में तेज बनाता है जो R API का उपयोग करता है।

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