将R函数作为参数传递给RCpp函数 [英] Passing R Function as Parameter to RCpp Function

查看:64
本文介绍了将R函数作为参数传递给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;
}

我如何使函数功能"在Rcpp中真正起作用?

How would I make "Function func" actually work in Rcpp?

P.S.我知道有很多方法可以在没有Rcpp的情况下执行此操作(此示例适用于我),但我只是以此为例来说明我在寻找什么.

P.S. I understand there are ways to do this without Rcpp (apply comes to mind for this example) but I'm just using this as an example to demonstrate what I'm looking for.

推荐答案

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

You should be able to use the example in the link I provided above to get your code working; but you should also take note of Dirk's warning,

调用函数很简单而且很诱人.那里也很慢涉及间接费用.然后从您的C ++内部反复调用它可能埋在几个循环中的代码完全是愚蠢的.

Calling a function is simple and tempting. It is also slow as there are overheads involved. And calling it repeatedly from inside your C++ code, possibly buried within several loops, is outright silly.

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

which can be demonstrated by modifying your above code slightly and benchmarking the two versions:

#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

*/

请注意, RunFunction 的运行速度比 RunFunction2 快40倍:在前一种情况下,我们仅产生从C ++代码内部调用 func 的开销一次,而在后一种情况下,我们必须对输入向量的每个元素进行交换.如果您尝试在更长的向量上运行它,我敢肯定,相对于 RunFunction 而言, RunFunction2 的性能会大大降低.因此,如果要从C ++代码内部调用R函数,则应尝试利用R的本机矢量化(如果可能),而不是反复循环调用R函数,至少这样做相当简单.像 x ** 3 这样的计算.

Notice that RunFunction is ~40x faster than RunFunction2: in the former we only incur the overhead of calling func from inside the C++ code once, whereas in the latter case we have to make the exchange for each element of the input vector. If you tried running this on even longer vectors, I'm sure you would see a substantially worse performance from RunFunction2 relative to RunFunction. So, if you are going to be calling R functions from inside of your C++ code, you should try to take advantage of R's native vectorization (if possible) rather than repeatedly making calls to the R function in a loop, at least for reasonably simple calculations like x**3.

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

Also, if you were wondering why your code wasn't compiling, it was because of this line:

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

您可能会收到错误

无法将"SEXP"转换为"Rcpp :: traits :: storage_type< 14> :: type {akadouble}"分配

cannot convert ‘SEXP’ to ‘Rcpp::traits::storage_type<14>::type {aka double}’ in assignment

我通过将 func(a [i])的返回值包装在上述 Rcpp :: as< double>()中来解决此问题.但是,这显然不值得麻烦,因为无论如何您最终都会在整体上慢得多.

which I resolved by wrapping the return value of func(a[i]) in Rcpp::as<double>() above. However, this clearly isn't worth the trouble because you end up with a much slower function overall anyhow.

这篇关于将R函数作为参数传递给RCpp函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆