R y C++?
- Generalmente C++ como "acelerador" de funciones de R: recodificación en un lenguaje más veloz
- Lo realmente potente: Extensión de R e integración de código externo
Reunion Usuarios R Madrid - 10 de diciembre de 2015
Rcpp::Rcpp.package.skeleton(name="GradDesc",path="/tmp")
## GradDesc ## ├── DESCRIPTION ## ├── GradDesc.Rproj ## ├── inst ## ├── man ## ├── NAMESPACE ## ├── R ## └── src ## ## 4 directories, 3 files
## GradDesc ## ├── DESCRIPTION ## ├── inst ## │  └── include ## │  ├── ObjectiveFunction ## │  ├── OptimizationAlgorithm ## │  └── Utilities ## ├── man ## ├── NAMESPACE ## ├── R ## │  ├── GradDesc.R ## │  └── RcppExports.R ## └── src ## ├── GradientDescent.cpp ## ├── Makevars ## ├── Makevars.win ## ├── ObjectiveFunction.cpp ## ├── OptimizationAlgorithm.cpp ## ├── RcppExports.cpp ## ├── RcppGradientDescent.cpp ## ├── RcppModuloSumaCuadrados.cpp ## ├── Rcpp_purple_wrappers.cpp ## └── SumaCuadrados.cpp ## ## 8 directories, 14 files
// [[Rcpp::export]]
Rcpp::NumericVector GradientDescentSumaCuadrados(SEXP A,SEXP b) {
Purple::Vector<double> M_b = Rcpp::as<Purple::Vector<double>>(b);
Purple::Matrix<double> M_A = Rcpp::as<Purple::Matrix<double>>(A);
//....
return(Rcpp::wrap<Purple::Vector<double>>(minimalArgument));
}
SEXP A,SEXP b. Objetos de R (Matriz y vector)Purple::Vector y Purple::Matrix: Especializacion de la plantilla de Rcpp::as. Se define en purple_wrappers.cpp// [[Rcpp::export]]
Rcpp::NumericVector GradientDescentSumaCuadrados(SEXP A,SEXP b) {
Purple::Vector<double> M_b = Rcpp::as<Purple::Vector<double>>(b);
Purple::Matrix<double> M_A = Rcpp::as<Purple::Matrix<double>>(A);
//....
return(Rcpp::wrap<Purple::Vector<double>>(minimalArgument));
}
Rcpp::wrap. Se define en purple_wrappers.cpp## -*- mode: makefile; -*- PKG_CXXFLAGS=-I../inst/include ## With R 3.1.0 or later, you can uncomment the following line to tell R to ## enable compilation with C++11 (where available) CXX_STD = CXX11
Cómo funciona Rcpp:
RcppGradientDescent.cpp ([[Rcpp::export]]) -> src/RcppExports.cpp -> R/RcppExports.R (Función en R)
devtools::install(".", args="--no-multiarch")
Estimación de coeficientes de regresión por Gradient Descent vs OLS
library(GradDesc) head(iris)
## Sepal.Length Sepal.Width Petal.Length Petal.Width Species ## 1 5.1 3.5 1.4 0.2 setosa ## 2 4.9 3.0 1.4 0.2 setosa ## 3 4.7 3.2 1.3 0.2 setosa ## 4 4.6 3.1 1.5 0.2 setosa ## 5 5.0 3.6 1.4 0.2 setosa ## 6 5.4 3.9 1.7 0.4 setosa
A <- as.matrix(iris[,2:4]) y <- iris[,1]
Estimación de coeficientes de regresión por Gradient Descent vs OLS
coefs <- GradientDescentSumaCuadrados(A,y) names(coefs) <- colnames(A) # Usando función lm (quitamos el término independiente) lm(data=iris[,-5], formula=Sepal.Length~.-1)$coefficients
## Sepal.Width Petal.Length Petal.Width ## 1.1210617 0.9235289 -0.8956758
coefs
## Sepal.Width Petal.Length Petal.Width ## 1.1210617 0.9235288 -0.8956758
Estimación de coeficientes de regresión por Gradient Descent vs OLS
# Con término independiente: incluimos una columna de unos en la matriz del modelo A <- cbind(Interc=rep(1,nrow(A)), A) coefs <- GradientDescentSumaCuadrados(A,y) names(coefs) <- colnames(A) lm(data=iris[,-5], formula=Sepal.Length~.)$coefficients
## (Intercept) Sepal.Width Petal.Length Petal.Width ## 1.8559975 0.6508372 0.7091320 -0.5564827
coefs
## Interc Sepal.Width Petal.Length Petal.Width ## 1.8559957 0.6508376 0.7091322 -0.5564831
RCPP_MODULE: permite exportar objetos directamente. Similar a // [[Rcpp::export]]class GradientDescentSumaCuadradosClase {
public:
GradientDescentSumaCuadradosClase(SEXP A, SEXP y){
//...
}
SEXP getMinimalArgument(){
return Rcpp::wrap<Purple::Vector<double>>(gradient_descent.getMinimalArgument());
}
void setInitialArgument(SEXP vect_inicial){
gradient_descent.setInitialArgument(Rcpp::as<Purple::Vector<double>>(vect_inicial));
}
//...
private:
Purple::GradientDescent gradient_descent;
//...
};
class GradientDescentSumaCuadradosClase{
//...
};
RCPP_MODULE(ModuloSumaCuadrados){
using namespace Rcpp;
class_<GradientDescentSumaCuadradosClase>( "GradientDescentSumaCuadradosClase" )
.constructor<SEXP,SEXP>()
.method( "solve", &GradientDescentSumaCuadradosClase::getMinimalArgument )
.method( "setGradientNormGoal", &GradientDescentSumaCuadradosClase::setGradientNormGoal )
.method( "setEvaluationGoal", &GradientDescentSumaCuadradosClase::setEvaluationGoal )
.method( "starting_point", &GradientDescentSumaCuadradosClase::setInitialArgument )
;
}
DESCRIPTION : RcppModules: ModuloSumaCuadradosR/GradDesc.R: loadModule("ModuloSumaCuadrados",TRUE)RCPP_MODULE crea una clase S4 de R.
obj = new(GradientDescentSumaCuadradosClase,A,y) punto_inicial_alternativo = c(1,-1,-2,1) obj$starting_point(punto_inicial_alternativo) coefs2 = obj$solve() names(coefs2)<-colnames(A) coefs2
## Interc Sepal.Width Petal.Length Petal.Width ## 1.9291884 0.6326327 0.6991565 -0.5391704
lm(data=iris[,-5], formula=Sepal.Length~.)$coefficients
## (Intercept) Sepal.Width Petal.Length Petal.Width ## 1.8559975 0.6508372 0.7091320 -0.5564827
PKG_LIBS)## -*- mode: makefile; -*- PKG_CXXFLAGS=-I../../Purple PKG_LIBS=-L../../lib -lPurple ## With R 3.1.0 or later, you can uncomment the following line to tell R to ## enable compilation with C++11 (where available) CXX_STD = CXX11
make -f MakefileVersionCompilacionExterna/devtools::clean_dll(); devtools::clean_source()R/RcppExport.R y src/RcppExport.cpproxygen2 revisar el NAMESPACE. Tiene que tener:## # Generated by roxygen2: do not edit by hand ## ## export(GradientDescentSumaCuadrados) ## export(GradientDescentSumaCuadradosClase) ## import(Rcpp) ## useDynLib(GradDesc)
browseVignettes("Rcpp")RStan, Hadley: dplyr, tidyr, readr, RcppArmadilloOtras presentaciones: