Coa*_*oat 5 c++ r function rcpp
我正试图运行类似的东西
[R
my_r_function <- function(input_a) {return(input_a**3)}
RunFunction(c(1,2,3), my_r_function)
Run Code Online (Sandbox Code Playgroud)
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;
}
Run Code Online (Sandbox Code Playgroud)
我如何使"功能功能"实际上在Rcpp中工作?
PS我明白有没有办法可以在没有Rcpp的情况下做到这一点(这个例子可以考虑应用)但我只是以此为例来演示我正在寻找的东西.
您应该能够使用上面提供的链接中的示例来使代码正常工作; 但是你也应该注意到德克的警告,
调用函数很简单且很有诱惑力.它也很慢,因为涉及到管理费用.从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
*/
Run Code Online (Sandbox Code Playgroud)
请注意,比前者RunFunction快40倍RunFunction2:在前者中我们只会产生func从C++代码内部调用一次的开销,而在后一种情况下,我们必须为输入向量的每个元素进行交换.如果你尝试在更长的向量上运行它,我相信你会发现RunFunction2相对于相对的性能差得多RunFunction.因此,如果您要从C++代码中调用R函数,您应该尝试利用R的本机向量化(如果可能),而不是在循环中重复调用R函数,至少相当简单计算如x**3.
此外,如果您想知道为什么您的代码没有编译,那是因为这一行:
b[i] = func(a[i]);
Run Code Online (Sandbox Code Playgroud)
你可能得到了错误
在分配时无法将'SEXP'转换为'Rcpp :: traits :: storage_type <14> :: type {aka double}'
我通过包装的返回值解决func(a[i])在Rcpp::as<double>()上面.然而,这显然不值得这么麻烦,因为无论如何你最终会得到一个更慢的功能.