Thứ nhất, ifelse
không KHÔNG luôn đánh giá cả hai biểu thức - chỉ khi có cả TRUE
và FALSE
yếu tố trong vector thử nghiệm.
ifelse(TRUE, 'foo', stop('bar')) # "foo"
Và theo ý kiến của tôi:
ifelse
nên không được sử dụng trong một tình huống không vectorized. Đó là luôn chậm hơn và nhiều hơn nữa lỗi dễ bị sử dụng ifelse
qua if
/else
:
# This is fairly common if/else code
if (length(letters) > 0) letters else LETTERS
# But this "equivalent" code will yield a very different result - TRY IT!
ifelse(length(letters) > 0, letters, LETTERS)
Trong những tình huống vectorized tuy nhiên, ifelse
có thể là một lựa chọn tốt - nhưng hãy cẩn thận rằng độ dài và thuộc tính của kết quả có thể không phải là những gì bạn mong đợi (như trên, và tôi xem xét ifelse
bị phá vỡ trong đó tôn trọng).
Dưới đây là ví dụ: tst
có chiều dài 5 và có một lớp. Tôi mong đợi kết quả là chiều dài 10 và không có lớp, nhưng đó không phải là những gì xảy ra - nó nhận được một lớp không tương thích và chiều dài 5!
# a logical vector of class 'mybool'
tst <- structure(1:5 %%2 > 0, class='mybool')
# produces a numeric vector of class 'mybool'!
ifelse(tst, 101:110, 201:210)
#[1] 101 202 103 204 105
#attr(,"class")
#[1] "mybool"
Tại sao tôi mong đợi độ dài là 10? Bởi vì hầu hết các chức năng trong R "chu kỳ" vector ngắn hơn để phù hợp với còn:
1:5 + 1:10 # returns a vector of length 10.
... Nhưng ifelse
chỉ chu kỳ sự có/không có đối số để phù hợp với chiều dài của đối số tst.
Tại sao tôi mong đợi lớp học (và các thuộc tính khác) để không phải là được sao chép từ đối tượng thử nghiệm? Bởi vì <
trả về một vectơ logic không sao chép lớp và các thuộc tính từ các đối số (thường là số) của nó. Nó không làm điều đó bởi vì nó thường sẽ rất sai.
1:5 < structure(1:10, class='mynum') # returns a logical vector without class
Cuối cùng, bạn có thể tự làm "hiệu quả hơn" không?Vâng, có vẻ như là ifelse
không phải là nguyên thủy như if
và cần một số mã đặc biệt để xử lý NA
. Nếu bạn không có NA
s, bạn có thể tự làm điều đó nhanh hơn.
tst <- 1:1e7 %%2 == 0
a <- rep(1, 1e7)
b <- rep(2, 1e7)
system.time(r1 <- ifelse(tst, a, b)) # 2.58 sec
# If we know that a and b are of the same length as tst, and that
# tst doesn't have NAs, then we can do like this:
system.time({ r2 <- b; r2[tst] <- a[tst]; r2 }) # 0.46 secs
identical(r1, r2) # TRUE
cảm ơn bạn! Tôi không có thời gian để nhìn cái này bây giờ, nhưng tối nay tôi sẽ làm thế. Cảm ơn các ý kiến và ví dụ của bạn. –
lời khuyên và ví dụ tuyệt vời. Cảm ơn! –
Lưu ý rằng 'ifelse' thực hiện tái chế vectơ - nếu một trong hai biến' yes' hoặc 'no' có độ dài không bằng nhau đối với' test', chúng sẽ được tái chế. Điều này có nghĩa là mã thử nghiệm của bạn ở cuối ví dụ của bạn sẽ chỉ mang lại kết quả giống nhau nếu tất cả các vector có độ dài bằng nhau. Hãy thử ví dụ dữ liệu đầu vào này: 'tst <- mẫu (c (TRUE, FALSE), 1e2, thay thế = TRUE); một <- 1: 100; b <- - (1:50); ' – Andrie