LoginSignup
3
3

More than 5 years have passed since last update.

Rcpp: 引数にvectorを使うかIntegerVectorなどを使うか

Last updated at Posted at 2016-10-23

Rcppには、Rの各種ベクトル・行列に対応するクラスがひと通り用意されている。IntegerVector NumericMatrixなどだ。一方、Rcppで関数を書くときには標準ライブラリのstd::vectorを使うことも許されている。例えば、std::vector<int>型の引数を取る関数を定義してそれをRから用いる場合、Rのベクトルオブジェクトが舞台裏でC++の整数ベクトル型に変換されるので、同様の挙動が得られる。

関数内で行列演算などの数値計算をたくさん行う場合には、Rcpp上の型を用いるほうが様々な演算が定義されているので便利だし効率もいい。だけど、そこまでの数値計算を要さない処理である場合、標準ライブラリを使っていた方がC++に慣れていれば書きやすい意味もある。

変数をどう受け渡すのが良いか、変換効率について比較した。結論としては

  • 入力変数のサイズがあまり大きくなければ差はそれほどない。
  • IntegerVectorが引数の関数にはRから整数ベクトルを渡すと速い(型変換がないため)が、実数ベクトルを渡すと型変換が起こって遅くなる。
  • 同様にNumericVectorを取る関数にはRから実数ベクトルを渡すと速いが、整数ベクトルを渡すと型変換が起こって遅くなる。
  • 標準ライブラリのベクトルを用いると、必ず型変換が起こるので遅い。

テストコード

stdVector-v-RcppVector.png

library(Rcpp)
library(dplyr)
library(ggplot2)
library(microbenchmark)


cppFunction(
  'void TakeRcppIntVector(Rcpp::IntegerVector x)
  {
    return;
  }'
)

cppFunction(
  'void TakeStdIntVector(std::vector<int> x)
  {
    return;
  }'
)

cppFunction(
  'void TakeRcppRealVector(Rcpp::NumericVector x)
  {
    return;
  }'
)

cppFunction(
  'void TakeStdRealVector(std::vector<double> x)
  {
    return;
  }'
)



# performance check
d <- NULL
for (s in 1:6)
{
  intvec <- rep(1L, 10^s)
  realvec <- rep(1, 10^s)
  m <- microbenchmark(TakeRcppIntVector(intvec), TakeStdIntVector(intvec),
                      TakeRcppIntVector(realvec), TakeStdIntVector(realvec),
                      TakeRcppRealVector(intvec), TakeStdRealVector(intvec),
                      TakeRcppRealVector(realvec), TakeStdRealVector(realvec))
  cat(sprintf("\n size = 1e+%d\n", s))
  print(m)
  m <- as.data.frame(m)
  m$size <- 10^s
  d <- rbind(d, m)
}


v <- group_by(d, size, expr) %>%
  summarize(Mean = mean(time), Med = median(time),
            LB = quantile(time, 0.1), UB = quantile(time, 0.9))
v$input <- ifelse(grepl("intvec", v$expr), "pass integer", "pass numeric")
v$func <- sub("\\(.*\\)", "", v$expr)
ggplot(v, aes(x = size, y = Med, color = input)) +
  geom_point() + geom_line() + 
  xlab("Vector Size") + ylab("Time (nano sec)") +
  geom_ribbon(aes(ymin = LB, ymax = UB, fill = input), 
              alpha = 0.3, size = 0) +
  scale_y_log10() + scale_x_log10() +
  facet_grid(~func) +
  theme(legend.position="bottom")
3
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
3