RとC++とで関数をかき分けて練習する

  • No inputs, scalar output
returnOneR <- function(){
	return(1)
}
#include <Rcpp.h>

// [[Rcpp::export]]

int returnOneCpp(){
	return(1);
}
int add(int, int, int);
int returnOneCpp();
> sourceCpp("returnOneCpp.cpp")
> returnOneCpp()
[1] 1
  • Scalar input, scalar output
absR <- function(x){
	if(x > 0){
		x
	}else if(x == 0){
		0
	}else{
		-x
	}
}
#include <Rcpp.h>

// [[Rcpp::export]]

double absCpp(double x){
	if(x > 0){
		return x;
	}else if (x == 0){
		return 0;
	}else{
		return -x;
	}
}
int add(int, int, int);
int returnOneCpp();
double absCpp(double x);
> sourceCpp("absCpp.cpp")
> absCpp(-3)
[1] 3
> absCpp(0)
[1] 0
> absCpp(4)
[1] 4
  • Vector input, scalar output
    • "Rcpp::NumericVector"という記述に注意
      • ちなみに、cppFunction()を使うときには、double sumC(NumericVector x)と"Rcpp::"をつけなくてもうまくいきます…???
#include <Rcpp.h>

// [[Rcpp::export]]

double meanCpp(Rcpp::NumericVector x){
	int n = x.size();
	double ret = 0;
	for(int i = 0; i < n; ++i) {
		ret += x[i];
	}
	return ret/n;
}
    • namespaceという概念が…
#include <Rcpp.h>

using namespace Rcpp;

// [[Rcpp::export]]

double meanCpp2(NumericVector x){
	int n = x.size();
	double ret = 0;
	for(int i = 0; i < n; ++i) {
		ret += x[i];
	}
	return ret/n;
}
int add(int, int, int);
int returnOneCpp();
double absCpp(double);
double meanCpp(Rcpp::NumericVector);
meanR <- function(x){
	n <- length(x)
	ret <- 0
	for(i in 1:length(x)){
		ret <- ret + x[i]
	}
	ret/n
}
> sourceCpp("meanCpp.cpp")
> x <- runif(10)
> mean(x)
[1] 0.587014
> meanCpp(x)
[1] 0.587014
> meanR(x)
[1] 0.587014
> library(microbenchmark)
> x <- runif(1e3)
> microbenchmark(
+   mean(x),
+   meanR(x),
+   meanCpp(x)
+ )
Unit: microseconds
       expr      min       lq    median       uq      max neval
    mean(x)   28.590   35.921   38.4870   48.567  110.328   100
   meanR(x) 2275.825 2298.184 2389.4515 2869.430 3807.214   100
 meanCpp(x)    7.331   10.080   12.4625   14.662   45.084   100
  • Vector input, scalar output 2
    • cppの関数の中からmeanCppを呼ぼうとしたけれど、うまくいかなかった。cppのmean,powの関数はmath.hをincludeしないといけないかと思ったが、不要らしい…
#include <Rcpp.h>

// [[Rcpp::export]]

double corCpp(Rcpp::NumericVector x, Rcpp::NumericVector y) {
    int n = x.size();
    double mx = mean(x);
    double my = mean(y);
    double xx = 0;
    double yy = 0;
    double xy = 0;
    for(int i = 0; i < n; ++i) {
      xx += (x[i]-mx)*(x[i]-mx);
      yy += (y[i]-my)*(y[i]-my);
      xy += (x[i]-mx)*(y[i]-my);
    }
    return xy/pow(xx*yy,0.5);
  }
int add(int, int, int);
int returnOneCpp();
double absCpp(double);
double meanCpp(Rcpp::NumericVector);
double corCpp(Rcpp::NumericVector,Rcpp::NumericVector);
corR <- function(x,y){
	m.x <- mean(x)
	m.y <- mean(y)
	sum((x-m.x)*(y-m.y))/sqrt(sum((x-m.x)^2)*sum((y-m.y)^2))
}
> x <- runif(10)
> y <- runif(10)
> sourceCpp("corCpp.cpp")
> corCpp(x,y)
[1] -0.5522906
> corR(x,y)
[1] -0.5522906
> cor(x,y)
[1] -0.5522906
> x <- runif(1e3)
> y <- runif(1e3)
> microbenchmark(
+   cor(x,y),
+   corR(x,y),
+   corCpp(x,y)
+ )
Unit: microseconds
         expr     min       lq   median      uq     max neval
    cor(x, y) 198.663 203.0620 212.2255 220.289 353.708   100
   corR(x, y) 137.085 141.1170 147.8980 152.846 280.401   100
 corCpp(x, y)  21.992  23.2755  27.8580  29.690  74.408   100
#include <Rcpp.h>

using namespace Rcpp;
// [[Rcpp::export]]

NumericVector squareCpp(NumericVector x) {
int n = x.size();
NumericVector y(n);
for (int i = 0; i < n; i++){
	y[i] = pow(x[i],2);
}
return y;
}
> sourceCpp("squareCpp2.cpp")
> x <- seq(from=0,to=1,length=4)
> x^2
[1] 0.0000000 0.1111111 0.4444444 1.0000000
> squareCpp(x)
[1] 0.0000000 0.1111111 0.4444444 1.0000000
#include <Rcpp.h>

using namespace Rcpp;
// [[Rcpp::export]]

NumericVector sinCpp(NumericVector x) {
int n = x.size();
NumericVector y(n);
for (int i = 0; i < n; i++){
	y[i] = sin(x[i]);
}
return y;
}
#include <Rcpp.h>

using namespace Rcpp;
// [[Rcpp::export]]

NumericVector rowSumCpp(NumericMatrix x) {
	int nr = x.nrow();
	int nc = x.ncol();
	NumericVector y(nr);
	for (int i = 0; i < nr; i++){
		double tmp = 0;
		for(int j = 0; j < nc; j++){
			tmp += x(i,j);
		}
		y[i] = tmp;
	}
	return y;
}
> x <- matrix(1:20,4,5)
> rowSumCpp(x)
[1] 45 50 55 60
> apply(x,1,sum)
[1] 45 50 55 60
> microbenchmark(
+   apply(x,1,sum),
+   rowSumCpp(x)
+ )
Unit: microseconds
             expr      min       lq   median       uq      max neval
 apply(x, 1, sum) 1391.739 1433.891 1654.729 1775.320 5739.228   100
     rowSumCpp(x)   40.686   42.336   50.216   52.049  103.364   100
>