Rcpp Doping für den R Code

André Bleier Blog, Data Science

Wie viel Zeit ich schon damit verbracht habe rote Stoppschilder zu beobachten? Sehr, sehr viel!

Effizientes Programmieren kann helfen diese Zeit zu minimieren, aber oft hat man gar keinen Einfluss auf die Laufzeit seines Programms, da Spezifikationen im Unterbau von  \texttt{R} das eigentliche Bottleneck sind.

R ist eine sehr flexible Programmiersprache. Als Benutzer muss man weder Speicherplatz auf dem Arbeitsspeicher allokieren noch Datentypen bzw. Objekttypen von Variablen deklarieren. Diese Eigenschaft nimmt dem Nutzer sehr viel Arbeit ab, allerdings verliert man durch hinzugewonnene Flexibilität an Leistung. Mithilfe des R-Pakets  \texttt{Rcpp} kann man das Zepter selbst in die Hand nehmen und weniger dynamischen, aber dafür leistungsfähigen Code schreiben. Allerdings gibt es dabei für eingefleischte R Hacker einen Haken: Man muss  \texttt{C++} Code schreiben!

Rcpp ist ein R Front-End für C++ Programme bzw. Code. Warum C++? R besteht im Kern aus  \texttt{C} und  \texttt{Fortran} Code, allerdings ist dieser Kern optimiert maximale Flexibilität zu gewährleisten. C++ bietet sich als Vehikel für leistungsfähigen Code an, da beide Programmiersprachen objektorientiert sind.

Als geschulter C++ Hacker kann man durch dieses Front-End ganz leicht seine Programme in R Code einbetten. Wenn man mit C++ keine bis wenig Erfahrung hat, kann man durch die für R gewohnte Nutzer umgesetzte Rcpp Bibliothek durch geringen Aufwand selbst C++ Programme schreiben. Als Starthilfe hierzu ist das Buch zum Paket Rcpp von Dirk Eddelbuettel sehr zu empfehlen, da man in kürzester Zeit erste Programme bzw. Funktionen schreiben kann.

Um die Performance von R Core Funktionen und einer C++ Version zu vergleichen, nutzen wir die Matrixmultiplikation. In R multipliziert man Matrizen mithilfe des  \texttt{\%*\%} Operators. Die selbstgeschriebene Rcpp Version der Matrixmultiplikation benutzt das für lineare Algebra optimierte C++ Paket  \texttt{Eigen} . Mithilfe von Rcpp kann man auch C++ eigene Bibliotheken verwenden, hierzu muss man nötige Plug-Ins laden. Wie viel schneller können diese selbstgeschriebenen Funktionen nun sein? Wir testen die Performanz im Folgenden in einer kleinen Simulation.

Simulation

Setup der Evaluation besteht aus der Multiplikation zweier quadratischer Matrizen, die jeweils mit gleichverteilten Zufallszahlen aus dem Intervall  x \in [0, 1] befüllt werden. Iterativ wird die Dimension  n der Matrix um eine Einheit erhöht um die Steigung des Rechenaufwands zu untersuchen. Zusätzlich wird die Multiplikation mit den verschiedenen Versionen pro Iteration 100-mal durchgeführt um zufällige Schwankungen zu glätten.

Man sieht deutlich, dass der Rechenaufwand im Falle der R Core Multiplikation mit zunehmender Komplexität quadratisch ansteigt. Im Gegensatz dazu steigt der Aufwand bei Rcpp nahezu linear. Die selbsterstellte Rcpp Funktion ist etwa um den Faktor sechs schneller als das vorimplementierte R Pendant.

average computation time Rcpp

Natürlich ist es nicht immer sinnvoll eine Rcpp Version zu schreiben, da sich durch die Kompilierungszeit (in C++) auch schnell ein Bottleneck in das Programm einschleicht. Hierbei ist es wichtig zu erkennen bei welchen Funktionen die Verwendung von Rcpp einen Mehrwert im Kontext der Rechenzeit oder Speicherbelegung generiert. Dafür gibt es leider keine Faustregel, aber jegliche Art von Schleifen sind in C++ meist effizienter. Durch die Ausnutzung der Eigen Bibliothek kann man leistungs- und speichereffiziente Operationen der linearen Algebra in R verwenden.

Vergesst nicht die Rcpp Funktionen gegen ihr R Pendant in Bezug auf Laufzeit und Speicherbelegung zu benchmarken!

Referenzen

  • Eddelbuettel, Dirk. Seamless R and C++ integration with Rcpp. New York: Springer, 2013.
    • Über den Autor

      André Bleier

      The most exciting part of being a data scientist at STATWORX is to find this unique solution to a problem by fusing machine learning, statistics, and business knowledge.