2012-06-30 34 views
11

Chúng tôi muốn đặt tất cả các giá trị trong một mảng số không âm. Tôi đã thử nhiều thứ nhưng chưa đạt được giải pháp làm việc. Tôi nghĩ về một vòng lặp for với điều kiện, tuy nhiên điều này có vẻ không hoạt động.R: Thay thế các giá trị âm bằng không

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

Cảm ơn bạn đã gợi ý!

Trả lời

38

Cảm ơn ví dụ tái sản xuất. Đây là thứ R khá cơ bản. Bạn có thể gán cho thành phần được chọn của một vector (lưu ý một mảng có kích thước, và những gì bạn đã cho là một vector không phải là một mảng):

> 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 

cuộc chiến tranh Benchmark!

@James đã tìm thấy phương pháp thậm chí nhanh hơn và để lại trong nhận xét. Tôi tán thành anh ta, nếu chỉ vì tôi biết chiến thắng của anh ấy sẽ tồn tại trong thời gian ngắn.

Trước tiên, tôi cố gắng biên soạn, nhưng điều đó dường như không giúp bất cứ ai:

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

Nhưng chờ đợi! Dirk đã viết điều Rcpp này. Có thể một hoàn thành C++ không đủ năng lực đọc giấy JSS của mình, thích ứng với ví dụ của mình, và viết chức năng nhanh nhất của tất cả chúng? Hãy theo dõi, các thính giả thân yêu.

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

Đó là khẳng định, đội trưởng.

Điều này sửa đổi đầu vào p ngay cả khi bạn không gán cho nó. Nếu bạn muốn tránh hành vi đó, bạn phải sao chép:

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") 

Thật không may giết được lợi thế về tốc độ.

+0

Ari và @DirkEddelbuettel: Liệu nó thực sự thay đổi 'p' mà không gán? Dường như tôi không thử. – Aaron

+0

@Aaron Xem giải thích của Dirk tại đây: http://stackoverflow.com/questions/11300048/rcpp-pass-by-reference-vs-by-value –

4

Hoặc bạn cũng có thể sử dụng ifelse:

ifelse(pred_precipitation < 0, 0, pred_precipitation) 
11

Tôi sẽ sử dụng pmaxifelse có thể là một chút chậm vào những thời điểm và tập hợp con-thay thế tạo ra một vector bổ sung (có thể là một vấn đề với các tập dữ liệu lớn) .

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

tập hợp con-thay thế là by-xa nhanh nhất mặc dù:

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 cho điểm chuẩn. Đã thêm một lô thời gian (sử dụng 'autoplot.microbenchmark' trong gói' taRifx') –

+0

@ gsk3: wow, bạn đã làm gì để làm cho giải pháp của tôi tồi tệ hơn nhiều? : P –

+0

Kvit kvetching của bạn hoặc phải đối mặt với người đàn ông của tôi talonz.Tuy nhiên, trong tất cả sự nghiêm túc, tôi chạy nó một lần nữa và nó dường như là sự khác biệt nhất quán giữa kết quả 'rbenchmark' và kết quả' microbenchmark', ít nhất là trên hệ thống của tôi. ~ 2x so với chênh lệch thời gian ~ 3x. –

Các vấn đề liên quan