Rcpp
es un paquete disponible en el CRAN que permite emplear código C o C++ en proyectos R. Es una alternativa al la R API más sencilla, por lo que es muy popular. Esto se puede apreciar al comprobar que es utilizado por cerca de 1500 paquetes de los disponibles actualmente en el CRAN. Uno de los principales motivos para usar este paquete es el hecho de que un algoritmo escrito en C o C++ es generalmente más rápido que el mismo escrito en R. Otro motivo es poder utilizar código ya existente en nuestros proyectos de R. En esta entrada se va a explicar cómo usar código C++ en R con el paquete Rcpp
. Para ello se va a implementar la sucesión de Fibonacci tanto en R como en C y comparar el rendimiento de ambas soluciones.
Implementación de la sucesión de Fibonacci
La sucesión de Fibonacci se utilizó con anterioridad al explicar la forma de cachear funciones en R con memoise
para mejorar el rendimiento de estas. Ya en esa entrada se pudo comprobar que obtener los valores de la serie puede requerir cierto esfuerzo computacional.
Una implementación de esta sucesión en R y C se puede ver en el siguiente bloque de código. En este en primer lugar se carga la librería Rcpp
. Posteriormente se implementa la versión de R de la sucesión. Finalmente se utiliza cppFunction
para definir la versión en C del algoritmo.
library(Rcpp) # Definiendo la funcion en R fibonacci <- function(n) { if (n < 2) { return(n) } else { return(fibonacci (n-1) + fibonacci (n-2)) } } # Definiendo la funcion en C cppFunction(' int fibonacci_c(int n) { if (n < 2) { return(n); } else { return(fibonacci_c(n-1) + fibonacci_c(n-2)); } }' )
La implementación de R es la misma que ya se utilizó anteriormente en la entrada del paquete . En este código se puede ver lo fácil que es utilizar una función escrita en C con Rcpp
. Únicamente se ha de escribir el código y llamar al método cppFunction
, creando una función en R con el mismo nombre de la función C. Ahora es fácil comprobar que al llamar al método fibonacci
se obtienen el mismo resultado que llamando a fibonacci_c
. Por ejemplo, para 10 se obtiene 55, mientras que para 20 el valor devuelto es 6765 en ambos casos.
Comparación del rendimiento
Para comparar el rendimiento de ambas versiones se puede utilizar el paquete rbenchmark
. Para ello simplemente se ha de ejecutar ambas versiones con el mismo valor, por ejemplo 25.
library(rbenchmark) benchmark(fibonacci(25), fibonacci_c(25))[,1:4]
test replications elapsed relative
1 fibonacci(25) 100 7.394 176.048
2 fibonacci_c(25) 100 0.042 1.000
En los resultados se puede apreciar como la versión de C es mucho más rápida. El tiempo se reduce de 7,394 a 0,042, es decir, el código C es 176 veces más rápido.
El método sourceCpp
Escribir el código C o C++ en una cadena de R puede ser problemático. Para importar directamente archivos con el código se puede utilizar el método sourceCpp
. En el archivo simplemente se ha utilizar la etiqueta // [[Rcpp::export]]
para indicar las funciones a importar. En estos archivos además es posible incluir bloques de código en R mediante el empleo de comentarios de la forma /*** R ***/
.
#include <Rcpp.h> using namespace Rcpp; // [[Rcpp::export]] int fibonacci_c(int n) { if (n < 2) { return(n); } else { return(fibonacci_c(n-1) + fibonacci_c(n-2)); } } /*** R fibonacci_c(25) */
En este código se puede ver otra vez la implementación de la sucesión de Fibonacci en C. La etiqueta situada antes de la función indica que esta se ha de exportar. Al final del código se puede ver una línea en R que ejecuta el código de la función. Ahora en R simplemente se ha de usar.
sourceCpp('fibonacci.cpp')
Conclusiones
Poder utilizar código C++ en R puede ser muy útil para aumentar el rendimiento de nuestros proyectos. También puede ser de gran ayuda cuando se cuenta con las funciones ya escritas en C o C++. En estas situaciones saber cómo utilizar el paquete Rcpp
es importante.
Imágenes: Pixabay (Remaztered Studio)