2012-06-30 2 views
11

Мы хотим установить все значения в нулевом массиве, которые являются отрицательными. Я пробовал много вещей, но еще не достиг рабочего рабочего решения. Я думал о цикле с условием, однако это, похоже, не сработает.R: Замена отрицательных значений на ноль

#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]} 
} 

Спасибо за ваши подсказки!

ответ

38

Спасибо за воспроизводимый пример. Это довольно простой материал. Вы можете назначить выбранные элементы вектора (обратите внимание, массив имеет размеры, и то, что вы дали вектор не массив):

> 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 

Benchmark война!

@James нашел еще более быстрый метод и оставил его в комментарии. Я поддержал его, хотя бы потому, что знаю, что его победа будет недолгой.

Во-первых, я пытаюсь компиляции, но это не похоже, чтобы помочь кому-либо:

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

Но подождите! Дирк написал эту вещь Rcpp. Может ли полный некомпетентный C++ прочитать его статью JSS, адаптировать свой пример и написать самую быструю функцию из всех? Оставайтесь с нами, дорогие слушатели.

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

Это утвердительный, капитан.

Это изменяет вход p, даже если вы его не назначили. Если вы хотите избежать этого поведения, вам необходимо клонировать:

К сожалению, увы, преимущество скорости.

+0

Ари и @DirkEddelbuettel: Действительно ли это изменить 'p' без назначения? Кажется, я не пытаюсь. – Aaron

+0

@Aaron См. Объяснение Дирка здесь: http://stackoverflow.com/questions/11300048/rcpp-pass-by-reference-vs-by-value –

4

В качестве альтернативы вы можете также использовать ifelse:

ifelse(pred_precipitation < 0, 0, pred_precipitation) 
11

Я хотел бы использовать pmax потому ifelse может быть немного медленным время от времени и подмножество-замены создает дополнительный вектор (который может быть проблема с большими наборами данных) ,

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

Subset-замена по-намного быстрее, хотя:

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 для контрольных показателей. Добавлен график таймингов (с использованием 'autoplot.microbenchmark' в пакете' taRifx') –

+0

@ gsk3: вау, что вы сделали, чтобы сделать мое решение намного хуже? : P –

+0

Kvit ваш kvetching или лицо мой человек talonz.Несмотря на всю серьезность, я снова запустил его, и это, по-видимому, является последовательной разницей между результатом «rbenchmark» и результатом «microbenchmark», по крайней мере, в моей системе. ~ 2x против ~ 3x разницы во времени. –

Смежные вопросы