programación - programacion estadistica r
¿Dónde puedo aprender a escribir el código C para acelerar las funciones R lentas? (4)
@hadley: desafortunadamente, no tengo recursos específicos en mente para ayudarlo a comenzar con C ++. Lo recogí de los libros de Scott Meyers (Effective C ++, C ++ más efectivo, etc.) pero estos no son realmente lo que se podría llamar introductorio.
Utilizamos casi exclusivamente la interfaz .Call para llamar al código C ++. La regla es bastante fácil:
- La función C ++ debe devolver un objeto R. Todos los objetos R son SEXP.
- La función C ++ toma entre 0 y 65 objetos R como entrada (nuevamente SEXP)
- debe (no en realidad, pero podemos guardar esto para más adelante) ser declarado con un enlace C, ya sea con extern "C" o el alias RcppExport que define Rcpp.
Entonces una función .Call se declara así en algún archivo de encabezado:
#include <Rcpp.h>
RcppExport SEXP foo( SEXP x1, SEXP x2 ) ;
e implementado así en un archivo .cpp:
SEXP foo( SEXP x1, SEXP x2 ){
...
}
No hay mucho más que saber sobre la API R para usar Rcpp.
La mayoría de la gente solo quiere tratar con vectores numéricos en Rcpp. Lo haces con la clase NumericVector. Hay varias formas de crear un vector numérico:
De un objeto existente que pasas de R:
SEXP foo( SEXP x_) {
Rcpp::NumericVector x( x_ ) ;
...
}
Con valores dados usando la función :: create static:
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
) ;
De un tamaño dado:
Rcpp::NumericVector x( 10 ) ; // filled with 0.0
Rcpp::NumericVector x( 10, 2.0 ) ; // filled with 2.0
Entonces, una vez que tienes un vector, lo más útil es extraer un elemento de él. Esto se hace con el operador [], con indización basada en 0, por lo que, por ejemplo, la suma de valores de un vector numérico es más o menos así:
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 ) ;
}
Pero con el azúcar Rcpp podemos hacer esto mucho mejor ahora:
using namespace Rcpp ;
SEXP sum( SEXP x_ ){
NumericVector x(x_) ;
double res = sum( x ) ;
return wrap( res ) ;
}
Como dije antes, todo depende del tipo de código que quiera escribir. Mire lo que hace la gente en paquetes que dependen de Rcpp, revise las viñetas, las pruebas de unidades, vuelva a consultarnos en la lista de correo. Siempre estamos felices de ayudar.
¿Cuál es el mejor recurso para aprender a escribir el código C para usar con R? Sé sobre el sistema y la sección de interfaces de idiomas extranjeros de las extensiones R, pero me parece bastante difícil. ¿Cuáles son los buenos recursos (tanto en línea como fuera de línea) para escribir el código C para usar con R?
Para aclarar, no quiero aprender a escribir el código C, quiero aprender a integrar mejor a R y C. Por ejemplo, cómo convertir un vector entero C en un vector entero R (o viceversa) o desde un escalar C a un vector R?
@jbremnant: Eso es correcto. Las clases Rcpp implementan algo parecido al patrón RAII. Cuando se crea un objeto Rcpp, el constructor toma las medidas adecuadas para garantizar que el objeto R subyacente (SEXP) esté protegido del recolector de elementos no utilizados. El destructor retira la protección. Esto se explica en la Rcpp-intrduction . La implementación subyacente se basa en las funciones R API R_PreserveObject y R_ReleaseObject
De hecho, hay una penalización de rendimiento debido a la encapsulación C ++. Tratamos de mantener esto al mínimo con la creación de líneas, etc. La penalización es pequeña, y cuando se toma en cuenta la ganancia en términos de tiempo que lleva escribir y mantener el código, no es tan relevante.
Llamar a las funciones R desde la clase Rcpp. La función es más lenta que llamar directamente a eval con la API C. Esto se debe a que tomamos precauciones y ajustamos la llamada a la función en un bloque tryCatch para que capturemos errores R y los promovamos a excepciones C ++ para que puedan ser tratados usando el try / catch estándar en C ++.
La mayoría de la gente quiere usar vectores (especialmente NumericVector), y la penalización es muy pequeña con esta clase. El directorio examples / ConvolveBenchmarks contiene varias variantes de la notoria función de convolución de R-exts y la viñeta tiene resultados de referencia. Resulta que Rcpp lo hace más rápido que el código de referencia que usa la API R.
Bueno, está el bueno viejo. Usa la fuente, Luke. --- R tiene mucho código C (muy eficiente) que uno puede estudiar, y CRAN tiene cientos de paquetes, algunos de autores en los que confías. Eso proporciona ejemplos reales y probados para estudiar y adaptarse.
Pero como Josh sospechaba, me inclino más hacia C ++ y, por Rcpp tanto, a Rcpp . También tiene muchos ejemplos.
Editar: Hubo dos libros que encontré útiles:
- La primera es la " Programación S " de Venables y Ripley, a pesar de que se está poniendo larga en el diente (y ha habido rumores de una segunda edición durante años). En ese momento simplemente no había nada más.
- El segundo en el " Software para el Análisis de Datos " de Chambers, que es mucho más reciente y tiene una sensación R-céntrica mucho más agradable, y dos capítulos sobre la extensión de R. Se mencionan tanto a C como a C ++. Además, John me destroza por lo que hice con el digest por lo que solo vale la pena el precio de la admisión.
Dicho esto, John se está encariñando con Rcpp (y contribuyendo) ya que considera que la coincidencia entre los objetos R y los objetos C ++ (a través de Rcpp ) es muy natural, y las ReferenceClasses ayudan allí.
Edit 2: Con la pregunta reenfocada de Hadley, te recomiendo encarecidamente que consideres C ++. Hay tantas tonterías repetitivas que tienes que ver con C, muy tediosas y muy evitables . Eche un vistazo a la viñeta de introducción de Rcpp . Otro ejemplo simple es esta publicación de blog donde muestro que en lugar de preocuparnos por las diferencias del 10% (en uno de los ejemplos de Radford Neal) podemos obtener aumentos de ochenta veces con C ++ (en lo que es, por supuesto, un ejemplo artificial).
Edición 3: existe complejidad en el sentido de que puede encontrarse con errores de C ++ que son, por decirlo suavemente, difíciles de asimilar. Pero para usar Rcpp en lugar de extenderlo, casi nunca lo necesitarás. Y aunque este costo es innegable, está eclipsado por el beneficio de un código más simple, menos repetitivo, sin PROTECT / UNPROTECT, sin administración de memoria, etc. pp. Doug Bates declaró ayer que encuentra que C ++ y Rcpp son más como escribir R que escribir C ++. YMMV y todo eso.
Hadley,
Definitivamente puede escribir código C ++ que es similar al código C.
Entiendo lo que dices sobre C ++ que es más complicado que C. Esto es si quieres dominar todo: objetos, plantillas, STL, meta programación de plantillas, etc. La mayoría de la gente no necesita estas cosas y puede confiar en los demás lo. La implementación de Rcpp es muy complicada, pero solo porque no sabes cómo funciona tu nevera, eso no significa que no puedas abrir la puerta y tomar leche fresca ...
De sus muchas contribuciones a R, lo que me sorprende es que encuentre R algo tedioso (manipulación de datos, gráficos, manipulación de cadenas, etc.). Bueno, prepárate para muchas más sorpresas con el C API interno de R. Esto es muy tedioso.
De vez en cuando, leo los manuales R-exts o R-ints. Esto ayuda. Pero la mayoría de las veces, cuando realmente quiero averiguar algo, entro en la fuente R, y también en la fuente de los paquetes escritos por, por ejemplo, Simon (generalmente hay mucho que aprender allí).
Rcpp está diseñado para hacer que estos tediosos aspectos de API desaparezcan.
Puede juzgar por sí mismo lo que le parece más complicado, ofuscado, etc., basado en algunos ejemplos. Esta función crea un vector de caracteres usando la API C:
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);
}
Usando Rcpp, puede escribir la misma función que:
SEXP foobar(){
return Rcpp::CharacterVector::create( "foo", "bar" ) ;
}
o:
SEXP foobar(){
Rcpp::CharacterVector res(2) ;
res[0] = "foo" ;
res[1] = "bar" ;
return res ;
}
Como dijo Dirk, hay otros ejemplos en varias viñetas. También usualmente señalamos a las personas hacia nuestras pruebas unitarias porque cada una de ellas prueba una parte muy específica del código y se explican por sí mismas.
Obviamente estoy predispuesto aquí, pero recomendaría familiarizarme con Rcpp en lugar de aprender C API de R, y luego llegar a la lista de correo si algo no está claro o no parece factible con Rcpp.
De todos modos, final del argumento de venta.
Supongo que todo depende de qué tipo de código quieras escribir finalmente.
Romain