Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
467 views
in Technique[技术] by (71.8m points)

r - na.locf and inverse.rle in Rcpp

I wanted to check if there is any pre-existing trick for na.locf (from zoo package), rle and inverse.rle in RCpp?

I wrote a loop to implement, e.g. I did the implementation of na.locf(x, na.rm=FALSE, fromLast=FALSE) as follows:

#include <Rcpp.h>
using namespace Rcpp;

//[[Rcpp::export]]
NumericVector naLocf(NumericVector x) {
  int n=x.size();
  for (int i=1;i<n;i++) {
    if (R_IsNA(x[i]) & !R_IsNA(x[i-1])) {
      x[i]=x[i-1];
    }
  }
  return x;
}

I was just wondering that since these are quite basic functions, someone might have already implemented them in RCpp in a better way (may be avoid the loop) OR a faster way?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

The only thing I'd say is that you are testing for NA twice for each value when you only need to do it once. Testing for NA is not a free operation. Perhaps something like this:

//[[Rcpp::export]]
NumericVector naLocf(NumericVector x) {
    int n = x.size() ;
    double v = x[0]
    for( int i=1; i<n; i++){
        if( NumericVector::is_na(x[i]) ) {
            x[i] = v ;
        } else {
            v = x[i] ;    
        }
    }

    return x;
}

This still however does unnecessary things, like setting v every time when we could only do it for the last time we don't see NA. We can try something like this:

//[[Rcpp::export]]
NumericVector naLocf3(NumericVector x) {
    double *p=x.begin(), *end = x.end() ;
    double v = *p ; p++ ;

    while( p < end ){
        while( p<end && !NumericVector::is_na(*p) ) p++ ;
        v = *(p-1) ;
        while( p<end && NumericVector::is_na(*p) ) {
            *p = v ;
            p++ ;
        }
    }

    return x;
}

Now, we can try some benchmarks:

x <- rnorm(1e6)
x[sample(1:1e6, 1000)] <- NA 
require(microbenchmark)
microbenchmark( naLocf1(x), naLocf2(x), naLocf3(x) )
#  Unit: milliseconds
#       expr      min       lq   median       uq      max neval
# naLocf1(x) 6.296135 6.323142 6.339132 6.354798 6.749864   100
# naLocf2(x) 4.097829 4.123418 4.139589 4.151527 4.266292   100
# naLocf3(x) 3.467858 3.486582 3.507802 3.521673 3.569041   100

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...