2013-10-03 111 views
0

我需要從RcppEigen實現的函數內的向量中有效地刪除NA值。我當然可以用for循環來做,但我想知道是否有更有效的方法。有效刪除NA值

下面是一個例子:

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元)。我還調查了使用x.array()==x.array()找到所有NA/NaN值的路由,但無法找到使用結果與Eigen進行子集的方法。

+0

我想沒有辦法在過程中早些時候刪除'NA'? –

+0

不幸的不是。在我真實的用例中,我將三個矩陣傳遞給函數,並在相應的列向量之間進行迴歸。爲此,我需要刪除NA案例。所以我需要'lm'中的'na.omit'。我不想在R中的列索引上循環。 – Roland

回答

9

也許我並沒有正確理解這個問題,但在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) 

這將運行更快速除了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 
+0

+1 - 在一天結束時,您必須查看每個元素(i,j)。你可以僞裝一些魔法背後的循環,但爲什麼不保持簡單,並按照這裏所建議的做? –

+0

是的,我現在使用了這樣的東西,它速度夠快。但請記住,'resize'不保存Eigen中的數據。 – Roland

+0

您是否嘗試通過is_na()進行測試?使意圖更明確,然後比較。 –

-1

我不知道我是否正確或不明白的問題,但你可以使用下列參數:

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

這可能是使用`rinside」如果你想在C++中使用非常有用。

+0

我不想用普通的R,而是用Rcpp。用R我只會使用'na.omit'。與純粹的Rcpp/RcppEigen相比,使用'RInside'很可能會很慢。 – Roland

+0

這個答案中有相當多的混淆。 RInside用於在R內部製作單獨的應用程序。這與Rcpp相反,它旨在將C++代碼放入R. –