2012-06-30 196 views
11

Queremos establecer todos los valores en una matriz cero que sean negativos. Probé muchas cosas pero aún no conseguí una solución funcional. Pensé en un bucle for con condición, sin embargo, esto parece no funcionar.R: Reemplazar valores negativos por cero

#pred_precipitation is our array 
pred_precipitation <-rnorm(25,2,4)  

for (i in nrow(pred_precipitation)) 
{ 
    if (pred_precipitation[i]<0) {pred_precipitation[i] = 0} 
    else{pred_precipitation[i] = pred_precipitation[i]} 
} 

Gracias por sus sugerencias!

Respuesta

38

Gracias por el ejemplo reproducible. Esto es bastante básico. Puede asignar a los elementos seleccionados de un vector (nota una matriz tiene dimensiones, y lo que has dado no es un vector de una matriz):

> pred_precipitation[pred_precipitation<0] <- 0 
> pred_precipitation 
[1] 1.2091281 0.0000000 7.7665555 0.0000000 0.0000000 0.0000000 0.5151504 0.0000000 1.8281251 
[10] 0.5098688 2.8370263 0.4895606 1.5152191 4.1740177 7.1527742 2.8992215 4.5322934 6.7180530 
[19] 0.0000000 1.1914052 3.6152333 0.0000000 0.3778717 0.0000000 1.4940469 

guerras de referencia!

@James ha encontrado un método aún más rápido y lo dejó en un comentario. Le gané la victoria, aunque solo sea porque sé que su victoria será efímera.

En primer lugar, tratar de compilar, pero eso no parece ayudar a cualquier persona:

p <- rnorm(10000) 
gsk3 <- function(x) { x[x<0] <- 0; x } 
jmsigner <- function(x) ifelse(x<0, 0, x) 
joshua <- function(x) pmin(x,0) 
james <- function(x) (abs(x)+x)/2 
library(compiler) 
gsk3.c <- cmpfun(gsk3) 
jmsigner.c <- cmpfun(jmsigner) 
joshua.c <- cmpfun(joshua) 
james.c <- cmpfun(james) 

microbenchmark(joshua(p),joshua.c(p),gsk3(p),gsk3.c(p),jmsigner(p),james(p),jmsigner.c(p),james.c(p)) 
      expr  min  lq median  uq  max 
1  gsk3.c(p) 251.782 255.0515 266.8685 269.5205 457.998 
2  gsk3(p) 256.262 261.6105 270.7340 281.3560 2940.486 
3 james.c(p) 38.418 41.3770 43.3020 45.6160 132.342 
4  james(p) 38.934 42.1965 43.5700 47.2085 4524.303 
5 jmsigner.c(p) 2047.739 2145.9915 2198.6170 2291.8475 4879.418 
6 jmsigner(p) 2047.502 2169.9555 2258.6225 2405.0730 5064.334 
7 joshua.c(p) 237.008 244.3570 251.7375 265.2545 376.684 
8  joshua(p) 237.545 244.8635 255.1690 271.9910 430.566 

compiled comparison

Pero espera! Dirk escribió esta cosa de Rcpp. ¿Puede un completo C++ incompetente leer su documento JSS, adaptar su ejemplo y escribir la función más rápida de todas? Estén atentos, queridos oyentes.

library(inline) 
cpp_if_src <- ' 
    Rcpp::NumericVector xa(a); 
    int n_xa = xa.size(); 
    for(int i=0; i < n_xa; i++) { 
    if(xa[i]<0) xa[i] = 0; 
    } 
    return xa; 
' 
cpp_if <- cxxfunction(signature(a="numeric"), cpp_if_src, plugin="Rcpp") 
microbenchmark(joshua(p),joshua.c(p),gsk3(p),gsk3.c(p),jmsigner(p),james(p),jmsigner.c(p),james.c(p), cpp_if(p)) 
     expr  min  lq median  uq  max 
1 cpp_if(p) 8.233 10.4865 11.6000 12.4090 69.512 
2  gsk3(p) 170.572 172.7975 175.0515 182.4035 2515.870 
3 james(p) 37.074 39.6955 40.5720 42.1965 2396.758 
4 jmsigner(p) 1110.313 1118.9445 1133.4725 1164.2305 65942.680 
5 joshua(p) 237.135 240.1655 243.3990 250.3660 2597.429 

with rcpp comparison

Eso es afirmativa, capitán.

Esto modifica la entrada p incluso si no se le asigna. Si desea evitar ese comportamiento, debe clonar:

cpp_ifclone_src <- ' 
    Rcpp::NumericVector xa(Rcpp::clone(a)); 
    int n_xa = xa.size(); 
    for(int i=0; i < n_xa; i++) { 
    if(xa[i]<0) xa[i] = 0; 
    } 
    return xa; 
' 
cpp_ifclone <- cxxfunction(signature(a="numeric"), cpp_ifclone_src, plugin="Rcpp") 

Lo que lamentablemente elimina la ventaja de la velocidad.

+0

Ari y @DirkEddelbuettel: ¿Realmente modificar 'p 'sin asignar? No parece cuando lo intento. – Aaron

+0

@ Aaron Consulte la explicación de Dirk aquí: http://stackoverflow.com/questions/11300048/rcpp-pass-by-reference-vs-by-value –

4

Alternativamente, también puede utilizar ifelse:

ifelse(pred_precipitation < 0, 0, pred_precipitation) 
11

me gustaría utilizar pmax porque ifelse puede ser un poco lento a veces y subconjunto de reemplazo crea un vector adicional (que puede ser un problema con grandes conjuntos de datos) .

set.seed(21) 
pred_precipitation <- rnorm(25,2,4) 
p <- pmax(pred_precipitation,0) 

subconjunto de reemplazo es por lejos el más rápido sin embargo:

library(rbenchmark) 
gsk3 <- function(x) { x[x<0] <- 0; x } 
jmsigner <- function(x) ifelse(x<0, 0, x) 
joshua <- function(x) pmin(x,0) 
benchmark(joshua(p), gsk3(p), jmsigner(p), replications=10000, order="relative") 
     test replications elapsed relative user.self sys.self 
2  gsk3(p)  10000 0.215 1.000000  0.216 0.000 
1 joshua(p)  10000 0.444 2.065116  0.416 0.016 
3 jmsigner(p)  10000 0.656 3.051163  0.652 0.000 

autoplot microbenchmark

+0

+1 para pruebas comparativas. Se agregó un gráfico de tiempos (usando 'autoplot.microbenchmark' en el paquete' taRifx') –

+0

@ gsk3: wow, ¿qué hiciste para empeorar mi solución? : P –

+0

Kvit su kvetching o cara mi hombre talonz.Sin embargo, con toda seriedad, lo ejecuté de nuevo y parece ser una diferencia consistente entre el resultado 'rbenchmark' y el resultado' microbenchmark', al menos en mi sistema. ~ 2x vs. ~ 3x diferencias de tiempo. –

Cuestiones relacionadas