Nun, da ist der gute alte. Benutze die Quelle, Luke! --- R selbst hat viel (sehr effizienten) C-Code, den man studieren kann, und CRAN hat Hunderte von Paketen, einige von Autoren, denen Sie vertrauen. Das liefert echte, getestete Beispiele zum Studieren und Anpassen.
Aber wie Josh vermutet hat, neige ich mehr zu C ++ und damit zu Rcpp . Es gibt auch viele Beispiele.
Edit: Es gab zwei Bücher, die ich hilfreich fand:
- Das erste ist Venables und Ripleys " S Programming ", obwohl es immer länger wird (und es gibt Gerüchte über eine 2. Ausgabe seit Jahren). Zu der Zeit gab es einfach nichts anderes.
- Die zweite in Chambers '" Software for Data Analysis ", die viel jünger ist und ein viel besseres R-zentriertes Gefühl hat - und zwei Kapitel über die Erweiterung von R. Sowohl C als auch C ++ werden erwähnt. Außerdem zerfetzt John mich für das, was ich mit Digest gemacht habe, so dass allein der Eintrittspreis wert ist.
Trotzdem liebt John Rcpp (und trägt dazu bei), da er die Übereinstimmung zwischen R-Objekten und C ++ - Objekten (über Rcpp ) als sehr natürlich ansieht - und ReferenceClasses helfen dort.
Edit 2: Mit Hadleys refokussierten Frage, ich sehr stark fordere Sie auf C ++ zu betrachten. Es gibt so viel Unsinn auf der Kesselplatte, dass Sie mit C zu tun haben - sehr langweilig und sehr vermeidbar . Schauen Sie sich die Rcpp-Einführungsvignette an . Ein weiteres einfaches Beispiel ist dieser Blog-Beitrag, in dem ich zeige, dass wir, anstatt uns um 10% Unterschiede zu sorgen (in einem der Radford Neal-Beispiele), mit C ++ eine achtzigfache Steigerung erzielen können (was natürlich ein erfundenes Beispiel ist).
Bearbeiten 3: Es besteht Komplexität darin, dass Sie möglicherweise auf C ++ - Fehler stoßen, die, gelinde gesagt, schwer zu verstehen sind. Aber um Rcpp nur zu verwenden, anstatt es zu erweitern, sollten Sie es kaum jemals brauchen. Und obwohl diese Kosten nicht zu leugnen sind, werden sie durch den Vorteil von einfacherem Code, weniger Boilerplate, keinem PROTECT / UNPROTECT, keiner Speicherverwaltung usw. in den Schatten gestellt. Doug Bates erklärte erst gestern, dass C ++ und Rcpp dem Schreiben von R viel ähnlicher sind als C ++ zu schreiben. YMMV und das alles.
ggplot
?Hadley,
Sie können definitiv C ++ - Code schreiben, der dem C-Code ähnlich ist.
Ich verstehe, was Sie über C ++ sagen, das komplizierter als C ist. Dies ist, wenn Sie alles beherrschen möchten: Objekte, Vorlagen, STL, Vorlagen-Metaprogrammierung usw. Die meisten Menschen brauchen diese Dinge nicht und können sich einfach auf andere verlassen dazu. Die Implementierung von Rcpp ist sehr kompliziert, aber nur weil Sie nicht wissen, wie Ihr Kühlschrank funktioniert, heißt das nicht, dass Sie die Tür nicht öffnen und frische Milch holen können ...
Aus Ihren vielen Beiträgen zu R fällt mir auf, dass Sie R etwas langweilig finden (Datenmanipulation, Grafiken, String-Manipulation usw.). Bereiten Sie sich mit der internen C-API von R auf viele weitere Überraschungen vor. Dies ist sehr mühsam.
Von Zeit zu Zeit las ich die R-Exts- oder R-Ints-Handbücher. Das hilft. Aber die meiste Zeit, wenn ich wirklich etwas herausfinden möchte, gehe ich in die R-Quelle und auch in die Quelle von Paketen, die zB Simon geschrieben hat (dort gibt es normalerweise viel zu lernen).
Rcpp wurde entwickelt, um diese langwierigen Aspekte der API zu beseitigen.
Sie können anhand einiger Beispiele selbst beurteilen, was Sie komplizierter, verschleierter usw. finden. Diese Funktion erstellt mithilfe der C-API einen Zeichenvektor:
Mit Rcpp können Sie dieselbe Funktion schreiben wie:
oder:
Wie Dirk sagte, gibt es andere Beispiele auf den verschiedenen Vignetten. Wir weisen die Leute normalerweise auch auf unsere Unit-Tests hin, da jeder von ihnen einen ganz bestimmten Teil des Codes testet und etwas selbsterklärend ist.
Ich bin hier offensichtlich voreingenommen, aber ich würde empfehlen, sich mit Rcpp vertraut zu machen, anstatt die C-API von R zu lernen, und dann zur Mailingliste zu kommen, wenn etwas unklar ist oder mit Rcpp nicht machbar erscheint.
Wie auch immer, Ende des Verkaufsgesprächs.
Ich denke, es hängt alles davon ab, welche Art von Code Sie irgendwann schreiben möchten.
Romain
quelle
@hadley: Leider habe ich keine spezifischen Ressourcen im Sinn, um Ihnen den Einstieg in C ++ zu erleichtern. Ich habe es aus Scott Meyers 'Büchern (Effective C ++, Effective C ++ usw.) aufgegriffen, aber diese sind nicht wirklich das, was man als Einführung bezeichnen könnte.
Wir verwenden fast ausschließlich die .Call-Schnittstelle, um C ++ - Code aufzurufen. Die Regel ist einfach genug:
Eine .Call-Funktion wird also in einer Header-Datei wie folgt deklariert:
und wie folgt in einer CPP-Datei implementiert:
Es gibt nicht viel mehr über die R-API zu wissen, die Rcpp verwendet.
Die meisten Leute wollen sich nur mit numerischen Vektoren in Rcpp befassen. Sie tun dies mit der NumericVector-Klasse. Es gibt verschiedene Möglichkeiten, einen numerischen Vektor zu erstellen:
Von einem vorhandenen Objekt, das Sie von R weitergeben:
Mit gegebenen Werten mit der Funktion :: create static:
Von einer bestimmten Größe:
Sobald Sie einen Vektor haben, ist es am nützlichsten, ein Element daraus zu extrahieren. Dies geschieht mit dem Operator [] mit 0-basierter Indizierung, sodass beispielsweise das Summieren von Werten eines numerischen Vektors ungefähr so aussieht:
Aber mit Rcpp-Zucker können wir das jetzt viel besser machen:
Wie ich bereits sagte, hängt alles davon ab, welche Art von Code Sie schreiben möchten. Schauen Sie sich an, was Menschen in Paketen tun, die auf Rcpp basieren, überprüfen Sie die Vignetten, die Komponententests und melden Sie sich auf der Mailingliste bei uns. Wir helfen Ihnen gerne weiter.
quelle
@jbremnant: Das stimmt. Rcpp-Klassen implementieren etwas in der Nähe des RAII-Musters. Wenn ein Rcpp-Objekt erstellt wird, ergreift der Konstruktor geeignete Maßnahmen, um sicherzustellen, dass das zugrunde liegende R-Objekt (SEXP) vor dem Garbage Collector geschützt ist. Der Destruktor zieht den Schutz zurück. Dies wird in der Rcpp-Intduktionsvignette erklärt . Die zugrunde liegende Implementierung basiert auf den R-API-Funktionen R_PreserveObject und R_ReleaseObject
Es gibt tatsächlich Leistungseinbußen aufgrund der C ++ - Kapselung. Wir versuchen, dies durch Inlining usw. auf ein Minimum zu beschränken. Die Strafe ist gering, und wenn Sie den Zeitgewinn berücksichtigen, der zum Schreiben und Verwalten von Code erforderlich ist, ist dies nicht so relevant.
Aufrufen von R-Funktionen aus der Rcpp-Klasse Function ist langsamer als das direkte Aufrufen von eval mit der C-API. Dies liegt daran, dass wir Vorsichtsmaßnahmen treffen und den Funktionsaufruf in einen tryCatch-Block einbinden, damit wir R-Fehler erfassen und zu C ++ - Ausnahmen heraufstufen, damit sie mit dem Standard-try / catch in C ++ behandelt werden können.
Die meisten Leute wollen Vektoren verwenden (speziell NumericVector), und die Strafe ist bei dieser Klasse sehr gering. Das Verzeichnis examples / ConvolveBenchmarks enthält mehrere Varianten der berüchtigten Faltungsfunktion von R-exts, und die Vignette enthält Benchmark-Ergebnisse. Es stellt sich heraus, dass Rcpp es schneller macht als der Benchmark-Code, der die R-API verwendet.
quelle