Pregunta
Quería comprobar si existe algún truco preexistente para na.locf
(de zoo
paquete), rle
y inverse.rle
en RCpp
?
Escribí un bucle para implementar, p.e.Hice la implementación de na.locf(x, na.rm=FALSE, fromLast=FALSE)
como sigue:
#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;
}
Me preguntaba si, dado que se trata de funciones bastante básicas, es posible que alguien ya las haya implementado en RCpp
¿De una manera mejor (puede evitar el bucle) O de una manera más rápida?
Solución
Lo único que diría es que estás probando NA
dos veces para cada valor cuando solo necesitas hacerlo una vez.Pruebas para NA
No es una operación gratuita.Quizás algo como esto:
//[[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;
}
Sin embargo, esto todavía hace cosas innecesarias, como configurar v
cada vez que solo pudimos hacerlo por última vez no vemos NA
.Podemos probar algo como esto:
//[[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;
}
Ahora, podemos probar algunos puntos de referencia:
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