Wo kann ich lernen, wie man C-Code zu beschleunigen langsame R-Funktionen zu schreiben? [geschlossen]

StackOverflow https://stackoverflow.com/questions/4106174

  •  29-09-2019
  •  | 
  •  

Frage

Was ist die beste Ressource für das Lernen, wie C-Code für die Verwendung mit R zu schreiben? Ich weiß um das System und Fremdsprachen Schnittstellen -Abschnitt von R-Erweiterungen, aber ich es ziemlich schwer finden gehen. Was sind gute Ressourcen (sowohl online als auch offline) für mit R-C-Code für das Schreiben?

Um klären, ich will nicht lernen, wie C-Code zu schreiben, möchte ich lernen, wie man besser R und C. Zum Beispiel integrieren, wie kann ich von einem C-Integer-Vektor zu einem R ganzzahligen Vektor konvertieren (oder umgekehrt), oder von einem C skalaren zu einem R-Vektor?

War es hilfreich?

Lösung

Nun, es ist die gute alte Verwenden Sie die Quelle, Luke! --- R selbst viel (sehr effizient) hat C-Code kann man studieren und CRAN hat Hunderte von Paketen, einige von den Autoren du vertraust. Das bietet real, getestet Beispiele zu studieren und sich anzupassen.

Aber wie Josh vermutet, lehne ich mich mehr in Richtung C ++ und damit RCPP . Es hat auch viele Beispiele.

Edit: Es gab zwei Bücher, die ich gefunden hilfreich:

  • Die erste ist Venables und Ripleys „ S Programmierung “, auch wenn es lange in dem Zahn wird immer (und es gibt Gerüchte über eine zweite Auflage seit Jahren). Zu der Zeit gab es einfach nichts anderes.
  • Die zweite in Chambers' ‚ Software für Datenanalyse ‘, die viel jünger ist und hat ein viel schöneres R-zentrierte Gefühl - und zwei Kapitel über die Verlängerung R. Sowohl C und C ++ erwähnt erhalten . Außerdem zerfetzt John mich für das, was ich getan habe mit verdauen so dass allein wert ist der Preis für Eintritt.

sagte, wächst John gern RCPP (und einen Beitrag), wie er findet, die Übereinstimmung zwischen R Objekten und C ++ Objekten (über RCPP ) sehr natürlich sein - und ReferenceClasses Hilfe gibt.

Edit 2: Mit Hadleys refokussierten Frage, ich sehr stark Sie fordern C ++ zu betrachten. Es gibt so viel Unsinn vorformulierten Sie mit C zu tun haben --- sehr mühsam und sehr vermeidbar . Werfen Sie einen Blick auf die RCPP-Einführung Vignette . Ein weiteres einfaches Beispiel ist dieses Blog-Post , wo ich zeigen, dass statt sich Gedanken über 10% Unterschiede (in einer der Radford Neal Beispiele) können wir erhalten eightyfold steigt mit C ++ (auf das, was natürlich ein konstruiertes Beispiel).

Bearbeiten 3: Es ist in Komplexität, dass Sie in C ++ Fehler führen können, die, um es milde auszudrücken, schwer zu grok. Aber nur verwenden RCPP , anstatt sie zu verlängern, sollten Sie so gut wie nie brauchen. Und während dieser Kosten ist nicht zu leugnen, ist es weit verfinstert durch den Nutzen von einfachen Code, weniger vorformulierten, kein PROTECT / FREIGABE, kein Memory-Management etc pp. Doug Bates gerade gestern erklärte, dass er wie das Schreiben R C ++ und RCPP sein viel mehr findet als C ++ zu schreiben. YMMV und so weiter.

Andere Tipps

Hadley,

Sie können auf jeden Fall C ++ Code schreiben, in C-Code ähnlich ist.

Ich verstehe, was Sie über C ++ sagen mehr ist kompliziert als C. Dies ist, wenn Sie zu meistern alles wollen: Objekte, Vorlagen, STL, Vorlage Meta-Programmierung, etc ... die meisten Leute brauchen nicht, diese Dinge und kann nur verlassen sich auf andere zu. Die Implementierung von RCPP ist sehr kompliziert, aber nur, weil Sie nicht wissen, wie Sie Ihren Kühlschrank funktioniert, bedeutet dies nicht, dass Sie nicht die Tür auf und greifen frische Milch öffnen kann ...

Von Ihrem viele Beiträge zu R, was mir auffällt, ist, dass Sie R etwas langweilig finden (Datenmanipulation, Grafiken, string manipulatio, etc ...). Nun erhalten vorbereitet für viele weiteren Überraschungen mit dem internen C-API von R. Das ist sehr mühsam.

Von Zeit zu Zeit las ich den R-exts oder R-Ints Handbücher. Das hilft. Aber die meiste Zeit, wenn ich will wirklich etwas herausfinden, gehe ich in die R-Quelle und auch in der Quelle der Pakete, beispielsweise durch schriftliche Simon (es gibt in der Regel viel dort zu lernen).

RCPP soll diese mühsamen Aspekte der API gehen weg zu machen.

Sie können selbst beurteilen, was Sie mehr kompliziert, verschleiert, etc. finden ... basierend auf ein paar Beispiele. Diese Funktion erstellt einen Charakter Vektor, der die 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);
}

Mit RCPP, können Sie die gleiche Funktion schreiben wie:

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

oder:

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

Wie Dirk sagte, gibt es andere Beispiele für die verschiedenen Vignetten. Wir in der Regel auch Menschen gegenüber unserer Unit-Tests zeigen, weil jeder von ihnen einen ganz bestimmten Teil des Codes testen und etwas selbsterklärend.

Ich bin hier offensichtlich voreingenommen, aber ich würde empfehlen, den C-API von R immer vertraut zu RCPP anstatt zu lernen, und dann in die Mailingliste kommen, wenn etwas unklar ist oder scheint nicht machbar mit RCPP.

Wie auch immer, Ende des Verkaufsargument.

Ich denke, es hängt alles davon, welche Art von Code, den Sie schließlich schreiben möchten.

Romain

@hadley: leider, ich habe keine bestimmten Ressourcen im Auge zu Hilfe, die Sie auf C ++ Einstieg. Ich hob es von Scott Meyers Bücher bis (Effective C ++, Effektivere C ++, etc ...), aber diese sind nicht wirklich das, was man nennen einleitenden könnte.

Wir verwenden fast ausschließlich die .Call Schnittstelle C ++ Code aufzurufen. Die Regel ist einfach genug:

  • Die C ++ Funktion muss ein R-Objekt zurück. Alle R-Objekte sind sexp.
  • Die C ++ Funktion nimmt zwischen 0 und 65 R-Objekte als Eingabe (wieder sexp)
  • muss (nicht wirklich, aber wir können dies für später speichern) mit C-Bindung erklärt werden, entweder mit extern "C" oder RcppExport alias dass RCPP definiert .

So eine .Call Funktion wie diese in einiger Header-Datei deklariert wird:

#include <Rcpp.h>

RcppExport SEXP foo( SEXP x1, SEXP x2 ) ;

und wie diese in einer CPP-Datei implementiert:

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

Es gibt nicht viel mehr zu wissen über den R-API RCPP werden.

Die meisten Menschen wollen nur mit numerischen Vektoren in RCPP beschäftigen. Sie tun dies mit der NumericVector Klasse. Es gibt mehrere Möglichkeiten, einen numerischen Vektor zu erstellen:

Von einem bestehenden Objekt, dass Sie von R überliefern:

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

Bei gegebenen Werten des :: create statische Funktion:

 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
 ) ;

Von einer bestimmten Größe:

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

Dann, wenn Sie einen Vektor haben, die nützlichste Sache ist, ein Element daraus zu extrahieren. Dies wird mit dem Operator getan [], mit 0-basierter Indizierung, so zum Beispiel Summieren Werten eines numerischen Vektor geht in etwa so:

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 ) ;
}

Aber mit RCPP Zucker können wir dies tun, viel schön jetzt:

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

Wie ich schon sagte, es hängt alles davon ab, welche Art von Code, den Sie schreiben möchten. Blick in das, was in den Paketen Menschen zu tun, die auf RCPP verlassen, überprüfen Sie die Vignetten, die Unit-Tests, kommen zu uns zurück auf der Mailingliste. Wir sind immer gerne zur Verfügung.

@jbremnant: Das ist richtig. RCPP Klassen etwas in der Nähe des RAH Muster implementieren. Wenn ein RCPP Objekt erstellt wird, nimmt der Konstruktor geeignete Maßnahmen, um die zugrundeliegenden R-Objekt (sexp), um sicherzustellen, vom Garbage Collector geschützt ist. Der destructor zieht den Schutz. Dies erklärt sich in der RCPP-Intrduction Vignette . Die zugrunde liegende Implementierung stützt sich auf den R-API-Funktionen R_PreserveObject und R_ReleaseObject

Es ist in der Tat Leistungseinbuße aufgrund von C ++ Kapselung. Wir versuchen, diese auf einem Minimum zu halten mit inlining, etc ... Die Strafe ist klein, und wenn Sie berücksichtigen die Verstärkung in Bezug auf die Zeit in Anspruch nimmt, es zu schreiben und Code zu erhalten, es ist nicht so relevant.

Beim R-Funktionen aus der RCPP Klasse Funktion ist langsamer als direkt eval mit dem C api aufrufen. Dies liegt daran, wir Vorkehrungen treffen, und wickeln Sie den Funktionsaufruf in einen TryCatch Block, so dass wir Capture R Fehler und fördern sie auf C ++ Ausnahmen, so dass sie unter Verwendung der Standard-try / catch in C ++ behandelt werden können.

Die meisten Menschen wollen zu verwenden Vektoren (speziell NumericVector), und die Strafe ist sehr klein mit dieser Klasse. Die Beispiele / ConvolveBenchmarks Verzeichnis enthält mehrere Varianten der notorischen Faltungsfunktion von R-exts und die Vignette hat Benchmark-Ergebnisse. Es stellt sich heraus, dass RCPP macht es schneller als der Benchmark-Code, der die R-API verwendet.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top