1

我需要NA从使用 RcppEigen 实现的函数内的向量中有效地删除值。我当然可以使用for循环来做到这一点,但我想知道是否有更有效的方法。

这是一个例子:

library(RcppEigen)
library(inline)

incl <- '
using  Eigen::Map;
using  Eigen::VectorXd;
typedef  Map<VectorXd>  MapVecd;
'

body <- '
const MapVecd         x(as<MapVecd>(xx)), y(as<MapVecd>(yy));
VectorXd              x1(x), y1(y);
int                   k(0);
for (int i = 0; i < x.rows(); ++i) {
 if (x.coeff(i)==x.coeff(i) && y.coeff(i)==y.coeff(i)) {
  x1(k) = x.coeff(i);
  y1(k) = y.coeff(i);
  k++;
 };
};
x1.conservativeResize(k);
y1.conservativeResize(k);
return Rcpp::List::create(Rcpp::Named("x") = x1,
                          Rcpp::Named("y") = y1);
'

na.omit.cpp <- cxxfunction(signature(xx = "Vector", yy= "Vector"), 
                   body, "RcppEigen", incl)

na.omit.cpp(c(1.5, NaN, 7, NA), c(7.0, 1, NA, 3))
#$x
#[1] 1.5
#
#$y
#[1] 7

在我的用例中,我需要在循环中执行大约一百万次(在 Rcpp 函数内),并且向量可能很长(假设有 1000 个元素)。

PS:我还调查了使用 查找所有NA/NaN值的路线x.array()==x.array(),但无法找到使用 Eigen 子集的结果的方法。

4

2 回答 2

12

也许我没有正确理解这个问题,但在 Rcpp 中,我看不出你怎么可能比for循环更有效地做到这一点。 for循环在 R 中通常效率低下,只是因为在 R 中迭代循环需要大量繁重的解释机制。但是,一旦您处于 C++ 级别,情况就不是这样了。甚至本机矢量化的 R 函数最终也是用forC 中的循环实现的。所以我认为提高效率的唯一方法是尝试并行执行。

例如,这是一个省略单个向量中的值的简单na.omit.cpp函数:NA

rcppfun<-"
Rcpp::NumericVector naomit(Rcpp::NumericVector x){
std::vector<double> r(x.size());
int k=0;
  for (int i = 0; i < x.size(); ++i) {
    if (x[i]==x[i]) {
    r[k] = x[i];
    k++;
   }
  }
 r.resize(k);
 return Rcpp::wrap(r);    
}"

na.omit.cpp<-cppFunction(rcppfun)

这比 R 内置的运行得更快na.omit

> set.seed(123)
> x<-1:10000
> x[sample(10000,1000)]<-NA
> y1<-na.omit(x)
> y2<-na.omit.cpp(x)
> all(y1==y2)
[1] TRUE
> require(microbenchmark)
> microbenchmark(na.omit(x),na.omit.cpp(x))
Unit: microseconds
           expr     min       lq   median      uq      max neval
     na.omit(x) 290.157 363.9935 376.4400 401.750 6547.447   100
 na.omit.cpp(x) 107.524 168.1955 173.6035 210.524  222.564   100
于 2013-10-03T12:06:31.240 回答
-1

我不知道我是否正确理解了这个问题,但您可以使用以下参数:

       a = c(1.5, NaN, 7, NA)
       a[-which(is.na(a))]
       [1] 1.5 7.0

如果你想在 C++ 中使用 `rinside' 可能会很有用。

于 2013-10-03T10:16:46.580 回答