Eine Schritt-für-Schritt-Anleitung zum Schreiben eines R-Pakets, das C++-Code (Ubuntu) verwendet. (2023)

[Dieser Artikel wurde zuerst veröffentlicht amPascha, und freundlicherweise dazu beigetragenR-Blogger]. (Sie können Probleme mit dem Inhalt auf dieser Seite meldenHier)

Möchten Sie Ihre Inhalte auf R-Bloggern teilen?klicken Sie hierwenn Sie einen Blog haben, oderHierwenn nicht.

R/Shiny-Schulung: Sollte dieser Blog für Sie von Interesse sein, beachten Sie bitte, dass ich personalisierte und gruppenbasierte Schulungen anbiete, die über reserviert werden könnenKauf mir einen Kaffee. Darüber hinaus biete ich Schulungsdienstleistungen in spanischer Sprache an und stehe zur Verfügung, um Möglichkeiten zu besprechen, wie ich zu Ihrem Shiny-Projekt beitragen kann.

Ein großer Teil meines Forschungsinteresses erfordert die Schätzung rechenintensiver Modelle, wie etwa des General Equilibrium Poisson Pseudo Maximum Likelihood (GEPPML)-Schätzers, der aus den von Anderson und Van Wincoop (2004) eingeführten Gleichgewichtsbedingungen zur Schätzung und Schlussfolgerung abgeleitet ist.

Der GEPPML-Schätzer ist ein rechenintensiver Schätzer, der die Lösung eines Systems nichtlinearer Gleichungen erfordert. Für diese Aufgabe wäre die Verwendung einer kompilierten Sprache wie C++ möglicherweise besser geeignet. Die gute Nachricht ist, dass wir C++-Code in R und Python verwenden können, und in diesem Blogbeitrag geht es um die Verwendung von C++-Funktionen aus R.

Außerdem gebe ich nicht vor, ein C++-Experte zu sein oder darüber zu diskutieren, ob R besser als Python ist. Ich verwende beides aus Visual Studio Code. Ich möchte meine Erfahrungen mit der Verwendung von C++-Code in R teilen.

Dieser Blogbeitrag ist eine Zusammenfassung dessen, was nach stundenlangem Scheitern für mein zukünftiges Ich funktioniert hat. Ich hoffe, es hilft dir auch.

Ich bin Statistiker und Politikwissenschaftler,nichtein Informatiker!

Da ich C++ Version 11 bereits gelernt habe, habe ich mich für die Installation entschiedenllvm-11auf meinem Laptop, auf dem Linux Mint installiert ist und der auf Ubuntu 22.04 basiert.

Ubuntu und seine abgeleiteten Distributionen verwendengccals Standard-C++-Compiler undklirrenist nicht standardmäßig installiert. Verschiedene Quellen erwähnen dasklirrenBietet informativere Fehlermeldungen, wenn die Kompilierung fehlschlägt und wenn wir Code debuggen.

Das Zählen auf informative Fehlermeldungen ist eine äußerst nützliche Ressource, wenn wir C++ lernen oder wenn unser Code auf zwei verschiedene Arten fehlschlägt, zum einen, weil er nicht kompiliert wird, und zum anderen, weil er kompiliert, aber dann, wenn wir eine Funktion von RStudio (oder VSCode) aufrufen. es stürzt die R-Sitzung ab.

Ich habe die R-Pakete installiertcpp11UndSatz.

install.packages(c("cpp11", "usethis"))

Ich habe eine Datei erstellt~/.Rprofileenthält die folgenden Zeilen.

Bibliothek(devtools)Bibliothek(usethis)Bibliothek(cpp11)

ich rennenano ~/.R/Makevarsaus der Bash erstellt und dann mit STRG+O+ENTER gespeichert und mit STRG+X geschlossen. Es ist dasselbe, als würde man es mit dem Texteditor von Gnome oder einer anderen Desktop-Umgebung erstellen.

Jetzt vergiss esdevtools::install(). Nachdem Sie Ihren Editor erneut geöffnet haben, rufen Sie jedes Mal auf, wenn Sie RStudio (oder VSCode) verwendenInstallieren(), und das Gleiche gilt fürusethis::use_*()Undcpp11::cpp_*()Funktionen.

Installierenllvm-11Ich habe das Installationsskript aus dem offiziellen LLVM-Repository heruntergeladen und es auch installiertclang-11.

cd Downloadswget https://apt.llvm.org/llvm.shchmod +x llvm.shsudo ./llvm.sh 11

Bis zu diesem Zeitpunkt hatte ich beim Kompilieren von C++-Code immer noch die folgenden Fehlermeldungen.

Schwerwiegender Fehler: Datei „cstdio“ nicht gefunden. Schwerwiegender Fehler: Datei „vector“ nicht gefunden. -lc++abi: Keine solche Datei oder kein solches Verzeichnis

Ich musste zusätzliche Pakete installieren. Ich habe ein paar Stunden im Internet gesucht, bis ich es herausgefunden habe.

sudo apt install g++-11 libc++-11-dev libc++abi-11-dev

Um sicherzustellen, dass dieInstallieren()Funktion in R verwendet die richtige Version vonklirren++Ich habe das erstellt~/.R/MakevarsDatei. Der Inhalt der Datei ist wie folgt.

CLANGVER=-11CLANGLIB=-stdlib=libc++CXX=$(CCACHE) clang++$(CLANGVER) $(CLANGLIB)CXX11=$(CCACHE) clang++$(CLANGVER) $(CLANGLIB)CC=$(CCACHE) clang$( CLANGVER)SHLIB_CXXLD=clang++$(CLANGVER) $(CLANGLIB)CXXFLAGS=-Wall -O0 -pedanticCXX11FLAGS=-Wall -O0 -pedantic

Für beideCXXFLAGSUndCXX11FLAGSich benutze-O0um eine Optimierung zu vermeiden, was für das Debuggen nützlich ist. Nachdem der Code funktioniert, kann ich ihn ändern-O3um den kompilierten Code zu optimieren.

Wenn ich später mit kompilieren mussgcc, ich kann öffnen~/.R/Makevars, kommentieren Sie alle Zeilen, starten Sie RStudio oder VSCode neu und führen Sie es ausInstallieren()nochmal.

Wenn Sie RStudio (oder VSCode) schließen und erneut öffnen, können Sie durch Ausführen überprüfen, ob die Änderungen implementiert wurdenpkgbuild::check_build_tools(debug = TRUE), was die folgende Ausgabe zurückgeben sollte.

Versuche, eine einfache C-Datei zu kompilieren. /usr/lib/R/bin/R CMD SHLIB foo.cusing C-Compiler ausführen: 'Ubuntu clang version 11.1.0-6'clang-11 -I"/usr/share/R/include" -DNDEBUG -fpic -g -O2 -ffile-prefix-map=/build/r-base-JhpCKt/r-base-4.3.0=. -fstack-protector-strong -Wformat -Werror=format-security -Wdate-time -D_FORTIFY_SOURCE=2 -c foo.c -o foo.oclang-11 -shared -L/usr/lib/R/lib -Wl,- Bsymbolic-functions -flto=auto -ffat-lto-objects -flto=auto -Wl,-z,relro -o foo.so foo.o -L/usr/lib/R/lib -lR

Wenn ich gcc verwendet hätte, wäre die Ausgabe wie in den folgenden Zeilen gewesen.

Ich versuche, eine einfache C-Datei zu kompilieren. /usr/lib/R/bin/R CMD SHLIB foo.cusing C-Compiler ausführen: 'gcc (Ubuntu 11.3.0-1ubuntu1~22.04.1) 11.3.0'gcc -I"/usr/ share/R/include" -DNDEBUG -fpic -g -O2 -ffile-prefix-map=/build/r-base-JhpCKt/r-base-4.3.0=. -fstack-protector-strong -Wformat -Werror=format-security -Wdate-time -D_FORTIFY_SOURCE=2 -c foo.c -o foo.ogcc -shared -L/usr/lib/R/lib -Wl,-Bsymbolic- Funktionen -flto=auto -ffat-lto-objects -flto=auto -Wl,-z,relro -o foo.so foo.o -L/usr/lib/R/lib -lR

Der Schlüssel hier ist, dass ich es verwendeklirrenDie Zeilen beginnen mitklirren, nicht mitgcc.

Von RStudio (oder VSCode) aus können wir durch Ausführen ein neues Paket erstellencreate_package("~/cpp11dummypackage"). Dadurch wird ein neuer Ordner mit dem Namen erstelltcpp11dummypackage. Dann renne ichuse_cpp11()um die erforderlichen Dateien hinzuzufügen, um C++-Code in R zu verwenden.

Dann renne ichuse_r("cpp11dummypackage-package")um eine neue R-Skriptdatei mit dem Namen zu erstellencpp11dummypackage-package.Rinnerhalb derROrdner und fügte den folgenden Code hinzu.

#' @useDynLib cpp11dummypackage, .registration = TRUENULL

DerSatzSkeleton hat die Datei auch erstelltsrc/code.cppfür uns. Ich habe eine einfache Funktion hinzugefügt, um eine Matrix darauf zu transponieren, indem ich den Dateiinhalt durch die folgenden Zeilen ersetzt.

#include #include using namespace cpp11; [[cpp11::register]] doubles_matrix<> Xt(doubles_matrix<> X){ int NX = X.nrow(); int MX = X.ncol(); writable::doubles_matrix<> R(MX, NX); for (int i = 0; i < MX; i++) { for (int j = 0; j < NX; j++) { R(i, j) = X(j, i); } } return R;}

Um die Funktion zu exportieren, habe ich die folgenden Zeilen hinzugefügtcpp11dummypackage-package.R.

#' Eine Matrix transponieren#' @export#' @rdname Xt#' @param X numerische Matrix#' @return numerische Matrix#' @examples#' set.seed(1234)#' , nrow = 2, ncol = 2)#' X#' cpp11_Xt(X)cpp11_Xt <- function(X) { Xt(X)}

Ich habe die Funktionen nach dem Ausführen getestetcpp11_register()Undalle laden().

> set.seed(1234)> X <- Matrix(rnorm(4), nrow = 2, ncol = 2)> > cpp11_Xt(X) [,1] [,2][1,] -1,207066 0,2774292[2,] 1,084441 -2,3456977

Wenn ich bestanden hätte1:4anstattrnorm(4)ZuMatrix(), hätte ich die folgende Fehlermeldung erhalten.

> cpp11_Xt(X)Fehler: Ungültiger Eingabetyp, erwartete „doppelte“ tatsächliche „Ganzzahl“

Das liegt daran, dass ich die Funktion so deklariert habe, dass sie a akzeptiertdoubles_matrix<>als Eingabe und nicht alsintegers_matrix<>.

Um das kürzlich erstellte Paket zu installieren, führe ich die folgenden Zeilen in der R-Konsole aus.

clean_dll()cpp_register()document()install()

Um auf Debugging-Symbole zugreifen zu können, habe ich ein neues erstelltMakevarsDatei innerhalb dersrcOrdner und fügte die folgenden Zeilen hinzu.

CXX_STD = CXX11PKG_CPPFLAGS = -UDEBUG -g

Dann habe ich das mit Debugging-Symbolen kompilierte Paket neu installiert und in Bash ausgeführtR -d lldb-11. Von dort aus konnte ich folgenDasHervorragende Anleitung zum Debuggen von R- und C++-Code.

Ich habe ein Paket erstellt, das eine Reihe einfacher Funktionen enthält, um den OLS-Schätzer (Ordinary Least Squares) zu erhalten, indem ich eine C++-Funktion aufrufe, die andere C++-Funktionen aufruft. Mein Ansatz bestand darin, eine Funktion pro Schritt zu erstellen, was bedeutete, eine zu erhaltende Funktion zu erstellen\(X^tX\), ein anderer für\((X^tX)^{-1}\)die darin bestand, die Gauß-Jordan-Methode zu implementieren, um eine Matrix zu invertieren, eine andere für\(X^tY\)und rufen Sie dann jede dieser Funktionen auf, um sie zu erhalten\(\hat{\beta} = (X^tX)^{-1}(X^tY)\).

Diese Implementierung ist äußerst naiv, aber sie reicht aus, um zu zeigen, wie man C++-Code in R verwendet. Bitte sehen Sie es sich von mir anGitHub-Profil.

Eine gute Herausforderung wäre die Implementierung der von der verwendeten QR-Zerlegunglm()Funktion in R und verwenden Sie sie, um den OLS-Schätzer in C++ zu erhalten. Dies würde jedoch einige Anstrengungen erfordernHierSie können einen guten Ausgangspunkt finden.

Auf jeden Fall wäre es äußerst schwer, die Leistung des zu übertreffenlm()Funktion in R, die einige in C geschriebene Interna hat und wie rechnerisch robust istlm()Dies bedeutet eine weitere Funktion, die kaum zu übertreffen ist.

Verwandt

ZuHinterlasse einen KommentarFür den Autor folgen Sie bitte dem Link und kommentieren Sie seinen Blog:Pascha.

R-bloggers.combietet antägliche E-Mail-UpdatesumRNeuigkeiten und Tutorials zum ThemaR lernenund viele andere Themen.Klicken Sie hier, wenn Sie eine Stelle im Bereich R/Data Science ausschreiben oder finden möchten.

Möchten Sie Ihre Inhalte auf R-Bloggern teilen?klicken Sie hierwenn Sie einen Blog haben, oderHierwenn nicht.

Top Articles
Latest Posts
Article information

Author: Patricia Veum II

Last Updated: 06/19/2023

Views: 5233

Rating: 4.3 / 5 (44 voted)

Reviews: 83% of readers found this page helpful

Author information

Name: Patricia Veum II

Birthday: 1994-12-16

Address: 2064 Little Summit, Goldieton, MS 97651-0862

Phone: +6873952696715

Job: Principal Officer

Hobby: Rafting, Cabaret, Candle making, Jigsaw puzzles, Inline skating, Magic, Graffiti

Introduction: My name is Patricia Veum II, I am a vast, combative, smiling, famous, inexpensive, zealous, sparkling person who loves writing and wants to share my knowledge and understanding with you.