快速功能,按名称添加矢量元素

leo*_*ido 10 performance r vector rcpp

我写了这个R函数,给定任意数量的向量(...)通过根据它们的名称对各个元素值求和来组合它们.

add_vectors <- function(...) {
  a <- list(...)
  nms <- sort(unique(unlist(lapply(a, names))))
  out <- numeric(length(nms))
  names(out) <- nms
  for (v in a) out[names(v)] <- out[names(v)] + v

  out
}
Run Code Online (Sandbox Code Playgroud)

例:

v1 <- c(a=2,b=3,e=4)
v2 <- c(b=1,c=6,d=0,a=4)
add_vectors(v1, v2)
#
a b c d e 
6 4 6 0 4
Run Code Online (Sandbox Code Playgroud)

我正在尝试编写一个更快的等效函数.

不幸的是,此刻我不知道如何实现这一点,R所以我想Rcpp.但是,为了转换Rcpp这个函数我错过了一些概念:

  1. 如何管理...参数.使用List类型参数Rcpp
  2. 如何迭代...参数中的向量.
  3. 如何通过名称访问(然后求和)向量的元素(这非常简单R,但我无法想象如何进行Rcpp).

所以我正在寻找可以帮助我提高这个功能的性能(在R或中Rcpp,或两者兼而有之).

任何帮助表示赞赏,谢谢.

Rom*_*ois 6

我会用这样的东西:

#include <Rcpp.h>
using namespace Rcpp; 

// [[Rcpp::export]]
NumericVector add_all(List vectors){
    RCPP_UNORDERED_MAP<std::string,double> out ; 
    int n = vectors.size() ;
    for( int i=0; i<n; i++){
        NumericVector x = vectors[i] ;
        CharacterVector names = x.attr("names") ;
        int m = x.size() ;

        for( int j=0; j<m; j++){
            String name = names[j] ;
            out[ name ] += x[j] ;   
        }
    }
    return wrap(out) ;
}
Run Code Online (Sandbox Code Playgroud)

使用以下包装器:

add_vectors_cpp <- function(...){
    add_all( list(...) )
}
Run Code Online (Sandbox Code Playgroud)

RCPP_UNORDERED_MAP仅仅是一个的typedef unordered_map,无论是在std::std::tr1::取决于你的编译器,等等.

这里的技巧是...使用经典创建一个常规列表list(...).

如果你真的想直接...在C++中传递并在内部处理它,你将不得不使用该.External接口.这很少使用,因此Rcpp属性不支持该.External接口.

.External,它看起来像这样(未经测试):

SEXP add_vectors(SEXP args){
    RCPP_UNORDERED_MAP<std::string,double> out ; 
    args = CDR(args) ;
    while( args != R_NilValue ){
        NumericVector x = CAR(args) ;

        CharacterVector names = x.attr("names") ;
        int m = x.size() ;

        for( int j=0; j<m; j++){
            String name = names[j] ;
            out[ name ] += x[j] ;   
        }        
        args = CDR(args) ;
    }   
    return wrap(out) ;
}
Run Code Online (Sandbox Code Playgroud)

  • 使用`list(...)`将创建所有输入的副本,这可能是一个很高的性价格.更复杂的方法(但不需要.External)是传递函数环境和未评估的参数名称. (2认同)