有效删除NA值

时间:2013-10-03 10:05:39

标签: r eigen rcpp

我需要从使用RcppEigen实现的函数内的向量中有效地删除NA值。我当然可以使用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进行子集化的方法。

2 个答案:

答案 0 :(得分:10)

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

例如,这是一个简单的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)

这比内置na.omit的R的速度更快:

> 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

答案 1 :(得分:-1)

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

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

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