将R函数作为参数传递给RCpp函数

时间:2014-12-10 00:33:05

标签: c++ r function rcpp

我试图运行像

这样的东西

[R

my_r_function <- function(input_a) {return(input_a**3)}
RunFunction(c(1,2,3), my_r_function)

CPP

#include <Rcpp.h>
using namespace Rcpp;

// [[Rcpp::export]]
NumericVector RunFunction(NumericVector a, Function func)
{
  NumericVector b = NumericVector(a.size());
  for(int i=0; i<a.size(); i++)
    b[i] = func(a[i]);
  return b;
}

我如何制作&#34;功能函数&#34;实际上在Rcpp工作?

P.S。我知道有很多方法可以在没有Rcpp的情况下做到这一点(本例中可以考虑应用)但我只是以此为例来演示我正在寻找的内容。

2 个答案:

答案 0 :(得分:9)

您应该可以使用我在上面提供的链接中的示例来使您的代码正常工作;但你也应该注意到Dirk的警告,

  

调用函数很简单且很有诱惑力。它也很慢   是涉及的间接费用。并在C ++中反复调用   代码,可能埋在几个循环中,是彻头彻尾的愚蠢。

可以通过稍微修改上面的代码并对两个版本进行基准测试来证明:

#include <Rcpp.h>

// [[Rcpp::export]]
Rcpp::NumericVector RunFunction(Rcpp::NumericVector a, Rcpp::Function func)
{
  Rcpp::NumericVector b = func(a);
  return b;
}

// [[Rcpp::export]]
Rcpp::NumericVector RunFunction2(Rcpp::NumericVector a, Rcpp::Function func)
{
  Rcpp::NumericVector b(a.size());
  for(int i = 0; i < a.size(); i++){
    b[i] = Rcpp::as<double>(func(a[i]));
  }
  return b;
}

/*** R
my_r_function <- function(input_a) {return(input_a**3)}
x <- 1:10
##
RunFunction(x,my_r_function)

RunFunction2(x,my_r_function)
##
library(microbenchmark)
microbenchmark(
  RunFunction(rep(1:10,10),my_r_function),
  RunFunction2(rep(1:10,10),my_r_function))

Unit: microseconds
                                       expr     min       lq       mean   median       uq      max neval
  RunFunction(rep(1:10, 10), my_r_function)  21.390  22.9985   25.74988  24.0840   26.464   43.722   100
 RunFunction2(rep(1:10, 10), my_r_function) 843.864 903.0025 1048.13175 951.2405 1057.899 2387.550   100

*/

请注意,RunFunctionRunFunction2快〜40倍:在前者中,我们只会产生从C ++代码中调用func一次的开销,而在后一种情况下我们有为输入向量的每个元素进行交换。如果您尝试在更长的向量上运行此功能,我相信您会发现RunFunction2相对于RunFunction的性能会大幅下降。因此,如果您要从C ++代码中调用R函数,您应该尝试利用R的本机向量化(如果可能),而不是在循环中重复调用R函数,至少相当简单像x**3这样的计算。

另外,如果您想知道为什么您的代码没有编译,那是因为这一行:

b[i] = func(a[i]);

你可能会收到错误

  

无法将'SEXP'转换为'Rcpp :: traits :: storage_type&lt; 14&gt; :: type {aka   在作业中加倍}'

我通过将func(a[i])的返回值包含在Rcpp::as<double>()以上来解决。然而,这显然不值得这么麻烦,因为无论如何你最终会得到一个更慢的功能。

答案 1 :(得分:0)

您可以使用&#39; transform()&#39;并避免使用循环!请尝试以下代码:

List RunFunction(List input, Function f) {

    List output(input.size());

    std::transform(input.begin(), input.end(), output.begin(), f);
    output.names() = input.names();
}