模板化的Rcpp函数用于擦除NA值

leo*_*ido 7 templates r rcpp

我会编写一个函数(使用Rcpp),NAR向量中删除所有值.

在这之前,我通过Rcpp::cppFunction功能做了一点测试功能.

library(inline)
cppFunction('
  Vector<INTSXP> na_test(const Vector<INTSXP>& x) {
    return setdiff(x, Vector<INTSXP>::create(::traits::get_na<INTSXP>()));
  }
')
Run Code Online (Sandbox Code Playgroud)

这是这样的:

na_test(c(1, NA, NA, 1, 2, NA))
# [1] 1 2
Run Code Online (Sandbox Code Playgroud)

之后我尝试通过C++ 模板机制推广这个功能.

所以,在外部的.cpp文件(通过sourceCpp函数获取)中,我写道:

template <int RTYPE>
Vector<RTYPE> na_test_template(const Vector<RTYPE>& x) {
    return setdiff(x, Vector<RTYPE>::create(::traits::get_na<RTYPE>()));
}

// [[Rcpp::export(na_test_cpp)]]
SEXP na_test(SEXP x) {
    switch(TYPEOF(x)) {
        case INTSXP:
            return na_test_template<INTSXP>(x);
        case REALSXP:
            return na_test_template<REALSXP>(x);
    }
    return R_NilValue;
}
Run Code Online (Sandbox Code Playgroud)

这段代码编译但行为不同,我无法解释原因.

事实上:

na_test_cpp(c(1, NA, NA, 1, 2, NA))
# [1]  2 NA NA NA  1
Run Code Online (Sandbox Code Playgroud)

为什么相同的功能(显然)表现不同?这里发生了什么?

Rom*_*ois 7

按照你的答案,我会使用这样的东西作为模板:

template <int RTYPE>
Vector<RTYPE> na_omit_template(const Vector<RTYPE>& x) {
    int n = x.size() ;
    int n_out = n - sum( is_na(x) ) ;

    Vector<RTYPE> out(n_out) ;
    for( int i=0, j=0; i<n; i++){
        if( Vector<RTYPE>::is_na( x[i] ) ) continue ;
        out[j++] = x[i];
    }
    return out ;
}
Run Code Online (Sandbox Code Playgroud)

所以我们的想法是先计算结果的长度,然后再使用Rcpp向量类代替std::vector.这将导致更少的数据副本.


使用Rcpp(svn revision> = 4308)的开发版本,它适用于所有类型的我,然后我们可以使用我们的RCPP_RETURN_VECTOR调度宏而不是编写switch:

// [[Rcpp::export]]
SEXP na_omit( SEXP x ){
     RCPP_RETURN_VECTOR( na_omit_template, x ) ;   
}
Run Code Online (Sandbox Code Playgroud)

na_omit已被包含在Rcpp(svn revision> = 4309)中,只有一些修改,即它可以处理命名向量和任意糖表达式.